我试图理解为什么这段代码会抛出错误。即使
expanding
之后的前 30 行是 np.nan
仍然应该允许数字运算。为什么会失败?我应该如何解决这个问题?
import pandas as pd
import numpy as np
i = pd.date_range('2000-01-01', '2000-06-01', freq='D')
x = pd.DataFrame(data=np.random.randint(0,10, (len(i), 3)), index = i, columns = list('abc'))
# this works
# x.expanding(min_periods=30).corr()
# this doesn't. Why? Is it because of nans? Isn't np.nan a float
x.expanding(min_periods=30).aggregate(lambda t: t.corr().stack().loc[[('a', 'b'), ('a', 'c')], :])
# this fails too
# x.expanding(min_periods=30).aggregate(lambda t: t+1)
DataError:没有要聚合的数字类型
我可以通过这段代码生成愿望输出:
y = x.expanding(min_periods=30).corr()
y.index.names = ['dates', 'letters']
y.columns.name = 'cols'
y=y.stack()
mi = pd.MultiIndex.from_tuples([('a','b'), ('a','c')], names = ['letters', 'cols'])
y.to_frame().join(pd.DataFrame(index=mi), on=['letters', 'cols'], how='inner')
将 expanding() 方法与 aggregate() 函数一起使用时代码失败的原因是前 29 行中存在 NaN 值,正如您所怀疑的那样。
当将 aggregate() 与 expanding() 方法一起使用时,Pandas 首先尝试创建一个包含窗口中所有值的 DataFrame。由于前 29 行有 NaN 值,聚合函数:
(lambda t: t.corr().stack().loc[[('a', 'b'), ('a', 'c')], :]
在这种情况下应用于包含 NaN 值的 DataFrame。这会导致错误。
NaN 值的存在会在执行数学运算或聚合函数时导致意外结果,这就是为什么最好在代码中显式处理它们。
要解决此问题,您可以在执行聚合之前使用 dropna() 方法删除包含 NaN 值的行:
x.expanding(min_periods=30).apply(lambda t:t.dropna().corr().stack().loc[[('a', 'b'), ('a', 'c')], :])
在这里,我们使用“apply()”方法而不是“aggregate()”,并首先通过在传递给 lambda 函数的 DataFrame“t”上调用“dropna()”来删除包含 NaN 值的行。然后我们计算相关矩阵并像以前一样堆叠结果。
你可以试试这个:
out = (x.rename_axis("dates").expanding(min_periods=30).corr().xs("a", level=1)
[["b", "c"]].dropna().melt(var_name="cols", ignore_index=False)
.set_index("cols", append=True)
)
输出:
print(out)
value
dates cols
2000-01-30 b -0.210288
2000-01-31 b -0.223870
2000-02-01 b -0.224411
2000-02-02 b -0.156831
2000-02-03 b -0.164199
... ...
2000-05-28 c 0.022239
2000-05-29 c 0.027344
2000-05-30 c 0.014873
2000-05-31 c 0.014310
2000-06-01 c 0.024398
[248 rows x 1 columns]