pyhton-聚合分组操作grouby
pyhton-聚合操作
#将t按照用户id进行分组,然后统计所有用户收取的优惠券数目,并初始化一个索引值t = t.groupby('user_id').agg('sum').reset_index()#以User_id,Date_received分组, 组内的数据都用冒号连接t2 = t2.groupby(['User_id','Coupon_id'])['Date_received'].agg(lambda x:':'.join(x)).reset_index()
#for dataset3t = dataset3[['User_id']]#增加一列t['this_month_user_receive_all_coupon_count'] = 1t.head()#重建索引,聚合,分组求和t = t.groupby('User_id').agg('sum').reset_index()t.head()#1.2 对以下字段分别剔除缺失值和0值后进行groupby countcolumns = [ 'deposit_cur_balabce' #存款当前余额,'financial_cur_balabce' #理财当前余额,'loan_cur_balabce' #贷款当前金额,'own_products_sum' #持有产品数]#循环取这几列的数据for i in columns: temp = df_crm[[i]+['cust_isn','last_etl_acg_dt']].dropna()# 不等于0 temp = temp.loc[temp[i]!=0,:] temp = temp.groupby(['cust_isn','last_etl_acg_dt'],as_index=False).count()#拼接字段 temp.columns = ['cust_isn','last_etl_acg_dt']+['crm_count_'+i] fea_crm = pd.merge(fea_crm,temp,on = ['cust_isn','last_etl_acg_dt'],how = 'left')
处理距离数据
显示商品销量和距离的关系t4 = merchant3[(merchant3.date != 'null')&(merchant3.coupon_id != 'null')][['merchant_id','distance']]#把数据中的null值全部替换为-1t4.replace('null',-1,inplace=True)t4.distance = t4.distance.astype('int')#再把数据中的-1全部替换为NaNt4.replace(-1,np.nan,inplace=True)#返回用户离商品的距离最小值t5 = t4.groupby('merchant_id').agg('min').reset_index()t5.rename(columns={'distance':'merchant_min_distance'},inplace = True)#返回用户离商品的距离最大值t6 = t4.groupby('merchant_id').agg('max').reset_index()t6.rename(columns={'distance':'merchant_max_distance'},inplace = True)#print(t6)#返回距离的平均值t7 = t4.groupby('merchant_id').agg('mean').reset_index()t7.rename(columns = {'distance':'merchant_mean_distance'},inplace= True)#返回距离的中位值t8 = t4.groupby('merchant_id').agg('median').reset_index()t8.rename(columns={'distance':'merchant_median_distance'},inplace = True)
聚合求均值
Data Aggregation and Group Operations计算分组摘要统计,如计数、平均值、标准差,或⽤户⾃定# 义函数。# 计算分组的概述统计,⽐如数量、平均值或标准差,或是⽤# 户定义的函数。# 应⽤组内转换或其他运算,如规格化、线性回归、排名或选# 取⼦集等。# 计算透视表或交叉表。# 执⾏分位数分析以及其它统计分组分析。# 第10章 数据聚合与分组运算# 计算分组摘要统计,如计数、平均值、标准差,或⽤户⾃定# 义函数。# 计算分组的概述统计,⽐如数量、平均值或标准差,或是⽤# 户定义的函数。# 应⽤组内转换或其他运算,如规格化、线性回归、排名或选# 取⼦集等。# 计算透视表或交叉表。# 执⾏分位数分析以及其它统计分组分析。import numpy as npimport pandas as pdPREVIOUS_MAX_ROWS = pd.options.display.max_rowspd.options.display.max_rows = 20np.random.seed(12345)import matplotlib.pyplot as pltplt.rc('figure', figsize=(10, 6))np.set_printoptions(precision=4, suppress=True)GroupBy Mechanics# GroupBy机制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)})dfkey1 key2 data1 data20 a one -0.204708 1.3934061 a two 0.478943 0.0929082 b one -0.519439 0.2817463 b two -0.555730 0.7690234 a one 1.965781 1.246435grouped = df['data1'].groupby(df['key1'])grouped.head()0 -0.2047081 0.4789432 -0.5194393 -0.5557304 1.965781Name: data1, dtype: float64# 调⽤GroupBy的mean⽅法来计算分组平均值:grouped.mean()key1a 0.746672b -0.537585Name: data1, dtype: float64# ⼊多个数组的列表,就会得到不同的结果: 求取平均值means = df['data1'].groupby([df['key1'], df['key2']]).mean()meanskey1 key2a one 0.880536 two 0.478943b one -0.519439 two -0.555730Name: data1, dtype: float64 透视图# 这⾥,我通过两个键对数据进⾏了分组,得到的Series具有⼀个# 层次化索引(由唯⼀的键对组成): 透视图means.unstack()states = np.array(['Ohio', 'California', 'California', 'Ohio', 'Ohio'])years = np.array([2005, 2005, 2006, 2005, 2006])df['data1'].groupby([states, years]).mean()California 2005 0.478943 2006 -0.519439Ohio 2005 -0.380219 2006 1.965781Name: data1, dtype: float64df.groupby('key1').mean()df.groupby(['key1', 'key2']).mean()data1 data2key1 key2 a one 0.880536 1.319920two 0.478943 0.092908b one -0.519439 0.281746two -0.555730 0.769023df.groupby(['key1', 'key2']).size()key1 key2a one 2 two 1b one 1 two 1dtype:
Iterating Over Groups¶# 对分组进⾏迭代# GroupBy对象⽀持迭代,可以产⽣⼀组⼆元元组(由分组名和数# 据块组成)。看下⾯的例⼦:for name, group in df.groupby('key1'): print(name) print(group)a key1 key2 data1 data20 a one -0.204708 1.3934061 a two 0.478943 0.0929084 a one 1.965781 1.246435b key1 key2 data1 data22 b one -0.519439 0.2817463 b two -0.555730 0.769023对于多重键的情况,元组的第⼀个元素将会是由键值组成的元# 382# 组:# 对于多重键的情况,元组的第⼀个元素将会是由键值组成的元# 382# 组:for (k1, k2), group in df.groupby(['key1', 'key2']): print((k1, k2)) print(group)('a', 'one') key1 key2 data1 data20 a one -0.204708 1.3934064 a one 1.965781 1.246435('a', 'two') key1 key2 data1 data21 a two 0.478943 0.092908('b', 'one') key1 key2 data1 data22 b one -0.519439 0.281746('b', 'two') key1 key2 data1 data23 b two -0.55573 0.769023pieces = dict(list(df.groupby('key1')))pieces['b']key1 key2 data1 data22 b one -0.519439 0.2817463 b two -0.555730 0.769023df.dtypesgrouped = df.groupby(df.dtypes, axis=1)# 可以如下打印分组:for dtype, group in grouped: print(dtype) print(group)a0 -0.2047081 0.4789434 1.965781Name: data1, dtype: float64b2 -0.5194393 -0.555730Name: data1, dtype: float64Selecting a Column or Subset of Columnsdf.groupby('key1')['data1'] df.groupby('key1')[['data2']]df['data1'].groupby(df['key1']) df[['data2']].groupby(df['key1'])选取⼀列或列的⼦集# 对于由DataFrame产⽣的GroupBy对象,如果⽤⼀个(单个字符# 串)或⼀组(字符串数组)列名对其进⾏索引,就能实现选取部# 分列进⾏聚合的⽬的。也就是说:# 选取⼀列或列的⼦集# 对于由DataFrame产⽣的GroupBy对象,如果⽤⼀个(单个字符# 串)或⼀组(字符串数组)列名对其进⾏索引,就能实现选取部# 分列进⾏聚合的⽬的。也就是说:df.groupby(['key1', 'key2'])[['data2']].mean()data2key1 key2 a one 1.319920two 0.092908b one 0.281746two 0.769023尤其对于⼤数据集,很可能只需要对部分列进⾏聚合。例如,在# 前⾯那个数据集中,如果只需计算data2列的平均值并以# DataFrame形式得到结果,可以这样写:# 尤其对于⼤数据集,很可能只需要对部分列进⾏聚合。例如,在# 前⾯那个数据集中,如果只需计算data2列的平均值并以# DataFrame形式得到结果,可以这样写:s_grouped = df.groupby(['key1', 'key2'])['data2']s_groupeds_grouped.mean()key1 key2a one 1.319920 two 0.092908b one 0.281746 two 0.769023Name: data2, dtype: float64Grouping with Dicts and Series2# 通过字典或Series进⾏分组# 除数组以外,分组信息还可以其他形式存在。来看另⼀个示例# DataFrame:people = pd.DataFrame(np.random.randn(5, 5), columns=['a', 'b', 'c', 'd', 'e'], index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'])people.iloc[2:3, [1, 2]] = np.nan # Add a few NA valuespeoplea b c d eJoe 0.862580 -0.010032 0.050009 0.670216 0.852965Steve -0.955869 -0.023493 -2.304234 -0.652469 -1.218302Wes -1.332610 NaN NaN 0.690002 1.001543Jim -0.503087 -0.622274 -0.921169 -0.726213 0.222896Travis 0.051316 -1.157719 0.816707 0.433610 1.010737# 现在,假设已知列的分组关系,并希望根据分组计算列的和:mapping = {'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'blue', 'e': 'red', 'f' : 'orange'}# 通过映射分组by_column = people.groupby(mapping, axis=1)by_column.sum()blue redJoe 0.720225 1.705513Steve -2.956703 -2.197664Wes 0.690002 -0.331066Jim -1.647382 -0.902466Travis 1.250317 -0.095666map_series = pd.Series(mapping)map_seriespeople.groupby(map_series, axis=1).count()blue redJoe 2 3Steve 2 3Wes 1 2Jim 2 3Travis 2 3Grouping with Functions#groupby 统计 计数date_count = data[['cust_isn','last_etl_acg_dt']].groupby('last_etl_acg_dt',as_index=False).count()# Series也有同样的功能,它可以被看做⼀个固定⼤⼩的映射:# 通过函数进⾏分组# ⽐起使⽤字典或Series,使⽤Python函数是⼀种更原⽣的⽅法定# 义分组映射。任何被当做分组键的函数都会在各个索引值上被调# ⽤⼀次,其返回值就会被⽤作分组名称。具体点说,以上⼀⼩节# 的示例DataFrame为例,其索引值为⼈的名字。你可以计算⼀个# 字符串⻓度的数组,更简单的⽅法是传⼊len函数:people.groupby(len).sum()a b c d e3 -0.973117 -0.632306 -0.871159 0.634004 2.0774045 -0.955869 -0.023493 -2.304234 -0.652469 -1.2183026 0.051316 -1.157719 0.816707 0.433610 1.010737key_list = ['one', 'one', 'one', 'two', 'two']people.groupby([len, key_list]).min()a b c d e3 one -1.332610 -0.010032 0.050009 0.670216 0.852965two -0.503087 -0.622274 -0.921169 -0.726213 0.2228965 one -0.955869 -0.023493 -2.304234 -0.652469 -1.2183026 two 0.051316 -1.157719 0.816707 0.433610 1.010737Grouping by Index Levels根据索引级别分组# 层次化索引数据集最⽅便的地⽅就在于它能够根据轴索引的⼀个# 级别进⾏聚合:# 根据索引级别分组# 层次化索引数据集最⽅便的地⽅就在于它能够根据轴索引的⼀个# 级别进⾏聚合:columns = pd.MultiIndex.from_arrays([['US', 'US', 'US', 'JP', 'JP'], [1, 3, 5, 1, 3]], names=['cty', 'tenor'])hier_df = pd.DataFrame(np.random.randn(4, 5), columns=columns)hier_dfcty US JPtenor 1 3 5 1 30 -0.036264 1.095390 0.980928 -0.589488 1.5817001 -0.528735 0.457002 0.929969 -1.569271 -1.0224872 -0.402827 0.220487 -0.193401 0.669158 -1.6489853 -2.252797 -1.166832 0.353607 0.702110 -0.274569# 要根据级别分组,使⽤level关键字传递级别序号或名字:hier_df.groupby(level='cty', axis=1).count()cty JP US0 2 31 2 32 2 33 2 3
聚合操作与apply应用
Data Aggregation# 10.2 数据聚合# 聚合指的是任何能够从数组产⽣标量值的数据转换过程。之前的# 例⼦已经⽤过⼀些,⽐如mean、count、min以及sum等。你可# 能想知道在GroupBy对象上调⽤mean()时究竟发⽣了什么。许多# 常⻅的聚合运算(如表10-1所示)都有进⾏优化。然⽽,除了这# 些⽅法,你还可以使⽤其它的。# 例如,quantile可以计算Series或DataFrame389# 列的样本分位数。dfgrouped = df.groupby('key1')grouped['data1'].quantile(0.9)key1a 1.668413b -0.523068Name: data1, dtype: float64如果要使⽤你⾃⼰的聚合函数,只需将其传⼊aggregate或agg⽅# 法即可: 使用自己的聚合函数# 如果要使⽤你⾃⼰的聚合函数,只需将其传⼊aggregate或agg⽅# 法即可: 使用自己的聚合函数def peak_to_peak(arr): return arr.max() - arr.min()grouped.agg(peak_to_peak)grouped.describe()Column-Wise and Multiple Function Application⾯向列的多函数应⽤# 回到前⾯⼩费的例⼦。使⽤read_csv导⼊数据之后,我们添加了# ⼀个⼩费百分⽐的列tip_pct:# ⾯向列的多函数应⽤# 回到前⾯⼩费的例⼦。使⽤read_csv导⼊数据之后,我们添加了# ⼀个⼩费百分⽐的列tip_pct:tips = pd.read_csv('examples/tips.csv')# Add tip percentage of total billtips['tip_pct'] = tips['tip'] / tips['total_bill']tips[:6]total_bill tip smoker day time size tip_pct0 16.99 1.01 No Sun Dinner 2 0.0594471 10.34 1.66 No Sun Dinner 3 0.1605422 21.01 3.50 No Sun Dinner 3 0.1665873 23.68 3.31 No Sun Dinner 2 0.1397804 24.59 3.61 No Sun Dinner 4 0.1468085 25.29 4.71 No Sun Dinner 4 0.186240# 你已经看到,对Series或DataFrame列的聚合运算其实就是使⽤# aggregate(使⽤⾃定义函数)或调⽤诸如mean、std之类的⽅# 法。然⽽,你可能希望对不同的列使⽤不同的聚合函数,或⼀次# 应⽤多个函数。其实这也好办,我将通过⼀些示例来进⾏讲解。# ⾸先,我根据天和smoker对tips进⾏分组:grouped = tips.groupby(['day', 'smoker'])grouped_pct = grouped['tip_pct']grouped_pct.agg('mean')day smokerFri No 0.151650 Yes 0.174783Sat No 0.158048 Yes 0.147906Sun No 0.160113 Yes 0.187250Thur No 0.160298 Yes 0.163863Name: tip_pct, dtype: float64# 如果传⼊⼀组函数或函数名,得到的DataFrame的列就会以相应# 的函数命名:grouped_pct.agg(['mean', 'std', peak_to_peak])---------------------------------------------------------------------------NameError Traceback (most recent call last) in () 1 # 如果传⼊⼀组函数或函数名,得到的DataFrame的列就会以相应 2 # 的函数命名:----> 3 grouped_pct.agg(['mean', 'std', peak_to_peak])NameError: name 'peak_to_peak' is not defined你并⾮⼀定要接受GroupBy⾃动给出的那些列名,特别是lambda# 函数,它们的名称是'',这样的辨识度就很低了(通过# 函数的name属性看看就知道了)。因此,如果传⼊的是⼀个由# (name,function)元组组成的列表,则各元组的第⼀个元素就会被# ⽤作DataFrame的列名(可以将这种⼆元元组列表看做⼀个有序# 映射):# 你并⾮⼀定要接受GroupBy⾃动给出的那些列名,特别是lambda# 函数,它们的名称是'',这样的辨识度就很低了(通过# 函数的name属性看看就知道了)。因此,如果传⼊的是⼀个由# (name,function)元组组成的列表,则各元组的第⼀个元素就会被# ⽤作DataFrame的列名(可以将这种⼆元元组列表看做⼀个有序# 映射):grouped_pct.agg([('foo', 'mean'), ('bar', np.std)])foo barday smoker Fri No 0.151650 0.028123Yes 0.174783 0.051293Sat No 0.158048 0.039767Yes 0.147906 0.061375Sun No 0.160113 0.042347Yes 0.187250 0.154134Thur No 0.160298 0.038774Yes 0.163863 0.039389对于DataFrame,你还有更多选择,你可以定义⼀组应⽤于全部# 列的⼀组函数,或不同的列应⽤不同的函数。假设我们想要对# tip_pct和total_bill列计算三个统计信息:# 对于DataFrame,你还有更多选择,你可以定义⼀组应⽤于全部# 列的⼀组函数,或不同的列应⽤不同的函数。假设我们想要对# tip_pct和total_bill列计算三个统计信息:functions = ['count', 'mean', 'max']result = grouped['tip_pct', 'total_bill'].agg(functions)resulttip_pct total_billcount mean max count mean maxday smoker Fri No 4 0.151650 0.187735 4 18.420000 22.75Yes 15 0.174783 0.263480 15 16.813333 40.17Sat No 45 0.158048 0.291990 45 19.661778 48.33Yes 42 0.147906 0.325733 42 21.276667 50.81Sun No 57 0.160113 0.252672 57 20.506667 48.17Yes 19 0.187250 0.710345 19 24.120000 45.35Thur No 45 0.160298 0.266312 45 17.113111 41.19Yes 17 0.163863 0.241255 17 19.190588 43.11result['tip_pct']ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)]grouped['tip_pct', 'total_bill'].agg(ftuples)现在,假设你想要对⼀个列或不同的列应⽤不同的函数。具体的# 办法是向agg传⼊⼀个从列名映射到函数的字典:# 现在,假设你想要对⼀个列或不同的列应⽤不同的函数。具体的# 办法是向agg传⼊⼀个从列名映射到函数的字典:grouped.agg({'tip' : np.max, 'size' : 'sum'})grouped.agg({'tip_pct' : ['min', 'max', 'mean', 'std'], 'size' : 'sum'})tip_pct sizemin max mean std sumday smoker Fri No 0.120385 0.187735 0.151650 0.028123 9Yes 0.103555 0.263480 0.174783 0.051293 31Sat No 0.056797 0.291990 0.158048 0.039767 115Yes 0.035638 0.325733 0.147906 0.061375 104Sun No 0.059447 0.252672 0.160113 0.042347 167Yes 0.065660 0.710345 0.187250 0.154134 49Thur No 0.072961 0.266312 0.160298 0.038774 112Yes 0.090014 0.241255 0.163863 0.039389 40Returning Aggregated Data Without Row Indexes以“没有⾏索引”的形式返回聚合数据# 到⽬前为⽌,所有示例中的聚合数据都有由唯⼀的分组键组成的# 索引(可能还是层次化的)。由于并不总是需要如此,所以你可# 以向groupby传⼊as_index=False以禁⽤该功能:# 以“没有⾏索引”的形式返回聚合数据# 到⽬前为⽌,所有示例中的聚合数据都有由唯⼀的分组键组成的# 索引(可能还是层次化的)。由于并不总是需要如此,所以你可# 以向groupby传⼊as_index=False以禁⽤该功能:tips.groupby(['day', 'smoker'], as_index=False).mean()day smoker total_bill tip size tip_pct0 Fri No 18.420000 2.812500 2.250000 0.1516501 Fri Yes 16.813333 2.714000 2.066667 0.1747832 Sat No 19.661778 3.102889 2.555556 0.1580483 Sat Yes 21.276667 2.875476 2.476190 0.1479064 Sun No 20.506667 3.167895 2.929825 0.1601135 Sun Yes 24.120000 3.516842 2.578947 0.1872506 Thur No 17.113111 2.673778 2.488889 0.1602987 Thur Yes 19.190588 3.030000 2.352941 0.163863Apply: General split-apply-combine10.3 apply:⼀般性的“拆分-应⽤-合并”# 最通⽤的GroupBy⽅法是apply,本节剩余部分将重点讲解它。# 如图10-2所示,apply会将待处理的对象拆分成多个⽚段,然后# 对各⽚段调⽤传⼊的函数,最后尝试将各⽚段组合到⼀起。# 10.3 apply:⼀般性的“拆分-应⽤-合并”# 最通⽤的GroupBy⽅法是apply,本节剩余部分将重点讲解它。# 如图10-2所示,apply会将待处理的对象拆分成多个⽚段,然后# 对各⽚段调⽤传⼊的函数,最后尝试将各⽚段组合到⼀起。def top(df, n=5, column='tip_pct'): return df.sort_values(by=column)[-n:]top(tips, n=6)total_bill tip smoker day time size tip_pct109 14.31 4.00 Yes Sat Dinner 2 0.279525183 23.17 6.50 Yes Sun Dinner 4 0.280535232 11.61 3.39 No Sat Dinner 2 0.29199067 3.07 1.00 Yes Sat Dinner 1 0.325733178 9.60 4.00 Yes Sun Dinner 2 0.416667172 7.25 5.15 Yes Sun Dinner 2 0.710345现在,如果对smoker分组并⽤该函数调⽤apply,就会得到:# 现在,如果对smoker分组并⽤该函数调⽤apply,就会得到:tips.groupby('smoker').apply(top)total_bill tip smoker day time size tip_pctsmoker No 88 24.71 5.85 No Thur Lunch 2 0.236746185 20.69 5.00 No Sun Dinner 5 0.24166351 10.29 2.60 No Sun Dinner 2 0.252672149 7.51 2.00 No Thur Lunch 2 0.266312232 11.61 3.39 No Sat Dinner 2 0.291990Yes 109 14.31 4.00 Yes Sat Dinner 2 0.279525183 23.17 6.50 Yes Sun Dinner 4 0.28053567 3.07 1.00 Yes Sat Dinner 1 0.325733178 9.60 4.00 Yes Sun Dinner 2 0.416667172 7.25 5.15 Yes Sun Dinner 2 0.710345最终结果就有了⼀个层次化索引,其内层索引值来⾃# 原DataFrame。# 如果传给apply的函数能够接受其他参数或关键字,则可以将这# 些内容放在函数名后⾯⼀并传⼊:# 最终结果就有了⼀个层次化索引,其内层索引值来⾃# 原DataFrame。# 如果传给apply的函数能够接受其他参数或关键字,则可以将这# 些内容放在函数名后⾯⼀并传⼊:tips.groupby(['smoker', 'day']).apply(top, n=1, column='total_bill')total_bill tip smoker day time size tip_pctsmoker day No Fri 94 22.75 3.25 No Fri Dinner 2 0.142857Sat 212 48.33 9.00 No Sat Dinner 4 0.186220Sun 156 48.17 5.00 No Sun Dinner 6 0.103799Thur 142 41.19 5.00 No Thur Lunch 5 0.121389Yes Fri 95 40.17 4.73 Yes Fri Dinner 4 0.117750Sat 170 50.81 10.00 Yes Sat Dinner 3 0.196812Sun 182 45.35 3.50 Yes Sun Dinner 3 0.077178Thur 197 43.11 5.00 Yes Thur Lunch 4 0.115982可能你已经想起来了,之前我在GroupBy对象上调⽤过# describe:# 可能你已经想起来了,之前我在GroupBy对象上调⽤过# describe:result = tips.groupby('smoker')['tip_pct'].describe()resultresult.unstack('smoker') smokercount No 151.000000 Yes 93.000000mean No 0.159328 Yes 0.163196std No 0.039910 Yes 0.085119min No 0.056797 Yes 0.03563825% No 0.136906 Yes 0.10677150% No 0.155625 Yes 0.15384675% No 0.185014 Yes 0.195059max No 0.291990 Yes 0.710345dtype: float64f = lambda x: x.describe() grouped.apply(f)Suppressing the Group Keys禁⽌分组键# 从上⾯的例⼦中可以看出,分组键会跟原始对象的索引共同构成# 400# 结果对象中的层次化索引。将group_keys=False传⼊groupby即# 可禁⽌该效果:# 禁⽌分组键# 从上⾯的例⼦中可以看出,分组键会跟原始对象的索引共同构成# 400# 结果对象中的层次化索引。将group_keys=False传⼊groupby即# 可禁⽌该效果:tips.groupby('smoker', group_keys=False).apply(top)total_bill tip smoker day time size tip_pct88 24.71 5.85 No Thur Lunch 2 0.236746185 20.69 5.00 No Sun Dinner 5 0.24166351 10.29 2.60 No Sun Dinner 2 0.252672149 7.51 2.00 No Thur Lunch 2 0.266312232 11.61 3.39 No Sat Dinner 2 0.291990109 14.31 4.00 Yes Sat Dinner 2 0.279525183 23.17 6.50 Yes Sun Dinner 4 0.28053567 3.07 1.00 Yes Sat Dinner 1 0.325733178 9.60 4.00 Yes Sun Dinner 2 0.416667172 7.25 5.15 Yes Sun Dinner 2 0.710345Quantile and Bucket Analysis分位数和桶分析# 我曾在第8章中讲过,pandas有⼀些能根据指定⾯元或样本分位# 数将数据拆分成多块的⼯具(⽐如cut和qcut)。将这些函数跟# groupby结合起来,就能⾮常轻松地实现对数据集的桶# (bucket)或分位数(quantile)分析了。以下⾯这个简单的随# 机数据集为例,我们利⽤cut将其装⼊⻓度相等的桶中:# 分位数和桶分析# 我曾在第8章中讲过,pandas有⼀些能根据指定⾯元或样本分位# 数将数据拆分成多块的⼯具(⽐如cut和qcut)。将这些函数跟# groupby结合起来,就能⾮常轻松地实现对数据集的桶# (bucket)或分位数(quantile)分析了。以下⾯这个简单的随# 机数据集为例,我们利⽤cut将其装⼊⻓度相等的桶中:frame = pd.DataFrame({'data1': np.random.randn(1000), 'data2': np.random.randn(1000)})quartiles = pd.cut(frame.data1, 4)quartiles[:10]0 (-1.23, 0.489]1 (-1.23, 0.489]2 (-1.23, 0.489]3 (-1.23, 0.489]4 (-1.23, 0.489]5 (-1.23, 0.489]6 (-2.956, -1.23]7 (0.489, 2.208]8 (0.489, 2.208]9 (-1.23, 0.489]Name: data1, dtype: categoryCategories (4, interval[float64]): [(-2.956, -1.23] < (-1.23, 0.489] < (0.489, 2.208] < (2.208, 3.928]]由cut返回的Categorical对象可直接传递到groupby。因此,我们# 可以像下⾯这样对data2列做⼀些统计计算:# 由cut返回的Categorical对象可直接传递到groupby。因此,我们# 可以像下⾯这样对data2列做⼀些统计计算:def get_stats(group): return {'min': group.min(), 'max': group.max(), 'count': group.count(), 'mean': group.mean()}grouped = frame.data2.groupby(quartiles)grouped.apply(get_stats).unstack()count max mean mindata1 (-2.956, -1.23] 92.0 1.670835 -0.038501 -3.399312(-1.23, 0.489] 602.0 3.260383 -0.019113 -2.989741(0.489, 2.208] 294.0 2.954439 0.066179 -3.745356(2.208, 3.928] 12.0 1.765640 -0.048003 -1.929776这些都是⻓度相等的桶。要根据样本分位数得到⼤⼩相等的桶,# 使⽤qcut即可。传⼊labels=False即可只获取分位数的编号:# 这些都是⻓度相等的桶。要根据样本分位数得到⼤⼩相等的桶,# 使⽤qcut即可。传⼊labels=False即可只获取分位数的编号:# Return quantile numbersgrouping = pd.qcut(frame.data1, 10, labels=False)grouped = frame.data2.groupby(grouping)grouped.apply(get_stats).unstack()count max mean mindata1 0 100.0 1.670835 -0.010807 -3.3993121 100.0 2.628441 -0.033573 -2.1535452 100.0 2.527939 -0.149095 -2.9251133 100.0 3.260383 0.072874 -2.3155554 100.0 2.074345 -0.116594 -2.0479395 100.0 2.184810 0.074563 -2.9897416 100.0 2.089154 -0.033600 -2.0842317 100.0 2.954439 -0.014457 -3.0569908 100.0 2.735527 0.096532 -3.7453569 100.0 2.377020 0.152483 -3.428254Example: Filling Missing Values with Group-Specific Values示例:⽤特定于分组的值填充缺失值# 对于缺失数据的清理⼯作,有时你会⽤dropna将其替换掉,⽽有# 时则可能会希望⽤⼀个固定值或由数据集本身所衍⽣出来的值去# 填充NA值。这时就得使⽤fillna这个⼯具了。在下⾯这个例⼦# 中,我⽤平均值去填充NA值:# 示例:⽤特定于分组的值填充缺失值# 对于缺失数据的清理⼯作,有时你会⽤dropna将其替换掉,⽽有# 时则可能会希望⽤⼀个固定值或由数据集本身所衍⽣出来的值去# 填充NA值。这时就得使⽤fillna这个⼯具了。在下⾯这个例⼦# 中,我⽤平均值去填充NA值:s = pd.Series(np.random.randn(6))s[::2] = np.nanss.fillna(s.mean())0 0.4332561 1.4647532 0.4332563 -0.1949304 0.4332565 0.029944dtype: float64假设你需要对不同的分组填充不同的值。⼀种⽅法是将数据分# 组,并使⽤apply和⼀个能够对各数据块调⽤fillna的函数即可。# 下⾯是⼀些有关美国⼏个州的示例数据,这些州⼜被分为东部和# ⻄部:# 假设你需要对不同的分组填充不同的值。⼀种⽅法是将数据分# 组,并使⽤apply和⼀个能够对各数据块调⽤fillna的函数即可。# 下⾯是⼀些有关美国⼏个州的示例数据,这些州⼜被分为东部和# ⻄部:states = ['Ohio', 'New York', 'Vermont', 'Florida', 'Oregon', 'Nevada', 'California', 'Idaho']group_key = ['East'] * 4 + ['West'] * 4data = pd.Series(np.random.randn(8), index=states)dataOhio -1.199705New York 0.500468Vermont -0.084207Florida -0.145003Oregon -0.382199Nevada 0.588151California 2.653656Idaho -1.101910dtype: float64data[['Vermont', 'Nevada', 'Idaho']] = np.nandatadata.groupby(group_key).mean()我们可以⽤分组平均值去填充NA值:# 我们可以⽤分组平均值去填充NA值:fill_mean = lambda g: g.fillna(g.mean())data.groupby(group_key).apply(fill_mean)Ohio -1.199705New York 0.500468Vermont -0.084207Florida -0.145003Oregon -0.382199Nevada 0.588151California 2.653656Idaho -1.101910dtype: float64fill_values = {'East': 0.5, 'West': -1}fill_func = lambda g: g.fillna(fill_values[g.name])data.groupby(group_key).apply(fill_func)Example: Random Sampling and Permutation示例:随机采样和排列# 假设你想要从⼀个⼤数据集中随机抽取(进⾏替换或不替换)样# 本以进⾏蒙特卡罗模拟(Monte Carlo simulation)或其他分析⼯# 作。“抽取”的⽅式有很多,这⾥使⽤的⽅法是对Series使⽤# sample⽅法:# 示例:随机采样和排列# 假设你想要从⼀个⼤数据集中随机抽取(进⾏替换或不替换)样# 本以进⾏蒙特卡罗模拟(Monte Carlo simulation)或其他分析⼯# 作。“抽取”的⽅式有很多,这⾥使⽤的⽅法是对Series使⽤# sample⽅法:# Hearts, Spades, Clubs, Diamondssuits = ['H', 'S', 'C', 'D']card_val = (list(range(1, 11)) + [10] * 3) * 4base_names = ['A'] + list(range(2, 11)) + ['J', 'K', 'Q']cards = []for suit in ['H', 'S', 'C', 'D']: cards.extend(str(num) + suit for num in base_names)deck = pd.Series(card_val, index=cards)现在我有了⼀个⻓度为52的Series,其索引包括牌名,值则是21# 点或其他游戏中⽤于计分的点数(为了简单起⻅,我当A的点数# 为1):# 现在我有了⼀个⻓度为52的Series,其索引包括牌名,值则是21# 点或其他游戏中⽤于计分的点数(为了简单起⻅,我当A的点数# 为1):deck[:13]AH 12H 23H 34H 45H 56H 67H 78H 89H 910H 10JH 10KH 10QH 10dtype: int64def draw(deck, n=5): return deck.sample(n)draw(deck)get_suit = lambda card: card[-1] # last letter is suitdeck.groupby(get_suit).apply(draw, n=2)deck.groupby(get_suit, group_keys=False).apply(draw, n=2)Example: Group Weighted Average and Correlation示例:分组加权平均数和相关系数# 根据groupby的“拆分-应⽤-合并”范式,可以进⾏DataFrame# 的列与列之间或两个Series之间的运算(⽐如分组加权平均)。# 以下⾯这个数据集为例,它含有分组键、值以及⼀些权重值:# 示例:分组加权平均数和相关系数# 根据groupby的“拆分-应⽤-合并”范式,可以进⾏DataFrame# 的列与列之间或两个Series之间的运算(⽐如分组加权平均)。# 以下⾯这个数据集为例,它含有分组键、值以及⼀些权重值:df = pd.DataFrame({'category': ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b'], 'data': np.random.randn(8), 'weights': np.random.rand(8)})dfcategory data weights0 a -0.608443 0.7380781 a -0.340831 0.2249932 a 0.197070 0.1292183 a 1.129965 0.6412974 b -1.078691 0.2344865 b 0.261523 0.5078436 b 0.473563 0.3804627 b -0.939801 0.802412# 然后可以利⽤category计算分组加权平均数:grouped = df.groupby('category')get_wavg = lambda g: np.average(g['data'], weights=g['weights'])grouped.apply(get_wavg)categorya 0.129411b -0.360513dtype: float64close_px = pd.read_csv('examples/stock_px_2.csv', parse_dates=True, index_col=0)close_px.info()close_px[-4:]来做⼀个⽐较有趣的任务:计算⼀个由⽇收益率(通过百分数变# 化计算)与SPX之间的年度相关系数组成的DataFrame。下⾯是# ⼀个实现办法,我们先创建⼀个函数,⽤它计算每列和SPX列的# 成对相关系数:# 来做⼀个⽐较有趣的任务:计算⼀个由⽇收益率(通过百分数变# 化计算)与SPX之间的年度相关系数组成的DataFrame。下⾯是# ⼀个实现办法,我们先创建⼀个函数,⽤它计算每列和SPX列的# 成对相关系数:spx_corr = lambda x: x.corrwith(x['SPX'])# 接下来,我们使⽤pct_change计算close_px的百分⽐变化:rets = close_px.pct_change().dropna()---------------------------------------------------------------------------NameError Traceback (most recent call last) in () 1 # 接下来,我们使⽤pct_change计算close_px的百分⽐变化:----> 2 rets = close_px.pct_change().dropna()NameError: name 'close_px' is not definedget_year = lambda x: x.yearby_year = rets.groupby(get_year)by_year.apply(spx_corr)# 当然,你还可以计算列与列之间的相关系数。这⾥,我们计算# Apple和Microsoft的年相关系数:by_year.apply(lambda g: g['AAPL'].corr(g['MSFT']))# 当然,你还可以计算列与列之间的相关系数。这⾥,我们计算# Apple和Microsoft的年相关系数:by_year.apply(lambda g: g['AAPL'].corr(g['MSFT']))---------------------------------------------------------------------------NameError Traceback (most recent call last) in () 1 # 当然,你还可以计算列与列之间的相关系数。这⾥,我们计算 2 # Apple和Microsoft的年相关系数:----> 3 by_year.apply(lambda g: g['AAPL'].corr(g['MSFT']))NameError: name 'by_year' is not definedExample: Group-Wise Linear Regression示例:组级别的线性回归# 顺着上⼀个例⼦继续,你可以⽤groupby执⾏更为复杂的分组统# 计分析,只要函数返回的是pandas对象或标量值即可。例如,# 我可以定义下⾯这个regress函数(利⽤statsmodels计量经济学# 库)对各数据块执⾏普通最⼩⼆乘法(Ordinary Least# Squares, OLS)回归:# 示例:组级别的线性回归# 顺着上⼀个例⼦继续,你可以⽤groupby执⾏更为复杂的分组统# 计分析,只要函数返回的是pandas对象或标量值即可。例如,# 我可以定义下⾯这个regress函数(利⽤statsmodels计量经济学# 库)对各数据块执⾏普通最⼩⼆乘法(Ordinary Least# Squares, OLS)回归:import statsmodels.api as smdef regress(data, yvar, xvars): Y = data[yvar] X = data[xvars] X['intercept'] = 1. result = sm.OLS(Y, X).fit() return result.paramsby_year.apply(regress, 'AAPL', ['SPX'])by_year.apply(regress, 'AAPL', ['SPX'])
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
暂时没有评论,来抢沙发吧~