pandas在列上使用cumsum但重置计数

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

This帖子和this帖子让我接近,但我无法解决我的问题。

我有一个看起来像的df:

     2017-04-03    2017-04-04    2017-04-05    2017-04-06
id                                                                         
0           0.0        active           0.0           0.0   
1           0.0        active           0.0        active   
2           0.0           0.0           0.0           0.0 

我想计算每行的零并将它们放入一个字符串来编码数据,但是只要没有连续的零,计数就需要重置。

对于上面的df,输出df看起来像:

     2017-04-03    2017-04-04    2017-04-05    2017-04-06
id                                                                         
0    inactive_1        active    inactive_1    inactive_2   
1    inactive_1        active    inactive_1        active   
2    inactive_1    inactive_2    inactive_3    inactive_4

这个函数让我非常接近,但不考虑重置cumsum,它只是对行中所有零实例求和。

def inactive(s):
     np.where(s == 0, 'inactive_' + (s.eq(0).cumsum()).astype(str), s)

df.apply(inactive, 1)
python pandas cumsum
2个回答
2
投票

一个小环形交叉口,但这可以通过在每一行上应用groupby操作,然后使用np.where有选择地将您的值应用于原始行来完成。

def f(x):
    return x.groupby(x.ne(x.shift()).cumsum()).cumcount() + 1

i = df.apply(pd.to_numeric, errors='coerce')
j = 'inactive_' + i.apply(f, axis=1).astype(str)

df[:] = np.where(i.ne(0), df.values, j)

df

    2017-04-03  2017-04-04  2017-04-05  2017-04-06
id                                                
0   inactive_1      active  inactive_1  inactive_2
1   inactive_1      active  inactive_1      active
2   inactive_1  inactive_2  inactive_3  inactive_4

1
投票

您可以使用:

#convert to numeric, NaNs for non numeric
df1 = df.apply(pd.to_numeric, errors='coerce')
#count consecutive values with reset
a = df1 == 0
b = a.cumsum(axis=1)
c = b-b.where(~a, axis=1).ffill(axis=1).fillna(0).astype(int)

print (c)
    2017-04-03  2017-04-04  2017-04-05  2017-04-06
id                                                
0            1           0           1           2
1            1           0           1           0
2            1           2           3           4


#replace by mask 
df = df.mask(c != 0, 'inactive_' + c.astype(str))
print (df)
    2017-04-03  2017-04-04  2017-04-05  2017-04-06
id                                                
0   inactive_1      active  inactive_1  inactive_2
1   inactive_1      active  inactive_1      active
2   inactive_1  inactive_2  inactive_3  inactive_4

时序:

np.random.seed(425)
df = pd.DataFrame(np.random.choice([0, 'active'], size=(100000, 300)))

In [4]: %timeit (jez(df))
1 loop, best of 3: 1min 40s per loop

In [5]: %timeit col(df)
1 loop, best of 3: 5min 54s per loop

def jez(df):
    df1 = df.apply(pd.to_numeric, errors='coerce')
    #count consecutive values
    a = df1 == 0
    b = a.cumsum(axis=1)
    c = b-b.where(~a, axis=1).ffill(axis=1).fillna(0).astype(int)
    #replace by mask 
    return df.mask(c != 0, 'inactive_' + c.astype(str))

def f(x):
    return x.groupby(x.ne(x.shift()).cumsum()).cumcount() + 1

def col(df):

    i = df.apply(pd.to_numeric, errors='coerce')
    j = 'inactive_' + i.apply(f, axis=1).astype(str)

    df[:] = np.where(i.ne(0), df.values, j)

    return(df)

警告:

性能实际上取决于数据。

© www.soinside.com 2019 - 2024. All rights reserved.