问题缘起
pandas的DataFrame可以用 diff() 方法实现相邻单元数值相减,但是目前有这样一个实用场景:已知数据集是某公司每个季度当年盈利总和的数据,需要求出该公司每个季度的盈利数据。
换一个方式表达就是:每年有四个季度的数据,一季度的数据就是单一的一季度盈利值,二季度的数据是一二两个季度盈利值的和,以此类推。
要求出每个季度单一的盈利值,那么就是除了每年的第一季度,都用自己的值减去前一季度的值——这是一个** 部分相邻相减 ** 问题。
解决思路
先用全部数据做相邻相减;然后将每年的第一季度的值替换成原始数据。使用到的关键方法是:diff()/update()
注意:update()方法本身返回的一定是None,之前测试时一直觉得奇怪,print a.update(b),得到的都是 None。原来,正确的姿势是 a.update(b),这时候 a 已经更新数据了,直接 print a,就会看到结果。
import pandas as pd
s=pd.Series(['2014-03-31','2014-06-30','2014-09-30','2014-12-31','2015-03-31','2015-06-30','2015-09-30','2016-12-31','2016-03-31','2016-06-30','2016-09-30','2016-12-31'])
income=[12,23,36,56,22,32,35,29,12,45,68,98]
df=pd.DataFrame(income,index=s,columns=['income'])
# 全部相邻相减
sub_all=df.diff(axis=0)
print sub_all
# 找出需要替换回来的
print '--------现在开始替换回来---------'
retain=df.iloc[[0,4,8]]
sub_all.update(retain)
print sub_all
income
2014-03-31 NaN
2014-06-30 11.0
2014-09-30 13.0
2014-12-31 20.0
2015-03-31 -34.0
2015-06-30 10.0
2015-09-30 3.0
2016-12-31 -6.0
2016-03-31 -17.0
2016-06-30 33.0
2016-09-30 23.0
2016-12-31 30.0
--------现在开始替换回来---------
income
2014-03-31 12.0
2014-06-30 11.0
2014-09-30 13.0
2014-12-31 20.0
2015-03-31 22.0
2015-06-30 10.0
2015-09-30 3.0
2016-12-31 -6.0
2016-03-31 12.0
2016-06-30 33.0
2016-09-30 23.0
2016-12-31 30.0
如何快速找出所有的一季度数据
重点是先用 pd.to_datetime()方法将index转为 datetime 对象,这样就能很容易的获得 month
import pandas as pd
import numpy as np
import re,datetime as dt
def get_all_season_one(df_raw,base_key_name):
# df_raw[base_key_name] 是叠加的每季度数据,即二季度数据是一二季度之和
# df_raw.index 每年只有四个值,是每年的报告期 yyyy-03-31,yyyy-06-30,yyyy-09-30,yyyy-12-31
# df_raw.index 的数据是按照时间逆序排列
df_raw['diff']= df_raw.diff(axis=0)[base_key_name]
df_raw.index=pd.to_datetime(df_raw.index)
df_raw['season']=df_raw.index.month/3
season_ones=df_raw[df_raw['season']==1]
return season_ones
s=pd.Series(['2014-03-31','2014-06-30','2014-09-30','2014-12-31','2015-03-31','2015-06-30','2015-09-30','2016-12-31','2016-03-31','2016-06-30','2016-09-30','2016-12-31'])
income=[12,23,36,56,22,32,35,29,12,45,68,98]
df=pd.DataFrame(income,index=s,columns=['income'])
print get_all_season_one(df,'income')
执行结果:
income diff season
2014-03-31 12 NaN 1
2015-03-31 22 -34.0 1
2016-03-31 12 -17.0 1