本文敘述使用的“數(shù)據(jù)集”鏈接下載地址如下:
http://note.youdao.com/noteshare?id=5f44492149116cb6c52233786c1ca98d&sub=6C35AFC6AF9441648F245393DCAC61CB
1、MySQL和Pandas做分組聚合的對比說明
1)都是用來處理表格數(shù)據(jù)
??不管是mysql,還是pandas,都是處理像excel那樣的二維表格數(shù)據(jù)的。對于一個二維表,每一行都可以看作是一條記錄,每一列都可以看作是字段。
2)分組聚合的風(fēng)格不同
??學(xué)過mysql的人都知道,mysql在做數(shù)據(jù)處理和統(tǒng)計分析的時候,有一個很大的痛點:語法順序和執(zhí)行順序不一致,這就導(dǎo)致很多初學(xué)者很容易寫錯sql語句。
??業(yè)界處理像excel那樣的二維表格數(shù)據(jù),通常有如下兩種風(fēng)格:
- DSL風(fēng)格:使用面向?qū)ο蟮姆绞絹聿僮鳎琾andas就是采用這種方式,通俗說就是“語法順序和執(zhí)行順序一致”。
- SQL風(fēng)格:寫sql語句來處理。
3)從代碼角度,說明兩者的不同
① mysql
語法順序:
SELECT Column1, Column2, mean(Column3), sum(Column4)
FROM SomeTable
WHERE Condition 1
GROUP BY Column1, Column2
HAVING Condition2
邏輯執(zhí)行順序:
from...where...group...select...having...limit
② pandas
語法順序和邏輯執(zhí)行順序:
df[Condition1].groupby([Column1,Column2],as_index=False).agg({Column3: "mean",Column4:"sum"})
③ 圖示說明
- 首先from相當(dāng)于取出MySQL中的一張表,對比pandas就是得到了一個df表對象。
- 然后就是執(zhí)行where篩選,對比pandas就相當(dāng)于寫一個condition1過濾條件,做一個分組前的篩選篩選。
- 接著就是執(zhí)行g(shù)roup分組條件,對比pandas就是寫一個groupby條件進(jìn)行分組。
- 再接著就是執(zhí)行select條件,聚合函數(shù)就是寫在select后面的,對比pandas就是執(zhí)行agg()函數(shù),在其中針對不同的列執(zhí)行count、max、min、sum、mean聚合函數(shù)。
- 最后執(zhí)行的是having表示分組后的篩選,在pandas中,通過上圖可以發(fā)現(xiàn)我們得到了一個df1對象,針對這個df1對象,我們再做一次篩選,也表示分組后的篩選。
- 綜上所述:只要你的邏輯想好了,在pandas中,由于語法順序和邏輯執(zhí)行順序是一致的,你就按照邏輯順序?qū)懴氯?,就很容易了?/li>
4)用一個例子講述MySQL和Pandas分組聚合
① 求不同deptno(部門)下,sal(工資)大于8000的部門、工資;
② mysqi中代碼執(zhí)行如下
select deptno,sum(sal) sums
from emp
group by deptno
having sums > 9000;
結(jié)果如下:
③ pandas中代碼執(zhí)行如下
df = pd.read_excel(r"C:\Users\黃偉\Desktop\emp.xlsx")
display(df)
df = df.groupby("deptno",as_index=False).agg({"sal":"sum"})
display(df)
df1 = df[df["sal"]>9000]
display(df1)
結(jié)果如下:
2、groupby分組聚合的原理說明
1)原理圖
2)原理說明
- split:按照指定規(guī)則分組,由groupby實現(xiàn);
- apply:針對每個小組,使用函數(shù)進(jìn)行操作,得到結(jié)果,由agg()函數(shù)實現(xiàn);
- combine:將每一組得到的結(jié)果,匯總起來,得到最終結(jié)果;
- 注意:combine這一步是自動完成的,因此針對pandas中的分組聚合,我們只需要學(xué)習(xí)兩個內(nèi)容,① 學(xué)習(xí)怎么分組;② 學(xué)習(xí)如何針對每個分組中的數(shù)據(jù),進(jìn)行對應(yīng)的邏輯操作;
3、groupby分組對象的相關(guān)操作
??我們可以通過groupby方法來對Series或DataFrame對象實現(xiàn)分組操作,該方法會返回一個分組對象。但是,如果直接查看(輸出)該對象,并不能看到任何的分組信息。
1)groupby()函數(shù)語法
① 語法如下
- groupby(by=[“字段1”,“字段2”,…],as_index=True)
② 參數(shù)說明
- by參數(shù)傳入的分組字段,當(dāng)只有一個字段的時候,可以直接寫by=“字段1”。當(dāng)多字段聯(lián)合分組的時候,就寫成列表形式by=[“字段1”,“字段2”]。
- as_index參數(shù)的使用如圖所示
③ 參數(shù)as_index的使用說明
x = {"name":["a","a","b","b","c","c","c"],"num":[2,4,0,5,5,10,15]}
df = pd.DataFrame(x)
display(df)
df.groupby("name",as_index=True).agg({"num":"sum"})
df.groupby("name",as_index=False).agg({"num":"sum"})
結(jié)果如下:
2)groupby分組對象的常用方法或?qū)傩浴?/h5>
① groups屬性:返回一個字典,key表示組名,value表示這一組中的所有記錄;
② size()方法:返回每個分組的記錄數(shù);
x = {"name":["a","a","b","b","c","c","c"],"num":[2,4,0,5,5,10,15]}
df = pd.DataFrame(x)
display(df)
df.groupby("deptno").groups
df.groupby("deptno").size()
結(jié)果如下:
3)使用for循環(huán)打印groupby()分組對象中每一組的具體數(shù)據(jù)
x = {"name":["a","a","b","b","c","c","c"],"num":[2,4,0,5,5,10,15]}
df = pd.DataFrame(x)
display(df)
groupdf = df.groupby("name")
for (x,y) in groupdf:
display(x, y)
結(jié)果如下:
4)groupby()分組參數(shù)的4種形式
- 單字段分組:根據(jù)df中的某個字段進(jìn)行分組。
- 多字段分組:根據(jù)df中的多個字段進(jìn)行聯(lián)合分組。
- 字典或Series:key指定索引,value指定分組依據(jù),即value值相等的記錄,會分為一組。
- 自定義函數(shù):接受索引,索引相同的記錄,會分為一組。
使用如下數(shù)據(jù)演示這4種分組參數(shù):
df = pd.DataFrame({"部門":["A", "A", "B", "B"],
"小組":["g1", "g2", "g1", "g2"],
"利潤":[10, 20, 15, 28],
"人員":["a", "b", "c", "d"],
"年齡":[20, 15, 18, 30]})
display(df)
結(jié)果如下:
① 單字段分組:根據(jù)df中的某個字段進(jìn)行分組。
g = df.groupby("部門")
display(g)
for (x,y) in g:
display(x, y)
結(jié)果如下:
② 多字段分組:根據(jù)df中的多個字段進(jìn)行聯(lián)合分組。
g = df.groupby(["部門","小組"])
display(g)
for (x,y) in g:
display(x, y)
結(jié)果如下:
③ 字典:key指定索引,value指定分組依據(jù),即value值相等的記錄,會分為一組。
g = df.groupby({0:1, 1:1, 2:1, 3:2})
display(g)
for (x,y) in g:
display(x, y)
結(jié)果如下:
④ Series:分組排序(很重要)
df = pd.DataFrame({"部門":["A", "A", "A", "B", "B", "B"],
"利潤":[10, 32, 20, 15, 28, 10],
"銷售量":[20, 15, 33, 18, 30, 22]})
display(df)
df["排名"] = df["銷售量"].groupby(df["部門"]).rank()
df
結(jié)果如下:
⑤ 自定義函數(shù):將部門A、B分為一組,C單獨成為一組(很特別的需求)
df = pd.DataFrame({"部門":["A", "A", "B", "B", "C", "C"],
"小組":["g1", "g2", "g1", "g2", "g1", "g2"],
"利潤":[10, 20, 15, 28, 12, 14],
"人員":["a", "b", "c", "d", "e", "f"],
"年齡":[20, 15, 18, 30, 23, 34]})
df = df.set_index("部門")
display(df)
def func(x):
if x=="A" or x=="B":
return 0
else:
return 1
g = df.groupby(func)
display(g)
for (x,y) in g:
display(x, y)
結(jié)果如下:
4、agg()聚合操作的相關(guān)說明
??當(dāng)使用了groupby()分組的時候,得到的就是一個分組對象。當(dāng)沒有使用groupby()分組的時候,整張表可以看成是一個組,也相當(dāng)于是一個分組對象。
??針對分組對象,我們既可以直接調(diào)用聚合函數(shù)sum()、mean()、count()、max()、min(),還可以調(diào)用分組對象的agg()方法,然后像agg()中傳入指定的參數(shù)。
1)直接針對分組對象,調(diào)用聚合函數(shù)
① 針對df整張表,直接調(diào)用聚合函數(shù)
df = pd.DataFrame({"部門":["A", "A", "B", "B", "C", "C"],
"小組":["g1", "g2", "g1", "g2", "g1", "g2"],
"利潤":[10, 20, 15, 28, 12, 14],
"人員":["a", "b", "c", "d", "e", "f"],
"年齡":[20, 15, 18, 30, 23, 34]})
display(df)
df["利潤"].mean()
df[["年齡","利潤"]].mean()
結(jié)果如下:
② 針對df分組后的對象,直接調(diào)用聚合函數(shù)
df = pd.DataFrame({"部門":["A", "A", "B", "B", "C", "C"],
"小組":["g1", "g2", "g1", "g2", "g1", "g2"],
"利潤":[10, 20, 15, 28, 12, 14],
"人員":["a", "b", "c", "d", "e", "f"],
"年齡":[20, 15, 18, 30, 23, 34]})
display(df)
df.groupby("部門")["利潤"].mean()
df.groupby("部門").mean()
結(jié)果如下:
2)直接針對分組對象,調(diào)用agg()函數(shù)(很重要)
??下面知識的講解,涉及到“聚合函數(shù)字符串”,這是我自己起的名字,類似于"sum"、“mean”、“count”、“max”、“min”,都叫做“聚合函數(shù)字符串”。同時還需要注意一點,agg()函數(shù)中還有一個axis參數(shù),用于指定行、列。
- df.agg(“mean”)
- df.agg([“mean”, “sum”, “max”])
- df.agg({“利潤”:[“mean”, “sum”] , “年齡”:[“max”, “min”]})
- df.agg(lambda x: x.mean())
① 傳入單個聚合函數(shù)字符串
df = pd.DataFrame({"部門":["A", "A", "B", "B"],
"利潤":[10, 20, 15, 28],
"年齡":[20, 15, 18, 30]})
display(df)
df1 = df.groupby("部門").agg("mean")
display(df1)
結(jié)果如下:
② 傳入多個聚合函數(shù)字符串
df = pd.DataFrame({"部門":["A", "A", "B", "B"],
"利潤":[10, 20, 15, 28],
"年齡":[20, 15, 18, 30]})
display(df)
df1 = df.groupby("部門").agg(["sum","mean"])
display(df1)
結(jié)果如下:
③ 傳入一個字典:可以針對不同的列,提供不同的聚合信息。
df = pd.DataFrame({"部門":["A", "A", "B", "B"],
"利潤":[10, 20, 15, 28],
"年齡":[20, 15, 18, 30]})
display(df)
df1 = df.groupby("部門").agg({"利潤":["sum","mean"],"年齡":["max","min"]})
display(df1)
結(jié)果如下:
④ 傳入自定義函數(shù)
df = pd.DataFrame({"部門":["A", "A", "A", "B", "B", "B"],
"利潤":[10, 32, 20, 15, 28, 10],
"銷售量":[20, 15, 33, 18, 30, 22]})
display(df)
df.groupby("部門").agg(lambda x:x.max()-x.min())
結(jié)果如下:
|