Python 分组处理

在日常数据分析时,经常会遇到需要按列分组 (groupby) 的任务,如计算某公司各部门的人数,计算各部门男女平均工资,计算不同年代的员工的平均工资等等。在进行这类运算时,Pandas 提供了 groupby 函数,大多数问题它都可以解决,但有一些问题使用 groupby 函数会略显麻烦,下面我们就这些问题展开细致的讨论。

groupby 是 pandas 中非常重要的一个函数, 主要用于数据分类和聚合计算. 其思想是“split-apply-combine”(拆分 - 应用 - 合并),如下图:

..

分组原理图

一、单列分组聚合

单列分组聚合是指把某一列作为键进行分组,然后对各组进行聚合运算。

它是上述分组原理的最简单应用,比如根据员工信息数据,计算各部门员工数。

问题分析:要计算各部门员工数,首先把部门作为键进行分组,然后对各组成员进行计数。

部分员工信息数据如下:

EID 1 NAME 3 SURNAME GENDER STATE BIRTHDAY HIREDATE DEPT SALARY
1 Rebecca Moore F California 1974/11/20 2005/3/11 R&D 7000
2 Ashley Wilson F New York 1980/7/19 2008/3/16 Finance 11000
3 Rachel Johnson F New Mexico 1970/12/17 2010/12/1 Sales 9000
4 Emily Smith F Texas 1985/3/7 2006/8/15 HR 7000
5 Ashley Smith F Texas 1975/5/13 2004/7/30 R&D 16000

Python代码

import pandas as pd
employee = pd.read_csv("Employees.csv")  //读取数据
dept_emp_num = employee.groupby('DEPT')['DEPT'].count() //分组计数
print(dept_emp_num) 

讨论:groupby(‘DEPT’) 将数据按照部门分组, count() 函数进行计数。

二、多列分组聚合

多列分组聚合是指把多列的值同时作为键进行分组,然后对各组进行聚合运算。

它和单列分组聚合类似,只是分组的键是多列组合而已。如根据员工信息数据,计算各部门男女员工的平均工资。

继续使用上例中的员工信息数据

问题分析:需要分组的键有两个,分别是部门和性别,只要把他们组合起来看作是一个键,然后当做单列分组聚合即可。

Python 代码

import pandas as pdemployee = pd.read_csv("Employees.csv")
dept_gender_salary =   employee.groupby(['DEPT','GENDER'],as_index=False).SALARY.mean() //多列分组再聚合
print(dept_gender_salary) 

讨论:groupby([‘DEPT’,’GENDER’]),分组的两列以列表的形式作为参数,as_index 表示是否把分组列作为索引,True 表示作为索引,这里使用 False 表示不作为索引。使用 mean() 函数计算工资的平均值。

三、根据衍生列分组聚合

根据衍生列分组聚合,是指需要分组的键并不直接在数据中,需要根据数据计算出一列新数据,把它作为键对数据进行分组。如计算不同年代的员工的平均工资。

问题分析:员工信息数据中并没有年代这一列,因此需要根据员工的生日列计算出来,把它作为键对员工数据进行分组,然后再求工资均值。

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) 

讨论:年代数据在原数据中并不存在,使用 np.floor((employee[‘BIRTHDAY’].dt.year-1900)/10) 计算出衍生列表示年代,然后根据他分组并计算平均工资。

四、多个聚合

多个聚合,是指分组后对单列或者多列进行多种聚合。

(一) 多列单聚合

多列单聚合,指同时对多列聚合,但每列使用一种聚合方式。如:同时计算各部门员工的人数,平均工资。

问题分析:求员工人数可以对 EID 计数,求平均工资需要对工资列求均值,两列聚合但每列只用一种聚合方式。

Python 代码

import pandas as pd
employee = pd.read_csv("Employees.csv")
dept_agg =   employee.groupby('DEPT',as_index=False).agg({'EID':'count','SALARY':'mean'}) //分组并对 EID 计数,对 SALARY 求平均
print(dept_agg.rename(columns={'EID':'NUM','SALARY':'AVG_SALARY'})) // 重命名列名 

讨论:Pandas 的 agg()函数可以完成这类任务,各列以及各列的聚合方式以字典的形式作为参数传入 agg(),聚合的列作为字典的键,聚合方式作为字典的值,从而完成聚合运算。

(二) 单列多聚合

单列多聚合,指只对一列聚合,但聚合的方式有多种。如上述问题也可以直接对工资计数并求平均,此时是对工资进行了两种聚合——计数和平均。

Python 代码

import pandas as pd
employee = pd.read_csv("Employees.csv")
dept_agg = employee.groupby('DEPT').SALARY.agg(['count','mean']).reset_index() //对 SALARY 计数并求平均
print(dept_agg.rename(columns={'count':'NUM','mean':'AVG_SALARY'})) //重命名列名

讨论:如果是单列的不同聚合方式,则可以把聚合方式进行组合以列表的形式作为参数传入 agg()。

(三) 多列多聚合

多列多聚合,指对多列聚合同时也包含单列多聚合的组合聚合方式。聚合方式还可以是自己定义的函数,

如:计算各部门员工人数,平均工资和最大年龄。

问题分析:计算员工人数和平均工资,是对工资列计数并求平均(单列多聚合),求最大年龄,需对生日列使用自定义的函数计算出最大年龄。

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 分组,根据 SALARY 计数和求均值,BIRTHDAY 使用 max_age 计算最大年龄
dept_agg.columns   = ['NUM','AVG_SALARY','MAX_AGE'] //修改列名
print(dept_agg.reset_index()) 

讨论:这种情况,聚合列和聚合方式还是按照字典的方式传入,但当某一列需要多种聚合方式时,则需要将其组合,以列表的形式作为字典的值。

五、分组聚合值复制

分组聚合值复制,指把分组聚合的结果转换成与该组等长的列,相当于把聚合的结果复制到该组的所有行。如:为员工信息数据新增一列各部门的平均工资。

问题分析:各部门的平均工资需要按照部门分组再对工资求平均,把平均工资的值添加到对应的组,并保持数据原序。

Python 代码

import pandas as pd
employee = pd.read_csv("Employees.csv")
employee['AVG_SALARY'] =   employee.groupby('DEPT').SALARY.transform('mean') //按照 DEPT 分组并对 SALARY 求平均
print(employee) 

讨论:按照部门分组后,对工资求均值。transform() 函数在组内求聚合值后会按照原索引的顺序返回结果,可以自动按照索引添加结果,从而保证原数据顺序不变。

六、分组子集处理

分组应用:指分组后对各组进行一些非聚合运算。比如分组排序,分组后不再关心聚合的结果,而是关心组内记录的顺序。如:将各部门按照入职时间从早到晚进行排序 。

问题分析:按照部门分组后,不再关心分组后的聚合结果,而是关心员工的入职时间顺序。分组后,对各组进行循环同时对组内成员按照入职时间排序就可以了。

Python 代码

import pandas as pdemployee = 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)//按 DEPT 分组,并对各组按照 HIREDATE 排序,最后重置索引 
print(employee_new) 

讨论:分组后需要对组内成员排序,可以使用 apply()函数结合 lambda 的方式,其中 lambda 表达式是对各组循环,使用 sort_values() 函数在组内部再排序,返回组内排序的结果。

简单的运算使用 lambda 函数计算,但有时会遇到比较复杂的计算,如:计算各部门年龄最大的员工和年龄最小的员工的工资差。

问题分析:首先需按照部门分组,分组后还需要找到年龄最大的员工和年龄最小的员工的记录,然后才能计算工资差。

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'])//计算工资差按 DEPT 分组并使用自定义函数计算
salary_diff = employee.groupby('DEPT').apply(salary_diff)
print(salary_diff) 

讨论:使用 apply()结合自定义函数的方式。其中 apply() 会把分组的结果作为参数传入自定义函数。salary_diff() 函数是自定义函数,g 实质上就是 pandas 的 DataFrame 格式的数据框,这里是分组的结果。对它计算最大年龄和最小年龄的索引后,找到工资字段计算差即得到结果。

思考:

由上述讨论可见,熟练掌握 Pandas 的这些 groupby 方法对我们进行数据分析是特别有帮助的。

下面我们以 stack overflow 网站上的一些实际问题来进一步了解 groupby。

七、按位置分组

按位置分组,指不以某列作为键分组,而是以记录的位置作为键来分组。比如将数据每三行分到相同组或者按照位置分成奇数位置一组,偶数位置一组等。举例如下:

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

数据片段如下:

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

希望每三行分成一组,并把众数作为该组的结果。理想的结果如下:

time a b

2 0.5 -2.0

5 0.1 -1.0

8 0.5 -1.0

问题分析:该问题的分组与现有的列没有关系,只与位置相关,因此需要衍生出一列作为分组依据,按位置做整数乘法即得到衍生列,然后据此分组即可。

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]) //按照衍生列分组,使用 agg 结合 lambda 的方式得到众数,取各组各列的最后 1 个众数作为结果
print(res) 

讨论:衍生列计算方式为 np.arange(len(data)) // 3,其结果是 [0 0 0 1 1 1 2 2 2],把它作为键进行分组就可以把数据分成每三行一组。而 agg(lambda x: x.mode()) 则是将各组的各列分别求众数,如第一组 time 的众数为 [0,1,2] 而 a 和 b 的众数分别是 [0.5] 和[-2.0]分别取最后 1 个众数 iloc[-1]即得到想要的结果。

八、值变化分组

值变化分组,指在有序的数据中,发生数据变化时就分出一个新组。举例如下:

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

数据片段如下:

  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 连续相同时对 duration 进行求和,location 变化时则重新求和。理想结果如下:

duration location user

    15    house    A

     5      gym    A

     4      gym    B

    10     shop    B

    10      gym    B

问题分析:location 列的顺序很重要,连续相同时可以视为一组,当变化时则重新分一组,如 user=B 时,第 4 行 (索引为 3) 的 location 为 [gym,shop,gym,gym], 不可以把其中的 3 个 gym 分到 1 组,而应该把第一个 gym 单独作为 1 组,shop 与 gym 不同,值发生了变化,把 shop 分到下一组,后面两个 gym 没有值变化,可以分到同一组,分组的结果为[[gym],[shop],[gym,gym]],所以这里不可以使用 df.groupby([‘user’,’location’]).duration.sum() 来计算结果,而是要想办法生成一个衍生列作为分组依据。

代码如下:

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() //按照 user,location 和衍生列分组,对 duraton 求和
print(res) 

讨论:衍生列 derive 是当 location 与前者不同时进行累加,得到 [1 1 2 2 3 4 4]。然后按照 user,location 和该数列分组,再对 duration 求和。

九、条件变化分组

条件变化分组:指在有序的数据中,当满足某一条件时重新分组。举例如下:

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

数据片段如下:

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 中间随机取一行

理想结果形式如下:

333_c_132 n06

999_c_133 n12

998_c_134 n18

997_c_135 n36

996_c_136 n18

问题分析:取两个 x 之间的随机一条记录,可以转化成每当 code 等于 x 时开始新的一组,不等于 x 时分组不变,然后从该组中随机取一行。因此这里还是需要生成衍生列,把它作为键分组才能完成任务。

代码如下:

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)) // 根据衍生列分组,使用 apply 结合 lambda 的方式随机抽样
res=res.reset_index(level=0, drop=True)//重置索引
print(res)  

讨论:code.eq(x) 表示 code 等于 x 时为 True,其余为 False,cumsum()表示对其累加,生成的衍生列为 [1 1 1 1 1 1 1 1 1 2 2…],过滤掉等于 x 的列再根据该列进行分组并抽样即可。

思考:

前面所有的例子都是将原集合根据某个条件,将数据划分成若干个子集,且满足以下两点:

1)没有空子集

2)原集合的任何成员都属于且只属于某一个子集

我们称这种划分方式为完全划分。那么有没有不完全划分呢?

来看下面这几个例子

十、对位分组

对位分组,指先罗列出一个基准集合,然后将待分组集合成员的某个属性(字段或表达式)与基准集合成员比较,相同者则分到一个子集中,最后拆分出来的子集数量和基准集合成员数是相同的。对位分组有三个特点:

1)可能出现空子集(比如基准集合的某些成员在待分组集合中并不存在);

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

3)每个成员最多只出现在一个子集中。

(一)出现空子集

公司统计各部门男女人数,如果某个部门没有男员工或者没有女员工,则将该部门的男员工人数或女员工人数填为 0。

问题分析:如果直接按照部门和性别分组,则如果某个部门没有女员工或没有男员工时,该部门将只被分成 1 组,就会丢失掉缺少的性别的统计信息,因此不可以直接 groupby([‘DEPT’,’GENDER’])。很容易想到的方案就是,先按部门分组,罗列出 [男, 女] 的基准集合,使用左连接 (left join) 的方式与各组连接,再对连接后的结果按照性别分组,最后汇总结果,这样就能保证分组的结果总会有 [男, 女] 了。

Python 代码

import pandas as pd
def align_group(g,l,by):     //函数,对位分组
    d = pd.DataFrame(l,columns=[by])    //生成对照的 dataframe
    m =   pd.merge(d,g,on=by,how='left')//利用 merge 完成对位运算
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()))//按 DEPT 分组,再对各组使用函数对位分组,对 EID 进行计数
print(res) 

讨论:

自定义函数 align_group,使用 merge()函数完成罗列集合与待分组集合的 left join,再按 merge 的列进行分组。按部门分组后,使用 apply() 结合 lambda 表达式的方式对每组使用自定义函数对位分组,最后对 EID 列计数得到最终结果。(注意:这里不可以对 GENDER 计数,因为 merge 时 GENDER 的成员都被保留了,如果有空子集时,对它计数结果将是 1,而其他列(比如 EID), 在 left join 时会是空值,所以对 EID 计数结果是 0)。

(二)有待分组集合成员未被分到任何子集

按指定的部门 [‘Administration’, ‘HR’, ‘Marketing’, ‘Sales’] 分组,只查询这几个部门的人数且部门先后顺序保持不变。

问题分析:与出现空子集的情况类似,此时也可以使用 left join 的方式,将不在预先罗列的集合成员排除掉,只保留罗列集合中的成员。

代码如下:

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()) //使用对位分组函数分组,再对 EID 计数
print(res) 

讨论:Pandas 不直接支持对位分组的功能,因此完成起来成本就会比较高,而且使用 merge 函数也会导致运行效率低下。

十一、枚举分组

枚举分组:事先指定一组条件,将待分组集合的成员作为参数计算这批条件,条件成立者被划分到与该条件对应的一个子集中,结果集的子集和事先指定的条件一一对应。枚举分组的特点:允许集合成员重复出现在不同的子集中。

举例如下:

按在公司的工龄将员工分组统计每组的男女员工人数(分组条件重合时,列出所有满足条件的员工,分组的条件是 [工龄 <5 年,5 年 <= 工龄 <10 年,工龄 >=10 年,工龄 >=15 年])

问题分析:工龄 >=10 年和工龄 >=15 年两个条件有重复的区间,即工龄大于 15 年的员工,其工龄也一定大于 10 年,这时如果使用构造衍生列的方式来完成,将无法使同一个成员重复出现在两个分组中,因此需要考虑每个条件都分一次组,然后找出满足条件的组,最后再汇总。

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          //男女员工数为 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)

讨论:EMPLOYED 是根据入职时间 HIREDATE 新增加的一列,表示工龄。自定义函数 eval_g(),是把分组的条件转换成表达式,比如当条件是 s<5 时,eval_g(dd,ss)的表达式就是 emp_info[‘EMPLOYED’]<5,根据这个衍生列来对数据分组。对分组条件进行循环,按该衍生列分成两组,get_group(True) 表示取满足条件的组,最后把所有满足条件的结果使用 concat() 函数汇总。

总结

Python 在进行分组处理时,多数情况可以比较优雅的处理,但在处理有序分组时,如值变化分组、条件变化分组时则需要自己想办法生成满足分组条件的衍生列,略显麻烦。对位分组和枚举分组的两种情况更是糟糕,需要自己想办法去绕,要么使用 merge 运算,要么多次分组,使分组的成本变得很高,这样看来,Pandas 的分组运算还有其局限性。

对于分组运算,相比之下,esProc SPL 处理的更完善。 esProc 是专业的数据计算引擎,SPL 提供了丰富的分组运算,可以方便的完成上述任务,代码风格的一致程度也更好。

两个分组运算函数 groups()和 group(),分别实现分组聚合和分组子集,可以比 Python 更简洁地解决前面六个常规分组问题:

问题 SPL代码 简单说明
A.groups(DEPT;count(~):NUM) A是数据表,按 DEPT 分组,count() 计数
A.groups(DEPT,GENDER;avg(SALARY):AVG_SALARY) 按 DEPT,GENDER 分组,avg() 平均
A.groups((year(BIRTHDAY)-1900)\10:years;avg(SALARY):AVG_SALARY) (year(BIRTHDAY)-1900)\10命名为 years,并分组
A.groups(DEPT;count(EID):NUM,avg(SALARY):AVG_SALARY) 多列单聚合
A.groups(DEPT;count(SALARY):NUM,avg(SALARY):AVG_SALARY) 单列多聚合
A.groups(DEPT;count(SALARY):NUM,avg(SALARY):AVG_SALARY,max(age(BIRTHDAY)):MAX_AVG) 多列多聚合
B=A.derive(AVG_SALARY)>B.group(DEPT).((a=.avg(SALARY),.run(AVG_SALARY=a))) 增加新列修改为分组的聚合值
A.group(DEPT).conj(~.sort(HIREDATE)) 分组排序
A.group(DEPT;(ma=.minp(BIRTHDAY),mi=.maxp(BIRTHDAY),ma.SALARY-mi.SALARY):SALARY_DIF) 分组子集运算

对于这六个简单分组计算,Python 的分组计算方法同样方便。但涉及了很多其他函数,如 agg,transform,apply,lambda 表达式甚至是自定义函数等等,代码风格差别比较大。而 SPL 则基本保持了 groups(x;y) 或者是 group(x).(y) 这样统一的代码风格。

对于问题七、八、九,Python 就略显烦琐,需想办法生成衍生列,而 SPL 本身基于有序集合设计,提供了有序分组的选项,仍可以优雅的保持简单运算时的代码风格。

问题 SPL代码 简单说明
A.groups@n((#-1)\3;y) 每三行分 1 组,y 是聚合运算表达式
A.groups@o(user,location;y) @o选项:值变化分组
A.group@i(code==”x”).(y) @i选项:条件变化分组

根据分组后直接聚合还是分组后针对子集计算,灵活选择 groups 和 group 函数。

最后两个问题,对位分组和枚举分组,确实有点难为 Python 了,不过不管是使用 merge 函数绕还是多次分组,总算是完成了任务。而 SPL 提供了专门的对位分组函数 align()和枚举分组函数 enum(),可以继续优雅。

问题 SPL分组处理 简单说明
s=[“M”,”F”]A.group(DEPT).(~.align@a(s,GENDER).(y)) 可能出现空子集
s=[“Administration”, “HR”, “Marketing”, “Sales”]A.align@a(s,DEPT).(y) 有待分组集合成员未被分到任何子集
十一 c=[“?<5”,”?>=5 && ?<10”,”?>=10”,”?>=15”]A.enum(c, EMPLOYED) 有成员被分到不同子集

需要提到的是,Python 还有一个致命缺点——大数据(无法一次性读入内存)分组,它涉及到外存读写和 hash 分组,对于非专业的程序员来说,使用 Python 完成这个任务几乎是不可能的。有兴趣可以参考以下文章:

Python 如何处理大文件

这里介绍了 Python 处理大数据存在的问题(包括大数据分组),也简单介绍了 esProc SPL 中的游标系统,其中 group 和 groupx() 函数仍然可以优雅的完成大数据分组任务。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!