【问题标题】:pandas dataframe: how to count the number of 1 rows in a binary column?pandas dataframe:如何计算二进制列中的 1 行数?
【发布时间】:2017-09-22 19:01:35
【问题描述】:

我有以下熊猫数据框:

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]...某事

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

如何做到这一点?

【问题讨论】:

    标签: python pandas dataframe group-by pandas-groupby


    【解决方案1】:

    这是 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
    

    【讨论】:

    • 这非常好用!我也感谢 cmets 解释正在发生的事情
    【解决方案2】:
    • 由于first_column是二进制的,我可以使用astype(bool)得到True/False
    • 如果我采取相反的方式和cumsum,我可以很方便地将Trues 或1s 放在一起
    • 然后我将groupbycounttransform
    • transform 在原始索引中广播 count 聚合
    • 我首先使用where 将所有0s 组合在一起。
    • 我再次使用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
    

    【讨论】:

    • 我收到了一个奇怪的错误:ValueError: Wrong number of items passed 62, placement implies 1
    • @ShanZhengYang 您提供的示例数据是否出现此错误?还是其他数据?如果是其他数据,请编辑您的问题并包含重现问题的数据样本。
    • 我怀疑这可能是问题所在。原始数据框必须有 62 列 perhpas?我会找一个例子来发帖
    【解决方案3】:

    这是 pandas 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-10
      • 1970-01-01
      • 2014-12-03
      • 2021-08-05
      • 1970-01-01
      • 2021-04-16
      • 2022-11-02
      相关资源
      最近更新 更多