【问题标题】:Altering groupby and value_counts output for mapping to dataframe更改 groupby 和 value_counts 输出以映射到数据帧
【发布时间】:2020-07-17 22:29:52
【问题描述】:

我有一个场景,我试图按特定值过滤数据帧,并计算另一个标识符出现的次数。然后我将其转换为字典并映射回数据框。我遇到的问题是生成的字典无法映射回数据框,因为我给字典引入了复杂性(额外的键?),我不知道如何避免它。

我想这个简单的问题是:'如何在我的 CELL_ID 列上使用 value_counts',按另一个名为 Grid_Type 的列进行过滤,并将结果映射回每个 CELL_ID 的所有单元格?

我目前在做什么

这可以计算有多少单元格包含 CELL_ID,但不允许我按 Grid_Type 过滤

df['CELL_ID'].value_counts()
z1 = z.to_dict()
df['CELL_CNT'] = df['CELL_ID'].map(z1)

这个简单示例的字典输出如下所示:

7015988: 1, 7122961: 1, 6976792: 1

我的错误代码
这是我迄今为止一直在做的事情——我希望能够返回由 Grid_Type 过滤的计数。例如,我希望能够计算在每个 CELL_ID 中/按每个 CELL_ID 看到“Spot”的次数。

z = df[df.Grid_Type == 'Spot'].groupby('CELL_ID')['Grid_Type'].value_counts()
z1 = z.to_dict()
df['SPOT_CNT'] = df['CELL_ID'].map(z1)

似乎在我试图过滤的示例中,字典返回了一个更复杂的结果,其中包括 Grid_Type。问题是,我只想将计数映射到 Cell_ID。例如字典响应:

(7133691, 'Spot'): 3, (7133692, 'Spot'): 3, (7133693, 'Spot'): 2

示例数据

+---------+-----------+
| CELL_ID | Grid_Type |
+---------+-----------+
|     001 | Spot      |
|     001 | Square    |
|     001 | Spot      |
|     001 | Square    |
|     001 | Square    |
|     002 | Spot      |
|     002 | Square    |
|     002 | Square    |
|     003 | Square    |
|     003 | Spot      |
|     003 | Spot      |
|     003 | Spot      |
+---------+-----------+

期望的结果


+---------+-----------+----------+
| CELL_ID | Grid_Type | SPOT_CNT |
+---------+-----------+----------+
|     001 | Spot      |        2 |
|     001 | Square    |        2 |
|     001 | Spot      |        2 |
|     001 | Square    |        2 |
|     001 | Square    |        2 |
|     002 | Spot      |        1 |
|     002 | Square    |        1 |
|     002 | Square    |        1 |
|     003 | Square    |        3 |
|     003 | Spot      |        3 |
|     003 | Spot      |        3 |
|     003 | Spot      |        3 |
+---------+-----------+----------+

感谢您提供的任何帮助/

【问题讨论】:

    标签: python pandas dataframe pandas-groupby


    【解决方案1】:

    您似乎有答案,但我会用transform() 解决这个问题:

    # set it up
    df = pd.read_clipboard()
    print(df)
    
        CELL_ID Grid_Type
    0         1      Spot
    1         1    Square
    2         1      Spot
    3         1    Square
    4         1    Square
    5         2      Spot
    6         2    Square
    7         2    Square
    8         3    Square
    9         3      Spot
    10        3      Spot
    11        3      Spot
    
    df['SPOT_CNT'] = df.groupby('CELL_ID')['Grid_Type'].transform(lambda x: sum(x == 'Spot'))
    print(df)
    
        CELL_ID Grid_Type  SPOT_CNT
    0         1      Spot         2
    1         1    Square         2
    2         1      Spot         2
    3         1    Square         2
    4         1    Square         2
    5         2      Spot         1
    6         2    Square         1
    7         2    Square         1
    8         3    Square         3
    9         3      Spot         3
    10        3      Spot         3
    11        3      Spot         3
    

    lambda 函数内部:
    - 如果 value(x) == 'Spot'
    则返回 bool - 对于每个组,sum()True 布尔值相加
    最后transform,根据文档,行为如下:

    DataFrame.transform(self, func, axis=0, *args, **kwargs) → 'DataFrame'[source]
         "Call func on self producing a DataFrame with transformed values."  
         "Produced DataFrame will have same axis length as self." <----
    ...
    

    希望这有帮助。

    【讨论】:

    • 谢谢。这会创建第二个数据框吗?
    • 在技术意义上是的,但我们将其分配给原始df 作为列'SPOT_CNT'
    【解决方案2】:
    df = pd.read_csv('spot.txt', sep=r"[ ]{1,}", engine='python', dtype='object')
    
    print(df)
    
        CELL_ID Grid_Type
    0   001 Spot
    1   001 Square
    2   001 Spot
    3   001 Square
    4   001 Square
    5   002 Spot
    6   002 Square
    7   002 Square
    8   003 Square
    9   003 Spot
    10  003 Spot
    11  003 Spot
    
    df_gb = df['Grid_Type'].groupby([df['CELL_ID']]).value_counts()
    
    print(df_gb)
    
        CELL_ID  Grid_Type
    001      Square       3
             Spot         2
    002      Square       2
             Spot         1
    003      Spot         3
             Square       1
    Name: Grid_Type, dtype: int64
    
    
    
    df_gb_dict = df_gb.to_dict()
    
    count_list = []
    
    for idx, row in df.iterrows():
        for k, v in df_gb_dict.items():
            if k[0] == row['CELL_ID'] and k[1] == row['Grid_Type'] and row['Grid_Type'] == 'Spot':
                count_list.append([k[0], k[1], v])
            if k[0] == row['CELL_ID'] and k[1] == row['Grid_Type'] and row['Grid_Type'] == 'Square':
                count_list.append([k[0], k[1], df_gb_dict[(row['CELL_ID'], 'Spot')]])
    
    
    new_df = pd.DataFrame(count_list, columns=['CELL_ID',  'Grid_Type', 'SPOT_CNT'])
    
    new_df.sort_values(by='CELL_ID', inplace=True)
    
    new_df.reset_index(drop=True)
    
    print(new_df)
    
      CELL_ID Grid_Type  SPOT_CNT
    0      001      Spot         2
    1      001    Square         2
    2      001      Spot         2
    3      001    Square         2
    4      001    Square         2
    5      002      Spot         1
    6      002    Square         1
    7      002    Square         1
    8      003    Square         3
    9      003      Spot         3
    10     003      Spot         3
    11     003      Spot         3
    

    【讨论】:

    • 很好的答案,谢谢。我想我可以消化它并在很多地方使用。我还发现我可以使用z = df[df.Grid_Type == 'Spot'].groupby('CELL_ID')['Grid_Type'].count() 来计数。我认为 value_counts() 是错误的方法。
    • 我意识到你的问题只需要最后一列中的点数,即使是方形行,所以我相应地编辑了我的答案。
    猜你喜欢
    • 2017-12-28
    • 1970-01-01
    • 2021-07-21
    • 2019-01-18
    • 2020-03-16
    • 2019-05-16
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多