计算pandas中当前行之前的空白数

时间:2017-04-16 22:37:19

标签: python pandas

我有一个带有行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选项,但我无法完全掌握其工作原理。

有关如何有效解决这个问题的想法吗?

2 个答案:

答案 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

enter image description here

分解

# 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为零的时候。

bcis_blank的累计和,并将相应的值减去"重置"

对于不太直观的代码的价格......你的运行时间更快

天真时间测试

enter image description here