Python 分組處理

在日常數(shù)據(jù)分析時,經(jīng)常會遇到需要按列分組 (groupby) 的任務(wù),如計算某公司各部門的人數(shù),計算各部門男女平均工資,計算不同年代的員工的平均工資等等。在進行這類運算時,Pandas 提供了 groupby 函數(shù),大多數(shù)問題它都可以解決,但有一些問題使用 groupby 函數(shù)會略顯麻煩,下面我們就這些問題展開細致的討論。

groupby 是 pandas 中非常重要的一個函數(shù), 主要用于數(shù)據(jù)分類和聚合計算. 其思想是“split-apply-combine”(拆分 - 應(yīng)用 - 合并),如下圖:

分組原理圖

一、單列分組聚合

單列分組聚合是指把某一列作為鍵進行分組,然后對各組進行聚合運算。

它是上述分組原理的最簡單應(yīng)用,比如根據(jù)員工信息數(shù)據(jù),計算各部門員工數(shù)。

問題分析:要計算各部門員工數(shù),首先把部門作為鍵進行分組,然后對各組成員進行計數(shù)。

部分員工信息數(shù)據(jù)如下:

EIDNAMESURNAMEGENDERSTATEBIRTHDAYHIREDATEDEPTSALARY

1RebeccaMooreFCalifornia1974/11/202005/3/11R&D7000

2AshleyWilsonFNew York1980/7/192008/3/16Finance11000

3RachelJohnsonFNew ? Mexico1970/12/172010/12/1Sales9000

4EmilySmithFTexas1985/3/72006/8/15HR7000

5AshleySmithFTexas1975/5/132004/7/30R&D16000

………………………

Python代碼

import pandas as ? pd

employee = ? pd.read_csv("Employees.csv")

dept_emp_num = ? employee.groupby('DEPT')['DEPT'].count()

print(dept_emp_num)


讀取數(shù)據(jù)

分組計數(shù)

討論:groupby(‘DEPT’) 將數(shù)據(jù)按照部門分組, count() 函數(shù)進行計數(shù)。

二、多列分組聚合

多列分組聚合是指把多列的值同時作為鍵進行分組,然后對各組進行聚合運算。

它和單列分組聚合類似,只是分組的鍵是多列組合而已。如根據(jù)員工信息數(shù)據(jù),計算各部門男女員工的平均工資。

繼續(xù)使用上例中的員工信息數(shù)據(jù)

問題分析:需要分組的鍵有兩個,分別是部門和性別,只要把他們組合起來看作是一個鍵,然后當做單列分組聚合即可。

Python 代碼

import pandas as pd

employee = pd.read_csv("Employees.csv")

dept_gender_salary = ? employee.groupby(['DEPT','GENDER'],as_index=False).SALARY.mean()

print(dept_gender_salary)



多列分組再聚合

討論:groupby(['DEPT','GENDER']),分組的兩列以列表的形式作為參數(shù),as_index 表示是否把分組列作為索引,True 表示作為索引,這里使用 False 表示不作為索引。使用 mean() 函數(shù)計算工資的平均值。

三、根據(jù)衍生列分組聚合

根據(jù)衍生列分組聚合,是指需要分組的鍵并不直接在數(shù)據(jù)中,需要根據(jù)數(shù)據(jù)計算出一列新數(shù)據(jù),把它作為鍵對數(shù)據(jù)進行分組。如計算不同年代的員工的平均工資。

問題分析:員工信息數(shù)據(jù)中并沒有年代這一列,因此需要根據(jù)員工的生日列計算出來,把它作為鍵對員工數(shù)據(jù)進行分組,然后再求工資均值。

Python 代碼

import pandas as pd

import numpy as np

employee = pd.read_csv("Employees.csv")

employee['BIRTHDAY']=pd.to_datetime(employee['BIRTHDAY'])

years_salary = ? employee.groupby(np.floor((employee['BIRTHDAY'].dt.year-1900)/10)).SALARY.mean()

print(years_salary)




生日列轉(zhuǎn)換成日期格式


計算衍生數(shù)組并按此數(shù)組分組,再計算平均工資

討論:年代數(shù)據(jù)在原數(shù)據(jù)中并不存在,使用 np.floor((employee['BIRTHDAY'].dt.year-1900)/10) 計算出衍生列表示年代,然后根據(jù)他分組并計算平均工資。

四、多個聚合

多個聚合,是指分組后對單列或者多列進行多種聚合。

(一)?? 多列單聚合

多列單聚合,指同時對多列聚合,但每列使用一種聚合方式。如:同時計算各部門員工的人數(shù),平均工資。

問題分析:求員工人數(shù)可以對 EID 計數(shù),求平均工資需要對工資列求均值,兩列聚合但每列只用一種聚合方式。

Python 代碼

import pandas as pd

employee = pd.read_csv("Employees.csv")

dept_agg = ? employee.groupby('DEPT',as_index=False).agg({'EID':'count','SALARY':'mean'})

print(dept_agg.rename(columns={'EID':'NUM','SALARY':'AVG_SALARY'}))



分組并對 EID 計數(shù),對 SALARY 求平均

重命名列名

討論:Pandas 的 agg()函數(shù)可以完成這類任務(wù),各列以及各列的聚合方式以字典的形式作為參數(shù)傳入 agg(),聚合的列作為字典的鍵,聚合方式作為字典的值,從而完成聚合運算。

(二)?? 單列多聚合

單列多聚合,指只對一列聚合,但聚合的方式有多種。如上述問題也可以直接對工資計數(shù)并求平均,此時是對工資進行了兩種聚合——計數(shù)和平均。

Python 代碼

import pandas as ? pd

employee = ? pd.read_csv("Employees.csv")

dept_agg = employee.groupby('DEPT').SALARY.agg(['count','mean']).reset_index()

print(dept_agg.rename(columns={'count':'NUM','mean':'AVG_SALARY'}))



對 SALARY 計數(shù)并求平均

重命名列名

討論:如果是單列的不同聚合方式,則可以把聚合方式進行組合以列表的形式作為參數(shù)傳入 agg()。

(三)?? 多列多聚合

多列多聚合,指對多列聚合同時也包含單列多聚合的組合聚合方式。聚合方式還可以是自己定義的函數(shù),

如:計算各部門員工人數(shù),平均工資和最大年齡。

問題分析:計算員工人數(shù)和平均工資,是對工資列計數(shù)并求平均(單列多聚合),求最大年齡,需對生日列使用自定義的函數(shù)計算出最大年齡。

Python 代碼

import pandas as ? pd

import datetime

def max_age(s):

??? today = datetime. datetime.today().year

??? age = today-s.dt.year

??? return age.max()

employee = pd.read_csv("Employees.csv")

employee['BIRTHDAY']=pd.to_datetime(employee['BIRTHDAY'])

dept_agg = ? employee.groupby('DEPT').agg({'SALARY':['count','mean'],'BIRTHDAY':max_age})




dept_agg.columns ? = ['NUM','AVG_SALARY','MAX_AGE']

print(dept_agg.reset_index())



函數(shù):求最大年齡

年份

求年齡




按 DEPT 分組,根據(jù) SALARY 計數(shù)和求均值,BIRTHDAY 使用 max_age 計算最大年齡

修改列名


討論:這種情況,聚合列和聚合方式還是按照字典的方式傳入,但當某一列需要多種聚合方式時,則需要將其組合,以列表的形式作為字典的值。

五、分組聚合值復(fù)制

分組聚合值復(fù)制,指把分組聚合的結(jié)果轉(zhuǎn)換成與該組等長的列,相當于把聚合的結(jié)果復(fù)制到該組的所有行。如:為員工信息數(shù)據(jù)新增一列各部門的平均工資。

問題分析:各部門的平均工資需要按照部門分組再對工資求平均,把平均工資的值添加到對應(yīng)的組,并保持數(shù)據(jù)原序。

Python 代碼

import pandas as pd

employee = pd.read_csv("Employees.csv")

employee['AVG_SALARY'] = ? employee.groupby('DEPT').SALARY.transform('mean')

print(employee)



按照 DEPT 分組并對 SALARY 求平均

討論:按照部門分組后,對工資求均值。transform() 函數(shù)在組內(nèi)求聚合值后會按照原索引的順序返回結(jié)果,可以自動按照索引添加結(jié)果,從而保證原數(shù)據(jù)順序不變。

六、分組子集處理

分組應(yīng)用:指分組后對各組進行一些非聚合運算。比如分組排序,分組后不再關(guān)心聚合的結(jié)果,而是關(guān)心組內(nèi)記錄的順序。如:將各部門按照入職時間從早到晚進行排序 。

問題分析:按照部門分組后,不再關(guān)心分組后的聚合結(jié)果,而是關(guān)心員工的入職時間順序。分組后,對各組進行循環(huán)同時對組內(nèi)成員按照入職時間排序就可以了。

Python 代碼

import pandas as pd

employee = pd.read_csv("Employees.csv")

employee['HIREDATE']=pd.to_datetime(employee['HIREDATE'])

employee_new = ? employee.groupby('DEPT',as_index=False).apply(lambda ? x:x.sort_values('HIREDATE')).reset_index(drop=True)

print(employee_new)



修改入職時間格式


按 DEPT 分組,并對各組按照 HIREDATE 排序,最后重置索引


討論:分組后需要對組內(nèi)成員排序,可以使用 apply()函數(shù)結(jié)合 lambda 的方式,其中 lambda 表達式是對各組循環(huán),使用 sort_values() 函數(shù)在組內(nèi)部再排序,返回組內(nèi)排序的結(jié)果。

簡單的運算使用 lambda 函數(shù)計算,但有時會遇到比較復(fù)雜的計算,如:計算各部門年齡最大的員工和年齡最小的員工的工資差。

問題分析:首先需按照部門分組,分組后還需要找到年齡最大的員工和年齡最小的員工的記錄,然后才能計算工資差。

Python 代碼

import pandas as pd

def salary_diff(g):

??? max_age = ? g['BIRTHDAY'].idxmin()

??? min_age = ? g['BIRTHDAY'].idxmax()

??? diff = ? g.loc[max_age]['SALARY']-g.loc[min_age]['SALARY']

??? return diff

employee = pd.read_csv("Employees.csv")

employee['BIRTHDAY']=pd.to_datetime(employee['BIRTHDAY'])

salary_diff = employee.groupby('DEPT').apply(salary_diff)

print(salary_diff)


函數(shù):計算各組工資差

年齡最大的索引

年齡最小的索引

計算工資差




按 DEPT 分組并使用自定義函數(shù)計算


討論:使用 apply()結(jié)合自定義函數(shù)的方式。其中 apply() 會把分組的結(jié)果作為參數(shù)傳入自定義函數(shù)。salary_diff() 函數(shù)是自定義函數(shù),g 實質(zhì)上就是 pandas 的 DataFrame 格式的數(shù)據(jù)框,這里是分組的結(jié)果。對它計算最大年齡和最小年齡的索引后,找到工資字段計算差即得到結(jié)果。

思考:

由上述討論可見,熟練掌握 Pandas 的這些 groupby 方法對我們進行數(shù)據(jù)分析是特別有幫助的。


下面我們以 stack overflow 網(wǎng)站上的一些實際問題來進一步了解 groupby。

七、按位置分組

按位置分組,指不以某列作為鍵分組,而是以記錄的位置作為鍵來分組。比如將數(shù)據(jù)每三行分到相同組或者按照位置分成奇數(shù)位置一組,偶數(shù)位置一組等。舉例如下:

source:https://stackoverflow.com/questions/59110612/pandas-groupby-mode-every-n-rows

數(shù)據(jù)片段如下:

time?????????????????????? a?????????????????????? b

0????????????????????????? 0.5??????? ????????????-2.0

1????????????????????????? 0.5??????????????????? -2.0

2????????????????????????? 0.1?????? ?????????????-1.0

3????????????????????????? 0.1??????????????????? -1.0

4????????????????????????? 0.1??????????????????? -1.0

5????????????????? ????????0.5??????????????????? -1.0

6????????????????????????? 0.5??????????????????? -1.0

7???????????????? ?????????0.5??????????????????? -3.0

8????????????????????????? 0.5??????????????????? -1.0

希望每三行分成一組,并把眾數(shù)作為該組的結(jié)果。理想的結(jié)果如下:

time??????????????????? ???a?????????????????????? b

2????????????????????????? 0.5??????????????????? -2.0

5????????????????????????? 0.1??????????????????? -1.0

8????????????????????????? 0.5??????????????????? -1.0

問題分析:該問題的分組與現(xiàn)有的列沒有關(guān)系,只與位置相關(guān),因此需要衍生出一列作為分組依據(jù),按位置做整數(shù)乘法即得到衍生列,然后據(jù)此分組即可。

Python 代碼

import pandas as pd

import numpy as np

data = pd.read_csv("group3.txt",sep='\t')

res = data.groupby(np.arange(len(data)) // ? 3).agg(lambda x: x.mode().iloc[-1])

print(res)




按照衍生列分組,使用 agg 結(jié)合 lambda 的方式得到眾數(shù),取各組各列的最后 1 個眾數(shù)作為結(jié)果

討論:衍生列計算方式為 np.arange(len(data)) // 3,其結(jié)果是 [0 0 0 1 1 1 2 2 2],把它作為鍵進行分組就可以把數(shù)據(jù)分成每三行一組。而 agg(lambda x: x.mode()) 則是將各組的各列分別求眾數(shù),如第一組 time 的眾數(shù)為 [0,1,2] 而 a 和 b 的眾數(shù)分別是 [0.5] 和[-2.0]分別取最后 1 個眾數(shù) iloc[-1]即得到想要的結(jié)果。

八、值變化分組

值變化分組,指在有序的數(shù)據(jù)中,發(fā)生數(shù)據(jù)變化時就分出一個新組。舉例如下:

source:https://stackoverflow.com/questions/41620920/groupby-conditional-sum-of-adjacent-rows-pandas

數(shù)據(jù)片段如下:

????? duration? location? user

0??????? 10??? house??? A

1???????? 5??? house??? A

2???????? 5????? gym??? A

3???????? 4????? gym??? B

4??????? 10???? shop??? B

5???????? 4????? gym??? B

6???????? 6????? gym??? B

按照 user 分組后,各組當 location 連續(xù)相同時對 duration 進行求和,location 變化時則重新求和。理想結(jié)果如下:

? ?duration? location?? user

??????? 15??? house??? A

???????? 5????? gym??? A

???????? 4????? gym??? B

??????? 10???? shop??? B

??????? 10????? gym??? B

問題分析:location 列的順序很重要,連續(xù)相同時可以視為一組,當變化時則重新分一組,如 user=B 時,第 4 行 (索引為 3) 的 location 為 [gym,shop,gym,gym], 不可以把其中的 3 個 gym 分到 1 組,而應(yīng)該把第一個 gym 單獨作為 1 組,shop 與 gym 不同,值發(fā)生了變化,把 shop 分到下一組,后面兩個 gym 沒有值變化,可以分到同一組,分組的結(jié)果為[[gym],[shop],[gym,gym]],所以這里不可以使用 df.groupby(['user','location']).duration.sum() 來計算結(jié)果,而是要想辦法生成一個衍生列作為分組依據(jù)。

代碼如下:

import pandas as pd

df = pd.DataFrame({'user' : ['A', 'A', 'A', 'B', 'B', ? 'B','B'],

????????????? ? 'location' : ['house','house','gym','gym','shop','gym','gym'],

????????????? ? 'duration':[10,5,5,4,10,4,6]})

derive = (df.location != ? df.location.shift()).cumsum()

res = df.groupby(['user', 'location', derive], ? as_index=False, sort=False)['duration'].sum()

print(res)


生成數(shù)據(jù)




創(chuàng)造衍生列

按照 user,location 和衍生列分組,對 duraton 求和


討論:衍生列 derive 是當 location 與前者不同時進行累加,得到 [1 1 2 2 3 4 4]。然后按照 user,location 和該數(shù)列分組,再對 duration 求和。

九、條件變化分組

條件變化分組:指在有序的數(shù)據(jù)中,當滿足某一條件時重新分組。舉例如下:

source:https://stackoverflow.com/questions/62461647/choose-random-rows-in-pandas-datafram

數(shù)據(jù)片段如下:

ID????????? code

333_c_132?? x

333_c_132?? n06

333_c_132?? n36

333_c_132?? n60

333_c_132?? n72

333_c_132?? n84

333_c_132?? n96

333_c_132?? n108

333_c_132?? n120

999_c_133?? x

999_c_133?? n06

999_c_133?? n12

999_c_133?? n24

998_c_134?? x

998_c_134?? n06

998_c_134?? n12

998_c_134?? n18

998_c_134?? n36

997_c_135?? x

997_c_135?? n06

997_c_135?? n12

997_c_135?? n24

997_c_135?? n36

996_c_136?? x

996_c_136?? n06

996_c_136?? n12

996_c_136?? n18

996_c_136?? n24

996_c_136?? n36

995_c_137?? x

希望從 code 列的每兩個 x 中間隨機取一行

理想結(jié)果形式如下:

333_c_132?? n06

999_c_133?? n12

998_c_134?? n18

997_c_135?? n36

996_c_136?? n18

問題分析:取兩個 x 之間的隨機一條記錄,可以轉(zhuǎn)化成每當 code 等于 x 時開始新的一組,不等于 x 時分組不變,然后從該組中隨機取一行。因此這里還是需要生成衍生列,把它作為鍵分組才能完成任務(wù)。

代碼如下:

import pandas as pd

df = pd.read_csv("data.txt")

derive = df.code.eq('x').cumsum()

res=df[df.code.ne('x')].groupby(derive).apply(lambda ? x : x.sample(1))

res=res.reset_index(level=0, drop=True)

print(res)?



生成衍生列

根據(jù)衍生列分組,使用 apply 結(jié)合 lambda 的方式隨機抽樣

重置索引


討論:code.eq(x) 表示 code 等于 x 時為 True,其余為 False,cumsum()表示對其累加,生成的衍生列為 [1 1 1 1 1 1 1 1 1 2 2…],過濾掉等于 x 的列再根據(jù)該列進行分組并抽樣即可。

思考:

前面所有的例子都是將原集合根據(jù)某個條件,將數(shù)據(jù)劃分成若干個子集,且滿足以下兩點:

1)沒有空子集

2)原集合的任何成員都屬于且只屬于某一個子集

我們稱這種劃分方式為完全劃分。那么有沒有不完全劃分呢?

來看下面這幾個例子

十、對位分組

對位分組,指先羅列出一個基準集合,然后將待分組集合成員的某個屬性(字段或表達式)與基準集合成員比較,相同者則分到一個子集中,最后拆分出來的子集數(shù)量和基準集合成員數(shù)是相同的。對位分組有三個特點:

1)可能出現(xiàn)空子集(比如基準集合的某些成員在待分組集合中并不存在);

2)可能有待分組集合成員未被分到任何子集(比如有些不重要的成員未被列入基準集合);

3)每個成員最多只出現(xiàn)在一個子集中。

(一)出現(xiàn)空子集

公司統(tǒng)計各部門男女人數(shù),如果某個部門沒有男員工或者沒有女員工,則將該部門的男員工人數(shù)或女員工人數(shù)填為 0。

問題分析:如果直接按照部門和性別分組,則如果某個部門沒有女員工或沒有男員工時,該部門將只被分成 1 組,就會丟失掉缺少的性別的統(tǒng)計信息,因此不可以直接 groupby([‘DEPT’,’GENDER’])。很容易想到的方案就是,先按部門分組,羅列出 [男, 女] 的基準集合,使用左連接 (left join) 的方式與各組連接,再對連接后的結(jié)果按照性別分組,最后匯總結(jié)果,這樣就能保證分組的結(jié)果總會有 [男, 女] 了。

Python 代碼

import pandas as pd

def align_group(g,l,by):

? ??d = pd.DataFrame(l,columns=[by])

??? m = ? pd.merge(d,g,on=by,how='left')

return m.groupby(by,sort=False)

employee = pd.read_csv("Employees.csv")

l = ['M','F']

res = employee.groupby('DEPT').apply(lambda ? x:align_group(x, l, 'GENDER').apply(lambda s:s.EID.count()))

print(res)


函數(shù),對位分組

生成對照的 dataframe

利用 merge 完成對位運算

分組


指定序列

按 DEPT 分組,再對各組使用函數(shù)對位分組,對 EID 進行計數(shù)


討論:

自定義函數(shù) align_group,使用 merge()函數(shù)完成羅列集合與待分組集合的 left join,再按 merge 的列進行分組。按部門分組后,使用 apply() 結(jié)合 lambda 表達式的方式對每組使用自定義函數(shù)對位分組,最后對 EID 列計數(shù)得到最終結(jié)果。(注意:這里不可以對 GENDER 計數(shù),因為 merge 時 GENDER 的成員都被保留了,如果有空子集時,對它計數(shù)結(jié)果將是 1,而其他列(比如 EID), 在 left join 時會是空值,所以對 EID 計數(shù)結(jié)果是 0)。

(二)有待分組集合成員未被分到任何子集

按指定的部門 ['Administration', 'HR', 'Marketing', 'Sales'] 分組,只查詢這幾個部門的人數(shù)且部門先后順序保持不變。

問題分析:與出現(xiàn)空子集的情況類似,此時也可以使用 left join 的方式,將不在預(yù)先羅列的集合成員排除掉,只保留羅列集合中的成員。

代碼如下:

import pandas as pd

def align_group(g,l,by):

??? d = ? pd.DataFrame(l,columns=[by])

??? m = ? pd.merge(d,g,on=by,how='left')

??? return ? m.groupby(by,sort=False)

employee = pd.read_csv("Employees.csv")

sub_dept = ['Administration', 'HR', 'Marketing', ? 'Sales']

res = ? align_group(employee,sub_dept,'DEPT').apply(lambda x:x.EID.count())

print(res)


函數(shù),對位分組





指定順序的部門子集

使用對位分組函數(shù)分組,再對 EID 計數(shù)

討論:Pandas 不直接支持對位分組的功能,因此完成起來成本就會比較高,而且使用 merge 函數(shù)也會導致運行效率低下。

十一、枚舉分組

枚舉分組:事先指定一組條件,將待分組集合的成員作為參數(shù)計算這批條件,條件成立者被劃分到與該條件對應(yīng)的一個子集中,結(jié)果集的子集和事先指定的條件一一對應(yīng)。枚舉分組的特點:允許集合成員重復(fù)出現(xiàn)在不同的子集中。

舉例如下:

按在公司的工齡將員工分組統(tǒng)計每組的男女員工人數(shù)(分組條件重合時,列出所有滿足條件的員工,分組的條件是 [工齡 <5 年,5 年 <= 工齡 <10 年,工齡 >=10 年,工齡 >=15 年])

問題分析:工齡 >=10 年和工齡 >=15 年兩個條件有重復(fù)的區(qū)間,即工齡大于 15 年的員工,其工齡也一定大于 10 年,這時如果使用構(gòu)造衍生列的方式來完成,將無法使同一個成員重復(fù)出現(xiàn)在兩個分組中,因此需要考慮每個條件都分一次組,然后找出滿足條件的組,最后再匯總。

import pandas as pd

import datetime

def eval_g(dd:dict,ss:str):

??? return ? eval(ss,dd)???

emp_file = 'E:\\txt\\employee.txt'

emp_info = pd.read_csv(emp_file,sep='\t')

employed_list = ['Within five years','Five to ten ? years','More than ten years','Over fifteen years']

employed_str_list = ? ["(s<5)","(s>=5) & ? (s<10)","(s>=10)","(s>=15)"]

today = datetime.datetime.today().year

arr = pd.to_datetime(emp_info['HIREDATE'])

employed = today-arr.dt.year

emp_info['EMPLOYED']=employed

dd = {'s':emp_info['EMPLOYED']}

group_cond = []

for n in range(len(employed_str_list)):

??? emp_g = ? emp_info.groupby(eval_g(dd,employed_str_list[n]))

??? emp_g_index ? = [index for index in emp_g.size().index]

??? if True not ? in emp_g_index:

??????? ? female_emp=0

??????? ? male_emp=0

??? else:

??????? group = ? emp_g.get_group(True)

??????? sum_emp ? = len(group)

??????? ? female_emp = len(group[group['GENDER']=='F'])

??????? ? male_emp = sum_emp-female_emp

??? ? group_cond.append([employed_list[n],male_emp,female_emp])

group_df = ? pd.DataFrame(group_cond,columns=['EMPLOYED','MALE','FEMALE'])

print(group_df)



函數(shù),字符串轉(zhuǎn)表達式






分組條件




計算入職時間




循環(huán)分組條件

按分組條件分組

分組索引

如果沒有滿足條件的成員

男女員工數(shù)為 0


滿足條件

獲取分組

計算男女員工人數(shù)





匯總各個分組條件的計算結(jié)果

討論:EMPLOYED 是根據(jù)入職時間 HIREDATE 新增加的一列,表示工齡。自定義函數(shù) eval_g(),是把分組的條件轉(zhuǎn)換成表達式,比如當條件是 s<5 時,eval_g(dd,ss)的表達式就是 emp_info['EMPLOYED']<5,根據(jù)這個衍生列來對數(shù)據(jù)分組。對分組條件進行循環(huán),按該衍生列分成兩組,get_group(True) 表示取滿足條件的組,最后把所有滿足條件的結(jié)果使用 concat() 函數(shù)匯總。

總結(jié)

Python 在進行分組處理時,多數(shù)情況可以比較優(yōu)雅的處理,但在處理有序分組時,如值變化分組、條件變化分組時則需要自己想辦法生成滿足分組條件的衍生列,略顯麻煩。對位分組和枚舉分組的兩種情況更是糟糕,需要自己想辦法去繞,要么使用 merge 運算,要么多次分組,使分組的成本變得很高,這樣看來,Pandas 的分組運算還有其局限性。

對于分組運算,相比之下,esProc SPL 處理的更完善。 esProc 是專業(yè)的數(shù)據(jù)計算引擎,SPL 提供了豐富的分組運算,可以方便的完成上述任務(wù),代碼風格的一致程度也更好。

兩個分組運算函數(shù) groups()和 group(),分別實現(xiàn)分組聚合和分組子集,可以比 Python 更簡潔地解決前面六個常規(guī)分組問題:

分組子集運算

對于這六個簡單分組計算,Python 的分組計算方法同樣方便。但涉及了很多其他函數(shù),如 agg,transform,apply,lambda 表達式甚至是自定義函數(shù)等等,代碼風格差別比較大。而 SPL 則基本保持了 groups(x;y) 或者是 group(x).(y) 這樣統(tǒng)一的代碼風格。

對于問題七、八、九,Python 就略顯煩瑣,需想辦法生成衍生列,而 SPL 本身基于有序集合設(shè)計,提供了有序分組的選項,仍可以優(yōu)雅的保持簡單運算時的代碼風格。

問題SPL代碼簡單說明

根據(jù)分組后直接聚合還是分組后針對子集計算,靈活選擇 groups 和 group 函數(shù)。

最后兩個問題,對位分組和枚舉分組,確實有點難為 Python 了,不過不管是使用 merge 函數(shù)繞還是多次分組,總算是完成了任務(wù)。而 SPL 提供了專門的對位分組函數(shù) align()和枚舉分組函數(shù) enum(),可以繼續(xù)優(yōu)雅。


有成員被分到不同子集

需要提到的是,Python 還有一個致命缺點——大數(shù)據(jù)(無法一次性讀入內(nèi)存)分組,它涉及到外存讀寫和 hash 分組,對于非專業(yè)的程序員來說,使用 Python 完成這個任務(wù)幾乎是不可能的。有興趣可以參考以下文章:

Python 如何處理大文件

這里介紹了 Python 處理大數(shù)據(jù)存在的問題(包括大數(shù)據(jù)分組),也簡單介紹了 esProc SPL 中的游標系統(tǒng),其中 group 和 groupx() 函數(shù)仍然可以優(yōu)雅的完成大數(shù)據(jù)分組任務(wù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 幾乎所有的程序語言都能處理數(shù)據(jù),但有些過于通用,缺乏專業(yè)的結(jié)構(gòu)化計算函數(shù),用于數(shù)據(jù)處理時代碼比較繁瑣,比如C++、...
    心宇gxy閱讀 535評論 0 1
  • 職場人員使用 Excel 進行數(shù)據(jù)處理已經(jīng)成為家常便飯。不過相信大家一定有過很無助的情況,比如復(fù)雜計算、重復(fù)計算、...
    西柚學報表閱讀 621評論 1 6
  • 職場人員使用 Excel 進行數(shù)據(jù)處理已經(jīng)成為家常便飯。不過相信大家一定有過很無助的情況,比如復(fù)雜計算、重復(fù)計算、...
    心宇gxy閱讀 1,180評論 1 10
  • 職場人員使用 Excel 進行數(shù)據(jù)處理已經(jīng)成為家常便飯。不過相信大家一定有過很無助的情況,比如復(fù)雜計算、重復(fù)計算、...
    心宇gxy閱讀 336評論 0 1
  • 1.添加Age、Fullname字段 esproc: A4:我們用T表示序表。T.derive()表示增加字段。這...
    小黃鴨呀閱讀 432評論 0 0

友情鏈接更多精彩內(nèi)容