我有一个带有行is_blank
的DataFrame,用于指示行是否为NaN
。我想生成一个新功能,用于计算按NaN
分组的每组记录中当前行之前id
行的数量。
以下示例:
import pandas as pd
is_blank = [0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1]
id = [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2]
outval = [0, 0, 1, 2, 0, 1, 2, 0, 0, 0, 0]
test_df = pd.DataFrame({'id': id, 'is_blank': is_blank, 'outval': outval})
以下是玩具数据集的外观。我想生成outval
列。 outval[3]
是2,因为它之前有两个空格。然后outval[4]
重置为零,因为该行之前没有空行。
In[2]: test_df
Out[2]:
id is_blank outval
0 1 0 0
1 1 1 0
2 1 1 1
3 1 0 2
4 1 1 0
5 1 1 1
6 1 1 2
7 2 0 0
8 2 0 0
9 2 0 0
10 2 1 0
目前我正在尝试某种形式的累积计数:
In[3]: test_df.groupby(['id'])['is_blank'].cumsum().shift(1)
Out[3]:
0 NaN
1 0.0
2 1.0
3 2.0
4 2.0
5 3.0
6 4.0
7 5.0
8 0.0
9 0.0
10 0.0
但显然计数器不会在组内重置并最终计算所有空白行。我正在查看expanding_apply
选项,但我无法完全掌握其工作原理。
有关如何有效解决这个问题的想法吗?
答案 0 :(得分:3)
您可以根据is_blank
创建另一个群组变量,以重置 cumsum :
test_df['outval'] = (test_df.groupby([test_df.id, (test_df.is_blank.diff() != 0).cumsum()])
.is_blank.cumsum().groupby(test_df.id).shift().fillna(0))
test_df
分解:
# create a group variable whose id increases when the blanks are not consecutive
g = (test_df.is_blank.diff() != 0).cumsum()
g
#0 1
#1 2
#2 2
#3 3
#4 4
#5 4
#6 4
#7 5
#8 5
#9 5
#10 6
#Name: is_blank, dtype: int64
# group data frame on both id and g, then do cumsum on the is_blank column
test_df.groupby([test_df.id, g]).is_blank.cumsum().groupby(test_df.id).shift().fillna(0)
#0 0.0
#1 0.0
#2 1.0
#3 2.0
#4 0.0
#5 1.0
#6 2.0
#7 0.0
#8 0.0
#9 0.0
#10 0.0
#Name: is_blank, dtype: float64
答案 1 :(得分:3)
矢量化方法
b = np.append(0, test_df.is_blank.values[:-1])
i = test_df.id.values
bc = b.cumsum()
w1 = np.where(b == 0)[0]
w2 = np.append(0, np.where(i[:-1] != i[1:])[0] + 1)
bd2 = bc[w2].repeat(np.diff(np.append(r[w2], k)))
bd1 = bc[w1].repeat(np.diff(np.append(r[w1], k)))
test_df.assign(outval=bc - np.fmax(bd1, bd2))
id is_blank outval
0 1 0 0
1 1 1 0
2 1 1 1
3 1 0 2
4 1 1 0
5 1 1 1
6 1 1 2
7 2 0 0
8 2 0 0
9 2 0 0
10 2 1 0
这一点是找到"重置"的位置。会发生的。那是id
发生变化,is_blank
为零的时候。
让bc
为is_blank
的累计和,并将相应的值减去"重置"
对于不太直观的代码的价格......你的运行时间更快
天真时间测试