我试图找出如何将累积函数应用于对象。对于数字,有几种选择,例如cumsum
和cumcount
。还有df.expanding可以与apply
一起使用。但是我传递给apply
的函数不适用于对象。
import pandas as pd
df = pd.DataFrame({"C1": [1, 2, 3, 4],
"C2": [{"A"}, {"B"}, {"C"}, {"D"}],
"C3": ["A", "B", "C", "D"],
"C4": [["A"], ["B"], ["C"], ["D"]]})
df
Out:
C1 C2 C3 C4
0 1 {A} A [A]
1 2 {B} B [B]
2 3 {C} C [C]
3 4 {D} D [D]
在数据框中,我有整数值,集,字符串和列表。现在,如果我尝试expanding().apply(sum)
我有累积总和:
df.expanding().apply(sum)
Out[69]:
C1 C2 C3 C4
0 1.0 {A} A [A]
1 3.0 {B} B [B]
2 6.0 {C} C [C]
3 10.0 {D} D [D]
我的期望是,因为总和是在列表和字符串上定义的,所以我会得到这样的结果:
C1 C2 C3 C4
0 1.0 {A} A [A]
1 3.0 {B} AB [A, B]
2 6.0 {C} ABC [A, B, C]
3 10.0 {D} ABCD [A, B, C, D]
我也试过这样的事情:
df.expanding().apply(lambda r: reduce(lambda x, y: x+y**2, r))
Out:
C1 C2 C3 C4
0 1.0 {A} A [A]
1 5.0 {B} B [B]
2 14.0 {C} C [C]
3 30.0 {D} D [D]
它按预期工作:上一个结果为x
,当前行值为y
。但是,例如,我无法使用x.union(y)
进行缩减。
所以,我的问题是:我可以在对象上使用expanding
的替代方法吗?该示例只是为了表明expanding().apply()
不能处理对象dtypes。我正在寻找支持将函数应用于这两个输入的通用解决方案:前一个结果和当前元素。
答案 0 :(得分:2)
我认为您可以使用cumsum
异常set
,然后您需要先转换为list
然后转换为set
。顺便说一下,不建议在set
的列中存储C2
(lists
)或lists
C4
(DataFrame
)。
print df
C1 C2 C3 C4
0 1 {A} A [A]
1 2 {B} B [B]
2 3 {C} C [C]
3 4 {D} D [D]
print df[['C1','C3','C4']].cumsum()
C1 C3 C4
0 1 A [A]
1 3 AB [A, B]
2 6 ABC [A, B, C]
3 10 ABCD [A, B, C, D]
df['C2'] = df['C2'].apply(list)
df = df.cumsum()
df['C2'] = df['C2'].apply(set)
print df
C1 C2 C3 C4
0 1 {A} A [A]
1 3 {A, B} AB [A, B]
2 6 {A, C, B} ABC [A, B, C]
3 10 {A, C, B, D} ABCD [A, B, C, D]
答案 1 :(得分:2)
原来这不可能。
继续使用相同的样本:
def burndowntheworld(ser):
print('Are you sure?')
return ser/0
df.select_dtypes(['object']).expanding().apply(burndowntheworld)
Out:
C2 C3 C4
0 {A} A [A]
1 {B} B [B]
2 {C} C [C]
3 {D} D [D]
如果列的类型是object,则永远不会调用该函数。并且pandas没有可用于对象的替代方案。 rolling().apply()
也是如此。
在某种意义上,这是一件好事,因为具有自定义函数的expanding.apply
具有O(n ** 2)复杂度。对于cumsum
,ewma
等特殊情况,操作的递归性质可以降低线性时间的复杂性,但在最一般的情况下,它应该计算前n个元素的函数,然后为第一个n + 1个元素,依此类推。因此,特别是对于仅依赖于当前值和函数的先前值的函数,扩展是非常低效的。更不用说在DataFrame中存储列表或集合从来不是一个好主意。
所以答案是:如果你的数据不是数字而且函数依赖于前面的结果和当前元素,那么只需使用for循环。无论如何它会更有效率。
答案 2 :(得分:1)
好吧,你可以定义一个自定义函数
def custom_cumsum(df):
from functools import reduce
nrows, ncols = df.shape
index, columns = df.index, df.columns
rets = {}
new_col = None
for col in df.columns:
try:
new_col = {col:df.loc[:, col].cumsum()}
except TypeError as e:
if 'set' in str(e):
new_col = {col:[ reduce(set.union, df.loc[:, col][:(i+1)]) for i in range(nrows)]}
rets.update(new_col)
frame = pd.DataFrame(rets, index=index, columns=columns)
return frame