数据聚合与分组运算
df = pd.DataFrame({'key':['a','b','a','a'],'data':np.random.randint(1,10,4)}) df # groupby的本质 groupd = df['data'].groupby(df['key']) groupd # Groupby技术,另一个术语解释就是 split-apply-combine # 第一阶段 根据你所提供的一个或多个键被拆分为多组 # 第二阶段 将一个函数应用到各个分组上,并产生以个新值 # 第三阶段 所有这些函数的执行结果被合并到最终的结果对象中 # groupd 是GroupBy对象。它实际上还没有进行任何计算,只是含有一些有关分组键df['key']的中间数据而已。换句话说,该对象 # 已经有了接下来对各分组执行运算所需的一切信息。 # 这里最重要的是,数据根据分组键进行聚合,产生了一个新的Series,其索引为key列中的惟一值。 # groupby 的语法糖 # 对于由DataFrame产生的GroupBy对象,如果用一个或一组列名对其进行索引,就能实现选取部分列 # 进行聚合的目的。 df.groupby(df['key1'])['data1'] # 是以下代码的语法糖 df['data1'].groupby(df['key1']) # groupby + 函数 # 相对于字典或Series,python函数在定义分组映射关系时可以更有创意且更为抽象。 # 任何被当做分组键的函数都会在各个索引值上被调用一次,其返回值就会被当做分组名称。 # 假如你希望根据人名的长度进行分组,虽然可以求取人格字符串长度数组,但其实仅仅 # 传入一个len函数就可以了。高,实在是高。 people.groupby(len).sum() # 数据聚合 # 对于聚合,我指的是任何能够从数组中产生标量值的数据转换过程,比如,max(),min()。 # 然而,并不是只能是使用这些方法,你可以使用自己发明的聚合运算,还可以调用分组对象 # 上已经定义好的任何方法。例如,quantile() # 虽然quantile没有明确的实现与groupby对象,但它是一个series方法,所以这里是能用的。 # 实际上,GroupBy会高效的对Series进行切片,然后对各片调用piece,quantile,最终将这些结果 # 组装成最终结果。 df['data1'].group(df['key1']).quantile(0.9) # 如果使用自己的聚合函数,只需将其传入agg方法或aggregate方法 f['data1'].group(df['key1']).agg(peak_to_peak) # 分组级运算和转换 # 聚合只不过是分组运算的其中一种而已,它是数据转换的一个特例,也就是说,它接受 # 能够将一维数组简化为标量值的函数。 # 而transform和apply方法,它们能够执行更多其它的分组运算。 # 跟aggregate一样,transform也是一个有这严格条件的特殊函数:传入的函数只能产生两种结果: # 要么产生一个可以广播的标量值,如np.mean,要么产生一个相同大小的结果数组。 # 最一般化的GroupBy方法是apply。 # apply会将待处理的对象拆分成多个片段,然后对各片段调用传入的函数,最后尝试将各 # 片段组合到一起。 def top(df,n=5,column='tip_pct'): return df.sort_index(by=column)[-n:] tips.groupby('smoker').apply(top,n=6,column='total_pill') # 这里发生了什么? # top函数在DataFrame的各个片段上调用,然后由pandas.concat连接在一起,并以分组名称进行了标记。 # 于是最终结果就有了一个层次化索引。 # 如果传给apply的函数能够接受其它参数或关键字,则可以将这些内容放在函数名后面一并传入。 # 除了这些基本用法之外,能否充分发挥apply的威力很大程度上取决于你的创造力。传入的 # 那个函数能够做什么全由你说了算,它只需要返回一个pandas对象或标量值即可。 # 透视表和交叉表 # 透视表是一种常见的数据汇总工具。它根据一个或多个键对数据进行聚合,并根据行和列上的分组键 # 将数据分配到各个矩形区域中。在python和pandas中。可以通过groupby功能重塑运算制造透视表。 # DataFrame有一个pivot_table方法,可以实现透视功能。 # 应用场景还是很广的。 tips.pivot_table(values,rows=,cols=,aggfunc=,fill_value=,margins=) # 交叉表 crosstab # 交叉表是一种用于计算分组频率的特殊透视表。功能就很单一了,只是将某个矩形区域内计数。 pd.crosstab([tips.time,tips.day],tips.smoker,margins=True) # [tips.time,tips.day] 相当于 rows # tips.smoker 相当于 cols
时间序列
# 时间序列 # Pandas提供了一组标准的时间序列处理工具和数据算法。你可以高效的进行切片/切块, # 聚合,对定期/不定期的时间序列进行重采样等。这些工具大部分对金融和经济数据尤为有用, # 当然也可以用它们来分析服务器日志数据。 # 日期的范围,频率以及移动 # pandas中的时间序列一般被认为是不规则的,也就是说,它们没有固定的频率。但是,它常常需要以 # 某种相对固定的频率进行分析,比如每日,每月,每15分钟。这个时候只需调用resample即可。 # 重采样及频率转换 # 重采样指的是将时间序列从一个频率转换到另一个频率的处理过程。将高频率数据聚合到低频率 # 称为降采样,将低频率数据转换到高配率则称为升采样。并不是所有的重采样都能被划分到这两个 # 大类中。例如,将W-WED转换为W-FRI既不是升采样也不是降采样。 # Pandas对象都有一个resample方法,它是各种频率转换工作的主力函数。 # 降采样 # 方法一 resample # ts.resample('D',how='sum') # 将数据聚合到规整的低频率是一件非常普通的时间序列处理任务。待聚合的数据不必拥有固定的 # 频率,期望的频率很自动定义聚合的面元边界。 # 在用resample对数据进行降采样时,需要考虑两样东西 # 个区间哪边是闭合的, 默认 colsed='right' # 如何标记各个聚合面元,用区间的开头还是末尾 默认 label='right' # 用于产出聚合值的函数名,默认为 mean. # 方法二 groupby # 只需要传入一个能够访问时间序列的索引上的这些字段的函数即可。 # ts.groupby(lambda x:x.month).mean() # ts.groupby(lambda x:x.weekday).mean() # 移动窗口函数 # 在移动窗口(可以带有指数衰减权数)上计算的各种统计函数也是一类常见于时间序列的数组变换。 # 我将它们称为移动窗口函数,其中还包括那些窗口不定长的函数,如指数加权移动平均。跟其它 # 统计函数一样,移动窗口函数也会自动排除缺失值。 # 典型应用场景:股价 Series.rolling(10).mean()/count()/std()/sum()/corr()
金融和经济数据应用
# 数据规整化方面的话题 # 时间序列以及截面对其 # pandas可以在算术运算中自动对其数据,并在sum这样的函数中排除缺失数据(np.nan)。 # 频率不同的时间序列的运算 # 经济学时间序列常常有这按年,月,日计算的或其它更特殊的频率,有些完全四不规则的。 # 比如说,盈利预测调整随时都有可能发生。 # 频率转换和重对其的两大主要工具是resample和reindex。resample用于将数据转换到固定频率, # 而reindex则用于是数据符合一个新的索引。它们都支持插值(如向前填充)逻辑。 # reindex 和 resample一块记 df1 = pd.DataFrame(np.random.randint(1,20,10),index=pd.date_range('2010-01-01',periods=10),columns=['A']) df2 = pd.DataFrame(np.random.randint(21,40,10),index=pd.date_range('2010-01-05',periods=10),columns=['A']) df1.reindex(df2.index,method='bfill') # 拼接多个数据源 # 在一个特定的时间点上,从一个数据源切到另一个数据源 # 用另一个时间序列对当前时间序列中的缺失值打补丁 # 将数据中的符号(国家,资产代码等)替换为实际数据。 # 第一种情况 pd.concat() # 第二种情况 df1.combine_first(df2) /df1.update(df2,overwrite=False)