如何计算从右侧开始连续具有零值的列数,直到出现第一个非零元素?

5
假设我有以下数据框:
   C1 C2 C3 C4  
0  1  2  3  0  
1  4  0  0  0  
2  0  0  0  3  
3  0  3  0  0 

我希望添加另一列,以便显示从右边连续出现的零值列数。 新列将是:

  Cnew  
0 1  
1 3  
2 0  
3 2  
3个回答

5
你可以使用以下方法:
  • 使用 iloc[::-1] 实现倒序排序
  • 使用 cumsum 方法计算每一行的累计和 (axis=1)
  • 使用 eq 方法检查条件并计算 True 的数量,再用 sum 方法得出结果
df['new'] = df.iloc[:,::-1].cumsum(axis=1).eq(0).sum(axis=1)
print (df)
   C1  C2  C3  C4  new
0   1   2   3   0    1
1   4   0   0   0    3
2   0   0   0   3    0
3   0   3   0   0    2

print (df.iloc[:,::-1])
   C4  C3  C2  C1
0   0   3   2   1
1   0   0   0   4
2   3   0   0   0
3   0   0   3   0


print (df.iloc[:,::-1].cumsum(axis=1))
   C4  C3  C2  C1
0   0   3   5   6
1   0   0   0   4
2   3   3   3   3
3   0   0   3   3

print (df.iloc[:,::-1].cumsum(axis=1).eq(0))
      C4     C3     C2     C1
0   True  False  False  False
1   True   True   True  False
2  False  False  False  False
3   True   True  False  False

累加求和函数(cumsum)是做什么的? - Alex_ban
这是累积和,- http://mathworld.wolfram.com/CumulativeSum.html - jezrael
3,2,1,并且它计算为 0+3, 0+3+2, 0+3+2+1 - jezrael
在最后一行中,0,0+0, 0+0+3, 0+0+3+0 - jezrael

4

我会在布尔数组上使用 argmax。此外,如果我直接使用 numpy 可以使其更快。

(df.values[:, ::-1] != 0).argmax(1)

array([1, 3, 0, 2])

或者非常类似地

(df.values[:, ::-1].astype(bool)).argmax(1)

array([1, 3, 0, 2])

我可以使用assign将其放置在新的列中。

df.assign(new=(df.values[:, ::-1] != 0).argmax(1))

   C1  C2  C3  C4  new
0   1   2   3   0    1
1   4   0   0   0    3
2   0   0   0   3    0
3   0   3   0   0    2

在原地添加一个新列:

或者在原地添加一个新的列

df['new'] = (df.values[:, ::-1] != 0).argmax(1)
df

   C1  C2  C3  C4  new
0   1   2   3   0    1
1   4   0   0   0    3
2   0   0   0   3    0
3   0   3   0   0    2

时序
我们通过减少必要的工作来缩短时间。我们只需要找到第一个非零位的位置。

# My first variant
%timeit df.assign(new=(df.values[:, ::-1] != 0).argmax(1))
# My second variant
%timeit df.assign(new=(df.values[:, ::-1].astype(bool)).argmax(1))
# jezrael's solution
%timeit df.assign(new=df.iloc[:,::-1].cumsum(1).eq(0).sum(1))
# numpy version of jezrael's solution
%timeit df.assign(new=(df.values[:,::-1].cumsum(1) == 0).sum(1))
# Scott Boston's solution
%timeit df.assign(new=df.iloc[:,::-1].eq(0).cumprod(axis=1).sum(axis=1))
# numpy version of Scott Boston's solution
%timeit df.assign(new=(df.values[:,::-1] == 0).cumprod(1).sum(1))

small data

1000 loops, best of 3: 301 µs per loop
1000 loops, best of 3: 273 µs per loop
1000 loops, best of 3: 770 µs per loop
1000 loops, best of 3: 323 µs per loop
1000 loops, best of 3: 647 µs per loop
1000 loops, best of 3: 324 µs per loop

更大的数据

df = pd.DataFrame(np.random.choice([0, 1], (10000, 100), p=(.7, .3)))

100 loops, best of 3: 6.03 ms per loop
100 loops, best of 3: 5.3 ms per loop
100 loops, best of 3: 16.9 ms per loop
100 loops, best of 3: 9 ms per loop
100 loops, best of 3: 10.7 ms per loop
100 loops, best of 3: 10.1 ms per loop

3

使用 eq, cumprodsum (这与此处回答的一个问题非常相似:链接。)

df.iloc[:,::-1].eq(0).cumprod(axis=1).sum(axis=1)

输出:

0    1
1    3
2    0
3    2
dtype: int64

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接