[英]Group columns based on other columns in Python Pandas
假設我有以下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
有什么想法怎么做?
使用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)
性能隨數據變化很大 ,您可能希望在決定使用什么之前為所有解決方案計算自己的數據。
使用groupby
with agg
,last rename
columns和reset_index
:
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
順便說一句,我注意到了方法鏈和/或單線計算的趨勢。 如果性能不是問題,我建議使用您發現更有用/可讀的內容。 就個人而言,我更喜歡將計算分為3個部分。
績效基准
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.