基于Python中的其他列对列进行分组

2024-05-12 22:55:32 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有以下pd.DataFrame

Name | Color
------------------------------
John | Blue
Greg | Red
John | Yellow
Greg | Red
Greg | Blue

我想为每个名字得到一个不同颜色的表-有多少和它们的值。意思是这样的:

Name | Distinct | Values
--------------------------------------
John |   2      | Blue, Yellow
Greg |   2      | Red, Blue

你知道怎么做吗?你知道吗


Tags: namedataframe颜色bluered名字johncolor
3条回答

^{}^{}、最后rename列和^{}一起使用:

df = (df.groupby('Name')['Color'].agg(['nunique', lambda x: ', '.join(set(x))])
        .rename(columns={'nunique':'Distinct', '<lambda>':'Values'})
        .reset_index())
print (df)
   Name  Distinct        Values
0  Greg         2     Blue, Red
1  John         2  Blue, Yellow

一种避免低效lambda的方法:

df = df.groupby('Name')['Color'].apply(set).reset_index()

df['Distinct'] = df['Color'].map(len)
df['Color'] = df['Color'].map(', '.join)

#    Name         Color  Distinct
# 0  Greg     Red, Blue         2
# 1  John  Yellow, Blue         2

另一方面,我注意到一种趋势,即方法链和/或单行计算。如果性能不是问题,我建议使用您认为更有用/可读的内容。就我个人而言,我更喜欢把计算分成三部分。你知道吗

绩效基准

import pandas as pd
import numpy as np
from random import choice
from string import ascii_uppercase

df = pd.DataFrame({'Name': np.random.randint(0, 100, 10000),
                   'Color': [''.join(choice(ascii_uppercase) for _ in range(2)) for k in range(10000)]})

def jpp(df):
    df = df.groupby('Name')['Color'].apply(set).reset_index()

    df['Distinct'] = df['Color'].map(len)
    df['Color'] = df['Color'].map(', '.join)
    return df

def jez(df):
    return df.groupby('Name')['Color'].agg(['nunique', lambda x: ', '.join(set(x))])\
            .rename(columns={'nunique':'Distinct', '<lambda>':'Values'})\
            .reset_index()

def cs(df):
    f = [
            ('Distinct', 'nunique'), 
            ('Values', lambda x: ', '.join(x.unique()))
    ]

    return df.groupby('Name').Color.agg(f).reset_index()

%timeit jpp(df)  # 100 loops, best of 3: 15.7 ms per loop
%timeit jez(df)  # 10 loops, best of 3: 22.9 ms per loop
%timeit cs(df)   # 10 loops, best of 3: 27.1 ms per loop

使用groupby+agg,传递聚合函数的自定义list

f = [
        ('Distinct', 'nunique'), 
        ('Values', lambda x: ', '.join(x.unique()))
]

df.groupby('Name').Color.agg(f).reset_index()

   Name  Distinct        Values
0  Greg         2     Red, Blue
1  John         2  Blue, Yellow

计时

首先,设置-

df = pd.DataFrame(
      np.random.randint(0, 1000, (10000, 2)).astype(str), columns=['Name', 'Color']
)

接下来是计时。似乎pd.Series.unique慢得不合理(慢了4倍)。为了提高性能,我将使用np.unique

# in this answer

%%timeit
f = [
        ('Distinct', 'nunique'), 
        ('Values', lambda x: ', '.join(np.unique(x.values).tolist()))
]

df.groupby('Name').Color.agg(f).reset_index()

122 ms ± 1.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

使用lambda x: ', '.join(x.unique())会导致4倍的减速。使用set在这个数据上要快一些,但这要视情况而定。 你知道吗

# @jpp

%%timeit
v = df.groupby('Name')['Color'].apply(set).reset_index()
v['Distinct'] = v['Color'].map(len)
v['Color'] = v['Color'].map(', '.join)

219 ms ± 1.83 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# @jezrael

%%timeit
(df.groupby('Name')['Color'].agg(['nunique', lambda x: ', '.join(set(x))])
        .rename(columns={'nunique':'Distinct', '<lambda>':'Values'})
        .reset_index())

118 ms ± 4.29 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

性能随数据的变化而变化,在决定使用什么之前,您可能需要根据自己的数据计算所有解决方案的时间。你知道吗

相关问题 更多 >