2017-04-25 143 views
5

我有以下的熊猫数据框:pandas dataframe:如何计算二进制列中的1行数量?

import pandas as pd 
import numpy as np 

df = pd.DataFrame({"first_column": [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0]}) 

>>> df 
    first_column 
0    0 
1    0 
2    0 
3    1 
4    1 
5    1 
6    0 
7    0 
8    1 
9    1 
10    0 
11    0 
12    0 
13    0 
14    1 
15    1 
16    1 
17    1 
18    1 
19    0 
20    0 

first_column是0和1的二进制列。有连续的“集群”,它们总是以至少两对的形式出现。

我的目标是创建一个列,其“罪状”每组的人的行数:

>>> df 
    first_column counts 
0    0  0 
1    0  0 
2    0  0 
3    1  3 
4    1  3 
5    1  3 
6    0  0 
7    0  0 
8    1  2 
9    1  2 
10    0  0 
11    0  0 
12    0  0 
13    0  0 
14    1  5 
15    1  5 
16    1  5 
17    1  5 
18    1  5 
19    0  0 
20    0  0 

这听起来像一个工作为df.loc(),例如df.loc[df.first_column == 1] ...东西

我只是不确定如何考虑每个人的“集群”,以及如何用“行数”来标记每个独特的集群。

如何做到这一点?

回答

3

下面是用与NumPy的cumsumbincount一种方法 -

def cumsum_bincount(a): 
    # Append 0 & look for a [0,1] pattern. Form a binned array based off 1s groups 
    ids = a*(np.diff(np.r_[0,a])==1).cumsum() 

    # Get the bincount, index into the count with ids and finally mask out 0s 
    return a*np.bincount(ids)[ids] 

采样运行 -

In [88]: df['counts'] = cumsum_bincount(df.first_column.values) 

In [89]: df 
Out[89]: 
    first_column counts 
0    0  0 
1    0  0 
2    0  0 
3    1  3 
4    1  3 
5    1  3 
6    0  0 
7    0  0 
8    1  2 
9    1  2 
10    0  0 
11    0  0 
12    0  0 
13    0  0 
14    1  5 
15    1  5 
16    1  5 
17    1  5 
18    1  5 
19    0  0 
20    0  0 

套装第一6 elems的是1s然后测试了 -

In [101]: df.first_column.values[:5] = 1 

In [102]: df['counts'] = cumsum_bincount(df.first_column.values) 

In [103]: df 
Out[103]: 
    first_column counts 
0    1  6 
1    1  6 
2    1  6 
3    1  6 
4    1  6 
5    1  6 
6    0  0 
7    0  0 
8    1  2 
9    1  2 
10    0  0 
11    0  0 
12    0  0 
13    0  0 
14    1  5 
15    1  5 
16    1  5 
17    1  5 
18    1  5 
19    0  0 
20    0  0 
+0

这工作非常好!我很欣赏解释发生了什么的评论 – ShanZhengYang

4
  • 由于first_column是二进制的,我可以用astype(bool)获得True/False
  • 如果我把这些和cumsum相反,我得到了True小号混为一谈的一种方便的方法或1小号
  • 我然后groupbycounttransform
  • transform在原始索引中广播count汇总
  • 我首先使用where将所有0组合在一起。
  • 我用where再次到他们的计数设为0
  • 我用assign生成的df一份和新列。这是因为我不想破坏我们已有的df。如果你想直接写df使用df['counts'] = c

t = df.first_column.astype(bool) 
c = df.groupby((~t).cumsum().where(t, -1)).transform('count').where(t, 0) 
df.assign(counts=c) 

    first_column counts 
0    0  0 
1    0  0 
2    0  0 
3    1  3 
4    1  3 
5    1  3 
6    0  0 
7    0  0 
8    1  2 
9    1  2 
10    0  0 
11    0  0 
12    0  0 
13    0  0 
14    1  5 
15    1  5 
16    1  5 
17    1  5 
18    1  5 
19    0  0 
20    0  0 
+0

这是一个很好的解释。谢谢! – ShanZhengYang

+0

我收到上面的一个奇怪的错误:'ValueError:错误的项目数量通过62,安置意味着1' – ShanZhengYang

+0

@ShanZhengYang你得到这个错误与你提供的示例数据?或其他数据?如果有其他数据,请编辑您的问题并包含重现问题的数据样本。 – piRSquared

0

这里是大熊猫GROUPBY,我认为这是相当可读的另一种方法。 (可能的)优点是不依赖于列中仅存在1和0的假设。

主要的见解是创建连续值的组,然后简单地计算它们的长度。我们还携带组中值的信息,所以我们可以过滤零。

# Relevant column -> grouper needs to be 1-Dimensional 
col_vals = df['first_column'] 

# Group by sequence of consecutive values and value in the sequence. 
grouped = df.groupby(((col_vals!=col_vals.shift(1)).cumsum(), col_vals)) 

# Get the length of consecutive values if they are different from zero, else zero 
df['counts'] = grouped['first_column'].transform(lambda group: len(group))\ 
             .where(col_vals!=0, 0) 

这是团体和钥匙什么样子:

for key, group in grouped: 
    print key, group 

(1, 0) first_column 
0    0 
1    0 
2    0 
(2, 1) first_column 
3    1 
4    1 
5    1 
(3, 0) first_column 
6    0 
7    0 
(4, 1) first_column 
8    1 
9    1 
(5, 0)  first_column 
10    0 
11    0 
12    0 
13    0 
(6, 1)  first_column 
14    1 
15    1 
16    1 
17    1 
18    1 
(7, 0)  first_column 
19    0 
20    0 
相关问题