我有一个如下所示的数据框:
名称 | 日期 | col1 | col2 |
---|---|---|---|
A | 2021-03-01 | 0 | 1 |
A | 2021-03-02 | 0 | 0 |
A | 2021-03-03 | 3 | 1 |
A | 2021-03-04 | 1 | 0 |
A | 2021-03-05 | 3 | 1 |
A | 2021-03-06 | 1 | 0 |
B | 2021-03-01 | 1 | 0 |
B | 2021-03-02 | 2 | 0 |
B | 2021-03-03 | 3 | 1 |
B | 2021-03-04 | 0 | 1 |
B | 2021-03-05 | 0 | 0 |
B | 2021-03-06 | 0 | 0 |
我想按名称分组并找到其他非日期列的非零条目(基本上不包括任何前导零或尾随零)所跨越的天数,以获得类似的结果:
名称 | col1 | col2 |
---|---|---|
A | 4 | 5 |
B | 3 | 2 |
如何在不使用 for 循环的情况下执行此操作?
答案 0 :(得分:4)
我认为,np.trim_zeros
正是您要找的:
>>> import numpy as np; import pandas as pd
>>> df = pd.DataFrame.from_dict({'name': ['A']*6 + ['B']*6, 'col1': [0, 0, 3, 1, 3, 1, 1, 2, 3, 0, 0, 0], 'col2': [1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0]})
>>> df
name col1 col2
0 A 0 1
1 A 0 0
2 A 3 1
3 A 1 0
4 A 3 1
5 A 1 0
6 B 1 0
7 B 2 0
8 B 3 1
9 B 0 1
10 B 0 0
11 B 0 0
>>> df.groupby('name').aggregate(lambda x: len(np.trim_zeros(x))).reset_index()
name col1 col2
0 A 4 5
1 B 3 2
答案 1 :(得分:1)
另一种解决方案:
def fn(x):
i = x[(x != 0)].index
return i[-1] - i[0] + 1 if len(i) > 0 else 0
print(df.groupby("name").agg({"col1": fn, "col2": fn}))
打印:
col1 col2
name
A 4 5
B 3 2
答案 2 :(得分:0)
这里有一种方法可以更好地为许多组扩展[它避免了 apply(lambda x:)
以支持多个 groubpy 内置操作。]
检查值 !=0 然后在组内在两个方向上取一个 cummax
用 True 标记跨度。然后 groupby
+ sum
得到大小。
cols = ['col1', 'col2']
df1 = df[cols].ne(0)
df1 = df1.groupby(df['name']).cummax() & df1[::-1].groupby(df['name']).cummax()
df1 = df1.groupby(df['name']).sum()
print(df1)
col1 col2
name
A 4 5
B 3 2