Pandas:将groupby的结果分配给数据框中的新列

4
我有以下的玩具数据框(实际数据框有50万行):
df = pd.DataFrame({'size': list('SSMMMLS'),
                   'weight': [8, 10, 11, 1, 20, 14, 12],
                   'adult' : [False] * 5 + [True] * 2})

   adult size  weight
0  False    S       8
1  False    S      10
2  False    M      11
3  False    M       1
4  False    M      20
5   True    L      14
6   True    S      12

想要按adult分组,选择weight最大的行,并将其赋值给一个新列size2中的size列的值。
换句话说,我们希望有一个名为size2的列,该列包含具有最大weight值的行的size值,并传播到adult分组。因此,所有adult=False的行都将具有值S,因为adult=False时max weight为20。
   adult size size2  weight
0  False    S     S       8
1  False    S     S      10
2  False    M     S      11
3  False    M     S       1
4  False    M     S      20
5   True    L     L      14
6   True    S     L      12

我发现了这个链接,但它对我不起作用。
到目前为止,我有:
df.loc[:, 'size2'] = (df.groupby('adult',as_index=True)['weight','size']
                        .transform(lambda x: x.ix[x['weight'].idxmax()]['size']))
3个回答

4
您可以使用 transformlocvalues 来实现此功能:
>>> df["size2"] = df["size"].loc[df.groupby("adult")["weight"].transform("idxmax")].values
>>> df
   adult size  weight size2
0  False    S       8     M
1  False    S      10     M
2  False    M      11     M
3  False    M       1     M
4  False    M      20     M
5   True    L      14     L
6   True    S      12     L

一步一步来,首先我们找到合适的索引:
>>> df.groupby("adult")["weight"].transform("idxmax")
0    4
1    4
2    4
3    4
4    4
5    5
6    5
dtype: int64

然后我们使用这些索引来使用loc访问size列:

>>> df["size"].loc[df.groupby("adult")["weight"].transform("idxmax")]
4    M
4    M
4    M
4    M
4    M
5    L
5    L
Name: size, dtype: object

最后,我们使用.values来避免在尝试赋值时受到索引的干扰:

>>> df["size"].loc[df.groupby("adult")["weight"].transform("idxmax")].values
array(['M', 'M', 'M', 'M', 'M', 'L', 'L'], dtype=object)

>>> df["size2"] = df["size"].loc[df.groupby("adult")["weight"].transform("idxmax")].values

>>> df
   adult size  weight size2
0  False    S       8     M
1  False    S      10     M
2  False    M      11     M
3  False    M       1     M
4  False    M      20     M
5   True    L      14     L
6   True    S      12     L
>>> 

2

以下是对@jazrael的回答进行详细说明,结合您的数据框:

df = pd.DataFrame({'size': list('SSMMMLS'),
                   'weight': [8, 10, 11, 1, 20, 14, 12],
                   'adult' : [False] * 5 + [True] * 2})
#    adult size  weight
# 0  False    S       8
# 1  False    S      10
# 2  False    M      11
# 3  False    M       1
# 4  False    M      20
# 5   True    L      14
# 6   True    S      12

为了获取最大重量线的尺寸值:
def size4max_weight(subf):
    """ Return size value for the max weight line """
    return subf['size'][subf['weight'].idxmax()]

以 'adult' 作为分组条件将产生一个包含 False、True 值的系列:

>>> size2_col = df.groupby('adult').apply(size4max_weight)
>>> type(size2_col), size2_col.index
(pandas.core.series.Series, Index([False, True], dtype='object', name=u'adult'))

使用reset_index,我们可以将Series转换为DataFrame:
>>> size2_col = df.groupby('adult').apply(size4max_weight).reset_index(name='size2')
>>> size2_col
   adult size2
0  False     M
1   True     L
>>>

pd.merge 在 'adult' 上进行合并:

>>> pd.merge(df, size2_col, on=['adult'])
   adult size  weight size2
0  False    S       8     M
1  False    S      10     M
2  False    M      11     M
3  False    M       1     M
4  False    M      20     M
5   True    L      14     L
6   True    S      12     L

1
我理解你可以使用 merge。我认为size2中的第一个值是M,因为最大的weight20
df = pd.DataFrame({'size': list('SSMMMLS'),
                   'weight': [8, 10, 11, 1, 20, 14, 12],
                   'adult' : [False] * 5 + [True] * 2})

print(df)
   adult size  weight
0  False    S       8
1  False    S      10
2  False    M      11
3  False    M       1
4  False    M      20
5   True    L      14
6   True    S      12

print(
    df.groupby('adult') 
       .apply(lambda subf: subf['size'][subf['weight'].idxmax()]).reset_index(name='size2')
    )               
   adult size2
0  False     M
1   True     L

print(
    pd.merge(df, 
             df.groupby('adult')
               .apply(lambda subf: subf['size'][subf['weight'].idxmax()]
                     ).reset_index(name='size2'), on=['adult'])
      )          
   adult size  weight size2
0  False    S       8     M
1  False    S      10     M
2  False    M      11     M
3  False    M       1     M
4  False    M      20     M
5   True    L      14     L
6   True    S      12     L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接