【问题标题】:Count group by where in intervall按间隔计数组
【发布时间】:2023-01-12 04:58:55
【问题描述】:

我对如何在 Python Pandas 中获得简单的解决方案有点迷茫

我有一个包含 3 列的数据框:

A  B  val
P1 P2 12
P1 P2 14
P2 P2 18
P2 P1 17
P1 P3 15
P1 P3 16
P1 P3 13

我想按 A 和 B 分组,以特定间隔计算值,在另一个数据框中手动定义:

MIN MAX
12  12
13  15
16  17

结果应该是 interval 和 rest 上的计数,如下所示:

A  B  V_12_12 V_13_15 V_16_17 V_OTHERS
P1 P2 1       1       0       0        
P2 P2 0       0       0       1
P2 P1 0       0       1       0       
P1 P3 0       2       1       0

我想动态地得到结果,如果我改变间隔,删除或添加其他它应该改变最终数据框中的列名或数字。

感谢帮助。

【问题讨论】:

  • 按 A、B 索引。迭代迭代并过滤。用计数累积字典。将字典变成数据框

标签: python pandas


【解决方案1】:

使用pd.cut尝试这样的事情:

df = pd.read_clipboard()
df2 = pd.read_clipboard()

df['labels']=pd.cut(df['val'], 
                    bins=[0]+df2['MAX'].tolist()+[np.inf], 
                    labels = [f'V_{s}_{e}' for s, e in zip(df2['MIN'], df2['MAX'])]+['V_OTHERS'])

df.groupby(['A','B','labels'])['labels'].count().unstack().reset_index()

输出:

labels   A   B  V_12_12  V_13_15  V_16_17  V_OTHERS
0       P1  P1        0        0        0         0
1       P1  P2        1        1        0         0
2       P1  P3        0        2        1         0
3       P2  P1        0        0        1         0
4       P2  P2        0        0        0         1
5       P2  P3        0        0        0         0

【讨论】:

    【解决方案2】:

    在下面调用第二个数据框limits

    diffs = np.subtract.outer(df["val"].to_numpy(),
                              limits.to_numpy()).reshape(len(df), -1)
    from_min, from_max = diffs[:, ::2], diffs[:, 1::2]
    
    counts = (pd.DataFrame((from_min >= 0) & (from_max <= 0))
                .groupby([df["A"], df["B"]], sort=False).sum())
    
    counts.columns = limits.astype(str).agg("_".join, axis=1).radd("V_")
    
    counts["V_OTHERS"] = df.groupby(["A", "B"]).count().sub(counts.sum(axis=1), axis=0)
    
    counts = counts.reset_index()
    
    • 获取“val”列值与每个最小和最大限制的“交叉”差异

      • 外部减法将给出形状“(len(df), *limits.shape)”
      • 使其在最后 2 个维度变平,使其成为 2D 以添加更多列
    • 区分 from_min 和 from_max 的差异

      • 检查值是否落在范围之间:大于最小值,小于最大值
    • 按“A”和“B”对这些进行分组,然后将这些 True/False 相加以进行计数

    • 从限制的内容中提取新列的名称

      • 使用“_”连接的行式聚合,并从右侧添加“V_”
    • 最后计算余数

      • 查看 A 和 B 对,并从中减去预先计算的计数
    • 并重置索引以将石斑鱼移动到列

    要得到

    >>> counts
        A   B  V_12_12  V_13_15  V_16_17  V_OTHERS
    0  P1  P2        1        1        0         0
    1  P2  P2        0        0        0         1
    2  P2  P1        0        0        1         0
    3  P1  P3        0        2        1         0
    

    【讨论】:

      【解决方案3】:

      尝试这个:

      def find_group(val):
        if 12 <= val <= 12:
          return "V_12_12"
        elif 13 <= val <= 15:
          return "V_13_15"
        elif 16 <= val <= 17:
          return "V_16_17"
        else:
          return "V_OTHERS"
      
      df = pd.DataFrame({
          'A':['P1','P1','P2','P2','P1','P1','P1'],
          'B':['P2','P2','P2','P1','P3','P3','P3'],
          'val':[12,14,18,17,15,16,13]
      })
      df["group"]=df["val"].apply(find_group)
      
      result=df.groupby(["A","B","group"]).count().unstack(fill_value=0).stack()
      
      result.unstack()
      

      【讨论】:

      • 也许在find_group 中做一些事情,让它根据区间的值动态变化
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-16
      • 2016-04-15
      • 2022-01-16
      • 2017-09-01
      • 1970-01-01
      • 2010-09-16
      相关资源
      最近更新 更多