在數(shù)據(jù)分析中,經(jīng)常會遇到這樣的情況:根據(jù)某一列(或多列)標簽把數(shù)據(jù)劃分為不同的組別,然后再對其進行數(shù)據(jù)分析。比如,某網(wǎng)站對注冊用戶的性別或者年齡等進行分組,從而研究出網(wǎng)站用戶的畫像(特點)。在 Pandas 中,要完成數(shù)據(jù)的分組操作,需要使用 groupby() 函數(shù),它和 SQL 的GROUP BY操作非常相似。
在劃分出來的組(group)上應用一些統(tǒng)計函數(shù),從而達到數(shù)據(jù)分析的目的,比如對分組數(shù)據(jù)進行聚合、轉(zhuǎn)換,或者過濾。這個過程主要包含以下三步:
下面對 groupby() 函數(shù)的應用過程進行具體的講解。
首先我們創(chuàng)建一個 DataFrame 對象,下面數(shù)據(jù)描述了某班學生,計算機選修課的考試成績:
import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
'score': [82, 98, 91, 87],
'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
print(df)
輸出結(jié)果:
Name score option_course 0 John 82 C# 1 Helen 98 Python 2 Sona 91 Java 3 Ella 87 C
使用 groupby() 可以沿著任意軸分組。您可以把分組時指定的鍵(key)作為每組的組名,方法如下所示:
通過上述方法對 DataFrame 對象進行分組操作:
import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
'score': [82, 98, 91, 87],
'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
print(df)
#生成分組groupby對象
print(df.groupby('score'))
輸出結(jié)果:
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000021DE9A89640>
通過調(diào)用groups屬性查看分組結(jié)果:
import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
'score': [82, 98, 91, 87],
'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
#查看分組
print(df.groupby('score').groups)
輸出結(jié)果:
{82: Int64Index([0], dtype='int64'), 87: Int64Index([3], dtype='int64'), 91: Int64Index([2], dtype='int64'), 98: Int64Index([1], dtype='int64')}
當然也可以指定多個列標簽進行分組,示例如下:
import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
'score': [82, 98, 91, 87],
'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
#查看分組
print(df.groupby(['Name','score']).groups)
輸出結(jié)果:
{('Ella', 87): Int64Index([3], dtype='int64'), ('Helen', 98): Int64Index([1], dtype='int64'), ('John', 82): Int64Index([0], dtype='int64'), ('Sona', 91): Int64Index([2], dtype='int64')}
通過 get_group() 方法可以選擇組內(nèi)的具體數(shù)據(jù)項:
import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
'score': [82, 98, 91, 87],
'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
#根據(jù)score來分組
grouped=df.groupby('score')
#根據(jù)對應組的數(shù)據(jù)值,選擇一個組
print(grouped.get_group(91))
輸出結(jié)果:
Name score option_course 2 Sona 91 Java
通過以下方法來遍歷分組數(shù)據(jù),示例如下:
import pandas as pd
import numpy as np
data = {'Name': ['John', 'Helen', 'Sona', 'Ella'],
'score': [82, 98, 91, 87],
'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
#查看分組
grouped=df.groupby('score')
for label, option_course in grouped:
#其中key代表分組后字典的鍵,也就是score
print(label)
#字典對應的值選修的科目
print(option_course)
輸出結(jié)果:
82 Name score option_course 0 John 82 C# 87 Name score option_course 3 Ella 87 C 91 Name score option_course 2 Sona 91 Java 98 Name score option_course 1 Helen 98 Python
如上所示, groupby 對象的組名稱與 score 中的的元素值一一對應。
當您在創(chuàng)建 groupby 對象時,通過 agg() 函數(shù)可以對分組對象應用多個聚合函數(shù):
import pandas as pd
import numpy as np
data = {'name': ['John', 'Helen', 'Sona', 'Ella'],
'score': [82, 98, 91, 87],
'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
grouped=df.groupby('name')
#應用一個聚合函數(shù)求均值
print(grouped['score']).agg(np.mean)
輸出結(jié)果:
name Ella 87 Helen 98 John 82 Sona 91 Name: score, dtype: int64
當然,您也可以一次性應有多個聚合函數(shù),示例如下:
import pandas as pd
import numpy as np
data = {'name': ['John', 'Helen', 'Sona', 'Ella'],
'score': [82, 98, 91, 87],
'option_course': ['C#','Python','Java','C']}
df = pd.DataFrame(data)
grouped=df.groupby('name')
print(grouped['score'].agg([np.size,np.mean,np.std]))
輸出結(jié)果:
size mean std name Ella 1 87 NaN Helen 1 98 NaN John 1 82 NaN Sona 1 91 NaN
在組的行或列上可以執(zhí)行轉(zhuǎn)換操作,最終會返回一個與組大小相同的索引對象。示例如下:
import pandas as pd
import numpy as np
df = pd.DataFrame({'種類':['水果','水果','水果','蔬菜','蔬菜','肉類','肉類'],
'產(chǎn)地':['朝鮮','中國','緬甸','中國','菲律賓','韓國','中國'],
'水果':['橘子','蘋果','哈密瓜','番茄','椰子','魚肉','牛肉'],
'數(shù)量':[3,5,5,3,2,15,9],
'價格':[2,5,12,3,4,18,20]})
#分組求均值,水果、蔬菜、肉類
#對可執(zhí)行計算的數(shù)值列求均值
print(df.groupby('種類').transform(np.mean))
#transform()直接應用demean,實現(xiàn)去均值操作
demean = lambda arr:arr-arr.mean()
print(df.groupby('種類').transform(demean))
#自定義函數(shù)
# 返回分組的前n行數(shù)據(jù)
def get_rows(df,n):
#從1到n行的所有列
return df.iloc[:n,:]
#分組后的組名作為行索引
print(df.groupby('種類').apply(get_rows,n=1))
輸出結(jié)果:
數(shù)量 價格 0 4.333333 6.333333 1 4.333333 6.333333 2 4.333333 6.333333 3 2.500000 3.500000 4 2.500000 3.500000 5 12.000000 19.000000 6 12.000000 19.000000 數(shù)量 價格 0 -1.333333 -4.333333 1 0.666667 -1.333333 2 0.666667 5.666667 3 0.500000 -0.500000 4 -0.500000 0.500000 5 3.000000 -1.000000 6 -3.000000 1.000000 種類 產(chǎn)地 水果 數(shù)量 價格 種類 水果 0 水果 朝鮮 橘子 3 2 肉類 5 肉類 韓國 魚肉 15 18 蔬菜 3 蔬菜 中國 番茄 3 3
通過 filter() 函數(shù)可以實現(xiàn)數(shù)據(jù)的篩選,該函數(shù)根據(jù)定義的條件過濾數(shù)據(jù)并返回一個新的數(shù)據(jù)集。
下面,篩選出參加比賽超過三次的球隊(包含三次):
import pandas as pd
import numpy as np
data = {'Team': ['Riders', 'Riders', 'Devils', 'Devils', 'Kings',
'kings', 'Kings', 'Kings', 'Riders', 'Royals', 'Royals', 'Riders'],
'Rank': [1, 2, 2, 3, 3,4 ,1 ,1,2 , 4,1,2],
'Year': [2014,2015,2014,2015,2014,2015,2016,2017,2016,2014,2015,2017],
'Points':[874,789,863,663,741,802,756,788,694,701,812,698]}
df = pd.DataFrame(data)
#定義lambda函數(shù)來篩選數(shù)據(jù)
print (df.groupby('Team').filter(lambda x: len(x) >= 3))
輸出結(jié)果:
Team Rank Year Points 0 Riders 1 2014 874 1 Riders 2 2015 789 4 Kings 3 2014 741 6 Kings 1 2016 756 7 Kings 1 2017 788 8 Riders 2 2016 694 11 Riders 2 2017 698
更多建議: