对dtype对象的累积操作

问题描述 投票:3回答:3

我试图找出如何将累积函数应用于对象。对于数字,有几种选择,如cumsumcumcount。还有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。我正在寻找支持将函数应用于这两个输入的通用解决方案:前一个结果和当前元素。

python pandas dataframe
3个回答
2
投票

我认为你可以使用cumsum除了set,然后你需要先转换为list然后转换为set。顺便说一下,不建议在set的列中存储C2lists)或listsC4DataFrame)。

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]

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)复杂度。对于像cumsumewma等特殊情况,操作的递归性质可以降低线性时间的复杂性,但在最一般的情况下,它应该计算前n个元素的函数,然后是前n + 1个元素,所以上。因此,特别是对于仅依赖于当前值和函数的先前值的函数,扩展是非常低效的。更不用说在DataFrame中存储列表或集合从来不是一个好主意。

所以答案是:如果您的数据不是数字且函数依赖于先前的结果和当前元素,则只需使用for循环。无论如何它会更有效率。


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
© www.soinside.com 2019 - 2024. All rights reserved.