pandas分組聚合

數(shù)據(jù)的分組運算和聚合

在將數(shù)據(jù)集加載、融合吃挑、準(zhǔn)備好之后钝荡,通常就是計算分組統(tǒng)計或?成透視表, pandas提供了
?個靈活?效的groupby功能舶衬,它使你能以?種?然的?式對數(shù)據(jù)集進(jìn)?切?埠通、切塊、摘要等
操作

1. 分組機(jī)制 -- GroupBy

分組運算"split-apply-combine"(拆分-應(yīng)?-合并)逛犹。第?個階段端辱,pandas對象
(?論是Series、DataFrame還是其他的)中的數(shù)據(jù)會根據(jù)你所提供的?個或多個鍵被拆分
(split)為多組虽画。拆分操作是在對象的特定軸上執(zhí)?的舞蔽。例如,DataFrame可以在其?
(axis=0)或列(axis=1)上進(jìn)?分組码撰。然后渗柿,將?個函數(shù)應(yīng)?(apply)到各個分組并產(chǎn)
 ??個新值。最后脖岛,所有這些函數(shù)的執(zhí)?結(jié)果會被合并(combine)到最終的結(jié)果對象中

 df = pd.DataFrame({'key1' : ['a', 'a', 'b', 'b', 'a'],
 ....: 'key2' : ['one', 'two', 'one', 'two', 'one'],
 ....: 'data1' : np.random.randn(5),
 ....: 'data2' : np.random.randn(5)})
 grouped = df['data1'].groupby(df['key1'])
  變量grouped是?個GroupBy對象做祝。它實際上還沒有進(jìn)?任何計算砾省,只是含有?些有關(guān)分組鍵df[‘key1’]的中間數(shù)據(jù)?已
 grouped.mean()  # 對分組的數(shù)據(jù)求平均值鸡岗,索引是key1列去重后的值
 means = df['data1'].groupby([df['key1'], df['key2']]).mean()  # ?次傳?多個數(shù)組的列表混槐,外層索引為key1,內(nèi)層索引為key2,數(shù)據(jù)為data1的平均值
 means.unstack() # 轉(zhuǎn)置轩性,默認(rèn)把外層索引變?yōu)榱兴饕牵瑐魅雲(yún)?shù)1默認(rèn)將內(nèi)層索引變?yōu)榱兴饕?

GroupBy的size?法,它可以返回?個含有分組??的Series(填充數(shù)據(jù)為每一組包含的原始數(shù)據(jù)個數(shù))

df.groupby(['key1', 'key2']).size()

2.對分組進(jìn)行迭代:

GroupBy對象?持迭代揣苏,可以產(chǎn)??組?元元組(由分組名和數(shù)據(jù)塊組成)

a. 單一分組鍵情況:
    for name, group in df.groupby('key1'):
    ....: print(name)
    ....: print(group)
    
    輸出如下:
    a
     data1 data2 key1 key2
    0 -0.204708 1.393406 a one
    1  0.478943 0.092908 a two
    4  1.965781 1.246435 a one
    b
     data1 data2 key1 key2
    2 -0.519439 0.281746 b one
    3 -0.555730 0.769023 b two

b. 多重分組鍵情況(元組的第?個元素將會是由鍵值組成的元組):
     for (k1, k2), group in df.groupby(['key1', 'key2']):
     ....: print((k1, k2))
     ....: print(group)
    
    輸出如下:
    ('a', 'one')
     data1 data2 key1 key2
    0 -0.204708 1.393406 a one
    4  1.965781  1.246435 a one
    ('a', 'two')
     data1 data2 key1 key2
    1 0.478943 0.092908 a two
    ('b', 'one')
     data1 data2 key1 key2
    2 -0.519439 0.281746 b one
    ('b', 'two')
     data1 data2 key1 key2
    3 -0.55573 0.769023 b two

pieces = dict(list(df.groupby('key1'))) # 將分組后的數(shù)據(jù)做成一個字典(只能是一個分組鍵)
pieces['b'] # 通過key1的值拿到相應(yīng)片段的數(shù)據(jù)集

3. 根據(jù)dtypes對列進(jìn)行分組--df.dtypes輸出字段對應(yīng)數(shù)據(jù)類型(float64,object等)

     grouped = df.groupby(df.dtypes, axis=1)
     for dtype, group in grouped:
     ....: print(dtype)
     ....: print(group)
    
    輸出如下:
    
    float64
     data1 data2
    0 -0.204708 1.393406
    1 0.478943 0.092908
    2 -0.519439 0.281746
    3 -0.555730 0.769023
    4 1.965781 1.246435
    object
     key1 key2
    0 a one
    1 a two
    2 b one
    3 b two
    4 a one

4. 分組后選取分組的一列或者列的子集(默認(rèn)是按行分組)

df.groupby('key1')['data1'] # 取一列(結(jié)果還是分組對象)
df.groupby('key1')[['data1'悯嗓,'data2']] # 取多列(結(jié)果還是分組對象)
df.groupby(['key1', 'key2'])[['data2']].mean() # 分組后取data2列的數(shù)據(jù),按組求每一組data2的平均卸察,返回一個dataframe(兩層索引脯厨,key1和key2)

5.根據(jù)字典或者Sreies分組

 people = pd.DataFrame(np.random.randn(5, 5),
 ....: columns=['a', 'b', 'c', 'd', 'e'],
 ....: index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'])

 mapping = {'a': 'red', 'b': 'red', 'c': 'blue',
 ....: 'd': 'blue', 'e': 'red', 'f' : 'orange'}
 根據(jù)字典分組,再對每組求和(默認(rèn)按行分組,如果設(shè)置axis=1按列分組坑质,那么就按列求和):
 by_dict = people.groupby(mapping, axis=1).sum()
 根據(jù)Series分組(按列分組合武,那么就按列求和)
 map_series = pd.Series(mapping)
 by_series = people.groupby(map_series, axis=1).count()

6.通過函數(shù)進(jìn)行分組:

使?Python函數(shù)是?種更原?的?法定義分組映射。任何被當(dāng)做分組鍵的函數(shù)都會在各個索引值上被調(diào)??次涡扼,其返回值就會被?作分組名稱

people.groupby(len).sum()  # 根據(jù)people的行索引的長度分組稼跳,再對每組每列所有行數(shù)據(jù)求和
key_list = ['one', 'one', 'one', 'two', 'two']
people.groupby([len, key_list]).min() # 根據(jù)行索引長度和key_list來分組再取分組后每組每列所有行中的最小值作為填充數(shù)據(jù)(外層索引len的返回值的去重值,內(nèi)層索引key_list去重的值)

7.通過索引級別來分組:

層次化索引數(shù)據(jù)集最?便的地?就在于它能夠根據(jù)軸索引的?個級別進(jìn)?聚合吃沪,要根據(jù)級別分組汤善,使?level關(guān)鍵字傳遞級別序號或名字

 columns = pd.MultiIndex.from_arrays([['US', 'US', 'US', 'JP', 'JP'],
 ....: [1, 3, 5, 1, 3]],
 ....: names=['cty', 'tenor']) # 創(chuàng)建名字為為cty外層索引,名字為tenor的內(nèi)層索引
 hier_df = pd.DataFrame(np.random.randn(4, 5), columns=columns) # 創(chuàng)建dataframe,列索引為columns
 hier_df.groupby(level='cty', axis=1).count() # 分組鍵為cty層索引票彪,按列分組红淡,再統(tǒng)計每組每行的列數(shù)

數(shù)據(jù)的聚合

聚合指的是任何能夠從數(shù)組產(chǎn)?標(biāo)量值的數(shù)據(jù)轉(zhuǎn)換過程,?如mean降铸、count在旱、min以及sum等

1. 聚合函數(shù):

第一種.pandas內(nèi)置聚合函數(shù):
    count         分組中非NA值的數(shù)量
    sum           非NA值的和
    mean          非NA值的平均值
    median        非NA值的算術(shù)中位數(shù)
    std、var      無偏(分母為n-1)標(biāo)準(zhǔn)差和方差
    min垮耳、max      非NA值的最小和最大值
    prod          非NA值的極
    first颈渊、last   第一個和最后一個非NA值
第二種.自定義聚合函數(shù)(傳入aggregate或者agg方法):
     def peak_to_peak(arr):
     ....: return arr.max() - arr.min()
     grouped.agg(peak_to_peak)

2. 面向列的多函數(shù)應(yīng)用(默認(rèn)將作為分組條件的列變?yōu)樾兴饕鄠€條件列則變?yōu)閷哟位饕?/h2>

tips = pd.read_csv('examples/tips.csv')
tips['tip_pct'] = tips['tip'] / tips['total_bill']
grouped = tips.groupby(['day', 'smoker'])
grouped_pct = grouped['tip_pct']
grouped_pct.agg('mean') # 每個分組對tip_pct數(shù)據(jù)求平均终佛,輸出兩層行索引和一列數(shù)據(jù)(共3列)

傳??組函數(shù)或函數(shù)名俊嗽,得到的DataFrame的列就會以相應(yīng)的函數(shù)命名:
grouped_pct.agg(['mean', 'std', peak_to_peak]) # 輸出兩層索引和三列數(shù)據(jù)(共5列)

傳?的是?個由(name,function)元組組成的列表,則各元組的第?個元素就會被?作DataFrame的列名:
grouped_pct.agg([('foo', 'mean'), ('bar', np.std)])

對兩列數(shù)據(jù)計算三個統(tǒng)計數(shù)據(jù):
result = grouped['tip_pct', 'total_bill'].agg(['count', 'mean', 'max'])
result['tip_pct'] # 取出tip_pct數(shù)據(jù)的統(tǒng)計信息铃彰,返回一個dataframe

傳入元祖自定義默認(rèn)的統(tǒng)計名(函數(shù)名)
grouped['tip_pct', 'total_bill'].agg([('Dur', 'mean'),('Abw', np.var)])

對?個列或不同的列應(yīng)?不同的函數(shù)绍豁,向agg傳??個從列名映射到函數(shù)的字典
grouped.agg({'tip' : np.max, 'size' : 'sum'})
grouped.agg({'tip_pct' : ['min', 'max', 'mean', 'std'],'size' : 'sum'})

傳入as_index=False 阻止將作為分組條件的列變?yōu)樗饕A魹閿?shù)據(jù)牙捉;對結(jié)果調(diào)?reset_index也能
得到這種形式的結(jié)果竹揍。但使?as_index=False?法可以避免?些不必要的計算
tips.groupby(['day', 'smoker'], as_index=False).mean()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末敬飒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子芬位,更是在濱河造成了極大的恐慌无拗,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昧碉,死亡現(xiàn)場離奇詭異英染,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)被饿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門四康,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人狭握,你說我怎么就攤上這事闪金。” “怎么了论颅?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵哎垦,是天一觀的道長。 經(jīng)常有香客問我嗅辣,道長撼泛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任澡谭,我火速辦了婚禮愿题,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蛙奖。我一直安慰自己潘酗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布雁仲。 她就那樣靜靜地躺著仔夺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪攒砖。 梳的紋絲不亂的頭發(fā)上缸兔,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天,我揣著相機(jī)與錄音吹艇,去河邊找鬼惰蜜。 笑死,一個胖子當(dāng)著我的面吹牛受神,可吹牛的內(nèi)容都是我干的抛猖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼财著!你這毒婦竟也來了联四?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤撑教,失蹤者是張志新(化名)和其女友劉穎朝墩,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驮履,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡鱼辙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了玫镐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡怠噪,死狀恐怖恐似,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情傍念,我是刑警寧澤矫夷,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站憋槐,受9級特大地震影響双藕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阳仔,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一忧陪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧近范,春花似錦嘶摊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呀袱。三九已至哥攘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間聪黎,已是汗流浹背蔗喂。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工忘渔, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弱恒。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓辨萍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锈玉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容