【问题标题】:Get a new column (consensus of element in others) with pandas使用 pandas 获取新列(其他元素的共识)
【发布时间】:2019-08-19 06:39:08
【问题描述】:

我在使用 pandas 数据框时需要一些帮助。 这是数据框:

group   col1    col2    name
1       dog     40      canidae
1       dog     40      canidae
1       dog     40      canidae
1       dog     40      canidae
1       dog     40  
1       dog     40      canidae
1       dog     40      canidae
2       frog    85      dendrobatidae
2       frog    89      leptodactylidae
2       frog    89      leptodactylidae
2       frog    82      leptodactylidae
2       frog    89 
2       frog    81 
2       frog    89      dendrobatidae
3       horse   87      equidae1
3       donkey  76      equidae2
3       zebra   67      equidae3
4       bird    54      psittacidae
4       bird    56  
4       bird    34  
5       bear    67    
5       bear    54

我想要的是添加一列“consensus_name”并获取:

group col1   col2 name              consensus_name
1     dog    40   canidae           canidae
1     dog    40   canidae           canidae
1     dog    40                     canidae
1     dog    40   canidae           canidae
1     dog    40   canidae           canidae
2     frog   85   dendrobatidae     leptodactylidae
2     frog   89   leptodactylidae   leptodactylidae
2     frog   89   leptodactylidae   leptodactylidae
2     frog   82   leptodactylidae   leptodactylidae
2     frog   89                     leptodactylidae
2     frog   81                     leptodactylidae
2     frog   89   dendrobatidae     leptodactylidae
3     horse  87   equidae1          equidae3
3     donkey 76   equidae2          equidae3
3     zebra  67   equidae3          equidae3
4     bird   54   psittacidae       psittacidae
4     bird   56                     psittacidae
4     bird   34                     psittacidae
5     bear   67                     NA
5     bear   54                     NA

为了得到每个组的这个新列,我得到了最能代表该组的名称。

  • 对于 group1,有 4 行名称为 'canidae',而其中一行没有,因此我在 consensus_name 列中写下每一行 'canidae'

  • 对于group2,有 2 行名称为 'dendrobatidae',2 行没有任何内容,3 行名称为 'leptodactylidae',因此对于每一行,我在 consensus_name 列中写下 'leptodactylidae' .

  • 对于group3,有3行不同的名字,所以因为没有一致意见,我得到的名字是最小的col2数字,所以我在@987654335列写'equidae3' @。

  • 对于第4组只有一行有信息,所以是group4的consensus_name,所以我在consensus_name列写psittacidae

  • 对于group5 没有任何信息,则只需在consensus_name 列中写入NA。

有没有人想用 pandas 来做这件事?感谢您的帮助:)


anky = 的输出

    group    col1  col2             name   consensus_name
0       1     dog    40          canidae          canidae
1       1     dog    40          canidae          canidae
2       1     dog    40          canidae          canidae
3       1     dog    40          canidae          canidae
4       1     dog    40              NaN          canidae
5       1     dog    40          canidae          canidae
6       1     dog    40          canidae          canidae
7       2    frog    85    dendrobatidae    dendrobatidae
8       2    frog    89  leptodactylidae  leptodactylidae
9       2    frog    89  leptodactylidae  leptodactylidae
10      2    frog    82  leptodactylidae  leptodactylidae
11      2    frog    89              NaN  leptodactylidae
12      2    frog    81              NaN  leptodactylidae
13      2    frog    89    dendrobatidae    dendrobatidae
14      3   horse    87         equidae1         equidae1
15      3  donkey    76         equidae2         equidae2
16      3   zebra    67         equidae3         equidae3
17      4    bird    54      psittacidae      psittacidae
18      4    bird    56              NaN      psittacidae
19      4    bird    34              NaN      psittacidae
20      5    bear    67              NaN              NaN
21      5    bear    54              NaN              NaN

【问题讨论】:

  • df['consensus_name']=df.groupby(['group','col1'])['name'].apply(lambda x:x.ffill().bfill()) ??
  • @anky_91 你好,谢谢,但我对equidae3 (group3) 没有达成共识,我应该得到col2 值最低的名称。而在 group2 中,并非所有个人都有共识名称 leptodactylidae13 行保留了 dendrobatidae 名称...
  • 当您要求在 R 中找到解决方案时,为什么这个问题会被 Python 和 pandas 标记?
  • @Guybrush 这是我的错误,抱歉。

标签: python python-3.x pandas pandas-groupby


【解决方案1】:

使用pandas.DataFrame.Groupby.Series.transform 并将max 函数传递给它:

#First fillna with empty string
df.name.fillna('', inplace=True)

df['consensus_name'] = df.groupby('group').name.transform('max')

print(df)
    group    col1  col2             name   consensus_name
0       1     dog    40          canidae          canidae
1       1     dog    40          canidae          canidae
2       1     dog    40          canidae          canidae
3       1     dog    40          canidae          canidae
4       1     dog    40                           canidae
5       1     dog    40          canidae          canidae
6       1     dog    40          canidae          canidae
7       2    frog    85    dendrobatidae  leptodactylidae
8       2    frog    89  leptodactylidae  leptodactylidae
9       2    frog    89  leptodactylidae  leptodactylidae
10      2    frog    82  leptodactylidae  leptodactylidae
11      2    frog    89                   leptodactylidae
12      2    frog    81                   leptodactylidae
13      2    frog    89    dendrobatidae  leptodactylidae
14      3   horse    87         equidae1         equidae3
15      3  donkey    76         equidae2         equidae3
16      3   zebra    67         equidae3         equidae3
17      4    bird    54      psittacidae      psittacidae
18      4    bird    56                       psittacidae
19      4    bird    34                       psittacidae
20      5    bear    67                                  
21      5    bear    54                                  

编辑后指出一般不适用:

df['name'] = df.groupby('group').name.ffill()

df_group = df.groupby('group').name.apply(lambda x: pd.Series.mode(x, dropna=False)).reset_index()
df_group = df_group[df_group.level_1 == df_group.groupby('group').level_1.transform('max')]
df_group.rename({'name':'consensus_name'},axis=1, inplace=True)

df_final = pd.merge(df, df_group, on='group')

print(df_final)
    group    col1  col2             name  level_1   consensus_name
0       1     dog    40          canidae        0          canidae
1       1     dog    40          canidae        0          canidae
2       1     dog    40          canidae        0          canidae
3       1     dog    40          canidae        0          canidae
4       1     dog    40          canidae        0          canidae
5       1     dog    40          canidae        0          canidae
6       1     dog    40          canidae        0          canidae
7       2    frog    85    dendrobatidae        0  leptodactylidae
8       2    frog    89  leptodactylidae        0  leptodactylidae
9       2    frog    89  leptodactylidae        0  leptodactylidae
10      2    frog    82  leptodactylidae        0  leptodactylidae
11      2    frog    89  leptodactylidae        0  leptodactylidae
12      2    frog    81  leptodactylidae        0  leptodactylidae
13      2    frog    89    dendrobatidae        0  leptodactylidae
14      3   horse    87         equidae1        2         equidae3
15      3  donkey    76         equidae2        2         equidae3
16      3   zebra    67         equidae3        2         equidae3
17      4    bird    54      psittacidae        0      psittacidae
18      4    bird    56      psittacidae        0      psittacidae
19      4    bird    34      psittacidae        0      psittacidae
20      5    bear    67              NaN        0              NaN
21      5    bear    54              NaN        0              NaN

【讨论】:

  • 非常感谢您的帮助,它就像一个魅力。
  • 如果我没记错的话,当您将max 应用于对象类型列时。它获取出现次数最多的字符串。与字典无关。 @ALollz
  • 我同意@ALollz!这不是一个正确的答案。这是一个三步过程: (1) 分组行; (2) 统计每组的行数; (3) 合并回来,按计数排序并删除重复项。
  • @Erfan no max 总是返回最大值,而不是最频繁的值。检查pd.DataFrame({'A': [1,1,1], 'B': ['a', 'a', 'b']}).groupby('A').B.transform('max')
  • @ALollz 感谢您的指出。编辑我的答案以正确输出。
【解决方案2】:

您需要定义自己的函数。确保用NaN 替换空字符串,这样它们就不会被考虑。 transform 基于多列的计算可能会变得很棘手,因此请改为 groupby 并将结果映射回原始结果。

import numpy as np

def my_mode(gp):
    s = gp['name'].value_counts()
    s = s[s.eq(s.max())]

    if len(s) == 0:      # If all missing
        return np.NaN
    elif len(s) == 1:    # If there is a mode without ties
        return s.index[0]
    else:                # If ties, use the one with min col2 
        return gp.loc[gp['name'].isin(s.index)].sort_values('col2')['name'].iloc[0]

df['name'] = df['name'].replace({'': np.NaN})
df['consensus_name'] = df['group'].map(df.groupby('group').apply(my_mode))

输出:

    group    col1  col2             name   consensus_name
0       1     dog    40          canidae          canidae
1       1     dog    40          canidae          canidae
2       1     dog    40          canidae          canidae
3       1     dog    40          canidae          canidae
4       1     dog    40              NaN          canidae
5       1     dog    40          canidae          canidae
6       1     dog    40          canidae          canidae
7       2    frog    85    dendrobatidae  leptodactylidae
8       2    frog    89  leptodactylidae  leptodactylidae
9       2    frog    89  leptodactylidae  leptodactylidae
10      2    frog    82  leptodactylidae  leptodactylidae
11      2    frog    89              NaN  leptodactylidae
12      2    frog    81              NaN  leptodactylidae
13      2    frog    89    dendrobatidae  leptodactylidae
14      3   horse    87         equidae1         equidae3
15      3  donkey    76         equidae2         equidae3
16      3   zebra    67         equidae3         equidae3
17      4    bird    54      psittacidae      psittacidae
18      4    bird    56              NaN      psittacidae
19      4    bird    34              NaN      psittacidae
20      5    bear    67              NaN              NaN
21      5    bear    54              NaN              NaN   

我们没有明确定义的唯一边缘情况是当模态值它们与col2的最小值相同时会发生什么。目前,在这些情况下,它将选择索引最低的名称(DataFrame 中最先出现的名称)。

【讨论】:

  • @chippycentra 这应该是公认的答案。正如所指出的,我的答案在所有情况下都不起作用。只要答案被接受,我就无法删除我的答案。
  • 非常感谢您的帮助和时间,它运行良好:)
猜你喜欢
  • 2021-08-28
  • 2021-11-16
  • 1970-01-01
  • 2015-10-02
  • 1970-01-01
  • 2017-04-30
  • 2017-08-13
  • 2022-12-05
  • 2021-08-04
相关资源
最近更新 更多