数据规整:使用多层索引进行重塑,将 ‘长’ 透视为 ‘宽’, 将 ‘宽’ 透视为 ‘长’

3.1 使用多层索引进行重塑

多层索引在 dataframe 中提供了一种一致性方式用于重排列数据:

  • stack(堆叠):该操作会旋转或将列中的数据透视到行。
  • unstack(拆堆):将行中的数据透视到列。
data = pd.DataFrame(np.arange(6).reshape((2, 3)),
                    index=pd.Index(['Ohio', 'Colorado'], name='state'),
                    columns=pd.Index(['one', 'two', 'three'],
                    name='number'))
data
number	   one	two	three
state			
Ohio	    0	1	2
Colorado	3	4	5

result=data.stack()
result
state     number
Ohio      one       0
          two       1           #  将列中的数据透视到行。
          three     2
Colorado  one       3
          two       4
          three     5
dtype: int32

result.unstack()            #  就是拆成原来的
# 默认情况下,最内层是以拆堆的。你可以传入一个层级序号或名称来拆分一个不同的层级。
result.unstack(0)
state	Ohio	Colorado
number		
one	    0	3
two   	1	4
three	2	5


s1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd'])
s2 = pd.Series([4, 5, 6], index=['c', 'd', 'e'])
data2 = pd.concat([s1, s2], keys=['one', 'two'])
data2
one  a    0
     b    1
     c    2
     d    3
two  c    4
     d    5
     e    6
dtype: int64

data2.unstack()
	a	b	c	d	e               # 如果层级中所有值并未包含于每个子分组时,引入缺失值。
one	0.0	1.0	2.0	3.0	NaN
two	NaN	NaN	4.0	5.0	6.0

# 默认情况下,stack()可以过滤缺失值,所有这个操作时可逆的
data2.unstack().stack(dropna=False)           # 不过滤缺失值。
one  a    0.0
     b    1.0
     c    2.0
     d    3.0
     e    NaN
two  a    NaN
     b    NaN
     c    4.0
     d    5.0
     e    6.0
dtype: float64


df = pd.DataFrame({'left': result, 'right': result + 5},
                  columns=pd.Index(['left', 'right'], name='side'))
df
	side	    left	right
state	   number		
Ohio	     one	0	5
             two	1	6
           three	2	7
Colorado	  one	3	8
             two	4	9
           three	5	10

df.unstack(0)
side	    left	            right
state	Ohio	Colorado	Ohio	Colorado
number				
one    	0	3	5	8
two 	1	4	6	9
three	2	5	7	10

df.unstack(0).stack('side')            #  指名需要堆叠的轴向名称。等价于 .stack(0)
	state	Colorado	Ohio
number	side		
one	left	3	0
    right	8	5                        # 这个格式真的是不好看啊。。。
two	left	4	1
    right	9	6
three	left	5	2
    right	10	7

3.2 将 ‘长’ 透视为 ‘宽’

在数据库中和CSV 中存储多时间序列的方式就是所谓的长格式或堆叠格式。

data=pd.read_table('macrodata.csv',sep=r'\t')
data.head()
  year	quarter	realgdp	realcons	realinv	realgovt	realdpi	cpi	m1	tbilrate	unemp	pop	infl	realint
0	1959.0	1.0	2710.349	1707.4	286.898	470.045	1886.9	28.98	139.7	2.82	5.8	177.146	0.00	0.00
1	1959.0	2.0	2778.801	1733.7	310.859	481.301	1919.7	29.15	141.7	3.08	5.1	177.830	2.34	0.74
2	1959.0	3.0	2775.488	1751.8	289.226	491.260	1916.4	29.35	140.5	3.82	5.3	178.657	2.74	1.09
3	1959.0	4.0	2785.204	1753.7	299.356	484.052	1931.3	29.37	140.0	4.33	5.6	179.386	0.27	4.06
4	1960.0	1.0	2847.699	1770.5	331.722	462.199	1955.5	29.54	139.6	3.50	5.2	180.007	2.31	1.19

# PeriodIndex 以后再说,,就是将year 和 quarter 等列联合生成一种时间间隔类型。
periods=pd.PeriodIndex(year=data.year,quarter=data.quarter,name='data')
periods
PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2',
             '1960Q3', '1960Q4', '1961Q1', '1961Q2',
             ...
             '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3',
             '2008Q4', '2009Q1', '2009Q2', '2009Q3'],
            dtype='period[Q-DEC]', name='date', length=203, freq='Q-DEC')

columns=pd.Index(['realgdp','infl','unemp'],name='item')
data=data.reindex(columns=columns)                      # 这里就选出三列来
data.index=periods.to_timestamp('D','end')         
# ['1959-03-31 23:59:59.999999999','1959-06-30 23:59:59.999999999'........ 
# data.index 就是这样的,,,我也看不懂为啥后面有那么多9999999,以后学到在说吧,,,我怀疑买到了假书。。。

ldata=data.stack().reset_index().rename(columns={0:'value'})       # 看不懂的话可以拆开一步一步看结果。。。
ldata[:5]
	date	                        item	value
0	1959-03-31 23:59:59.999999999	realgdp	2710.349    # 这9999999999999是撒啊。。。
1	1959-03-31 23:59:59.999999999	infl	0.000
2	1959-03-31 23:59:59.999999999	unemp	5.800
3	1959-06-30 23:59:59.999999999	realgdp	2778.801
4	1959-06-30 23:59:59.999999999	infl	2.340

这种数据就是所谓的多时间序列的长格式。或称为具有两个或更多个键的其他观测数据(这里的键就是data and item)。表中的每一行表示一个时间点上的单个观测值。

数据通常以这种方式存储在关系型数据库中,如MySQL,因为固定模式(列名称和数据类型)允许item列中不同值的数量随这数据被添加到表中而改变。但是处理这种格式的数据更为困难,你可能更喜欢获取一个按data列时间索引的且每个不同 item独立一列的 dataframe。 使用pivote 方法。就是将一列变换成新的datafraem 的多列。

pivoted=ldata.pivot('date','item','value')  #  传递的前两个值分别用作行和列索,然后是可选的数值列来填充dataframe 。
pivoted
item	                          infl	realgdp	unemp
date			
1959-03-31 23:59:59.999999999	0.00	2710.349	5.8
1959-06-30 23:59:59.999999999	2.34	2778.801	5.1
1959-09-30 23:59:59.999999999	2.74	2775.488	5.3
1959-12-31 23:59:59.999999999	0.27	2785.204	5.6
1960-03-31 23:59:59.999999999	2.31	2847.699	5.2
...	...	...	...
2008-09-30 23:59:59.999999999	-3.16	13324.600	6.0
2008-12-31 23:59:59.999999999	-8.79	13141.920	6.9
2009-03-31 23:59:59.999999999	0.94	12925.410	8.1
2009-06-30 23:59:59.999999999	3.37	12901.504	9.2
2009-09-30 23:59:59.999999999	3.56	12990.341	9.6
203 rows × 3 columns

# 如果你同时想处理两个数值列
ldata['value2']=np.random.randn(len(ldata))

pivoted=ldata.pivot('date','item')
pivoted[:2]
                                 	value	                      value2
item	                          infl	realgdp	unemp	    infl	realgdp	unemp
date						
1959-03-31 23:59:59.999999999	0.00	2710.349	5.8	-1.875672	0.374631	0.219582
1959-06-30 23:59:59.999999999	2.34	2778.801	5.1	1.722825	1.106186	1.187564

pivoted['value'][:2]
item	                         infl	realgdp	unemp
date			
1959-03-31 23:59:59.999999999	0.00	2710.349	5.8
1959-06-30 23:59:59.999999999	2.34	2778.801	5.1


# pivot 方法等价于使用 set_index 创建分层索引,然后调用 unstack
unstacked=ldata.set_index(['date','item'])
unstacked           # 返回值 等于 pivoted

3.3 将 ‘宽’ 透视为 ‘长’

在 dataframe 中,pivot 方法的反操作就是pandas.melt。与将一列变换成新的dataframe 中的多列不同,他将多列合并成一列, 产生一个新的dataframe,其长度比输入更长。

df=pd.DataFrame({'key':['foo','bar','baz'],'A':[1,2,3],'B':[4,5,6],'C':[7,8,9]})
df
    key	A	B	C
0	foo	1	4	7
1	bar	2	5	8
2	baz	3	6	9

melted=pd.melt(df,['key'])      # 使用 melt 时,必须要指名那些列是分组坐标。这里我们使用key 列作为唯一的分组坐标
melted
	key	variable	value
0	foo	A	1
1	bar	A	2
2	baz	A	3
3	foo	B	4
4	bar	B	5
5	baz	B	6
6	foo	C	7
7	bar	C	8
8	baz	C	9

reshaped=melted.pivot('key','variable','value')
reshaped                      # 使用pivote 将数据重塑到原先的布局。
variable	A	B	C
key			
bar	    2	5	8
baz    	3	6	9
foo   	1	4	7

reshaped.reset_index()           # pivot 的结果根据行标签的列生成了索引(就是key那一列)
variable	key	A	B	
0	bar	    2	5	8                  # 使用 reset_index 回移一列,就是多加一列索引。。
1	baz	    3	6	9
2	foo	    1	4	7


pd.melt(df,id_vars=['key'],value_vars=['A','B'])         # 指定列的子集作为值列
	key	variable	value
0	foo	A	1
1	bar	A	2
2	baz	A	3
3	foo	B	4
4	bar	B	5
5	baz	B	6

pd.melt(df,value_vars=['A','B','key'])        # 也可以无需任何分组组标。
	variable	value
0	A	1
1	A	2
2	A	3
3	B	4
4	B	5
5	B	6
6	key	foo
7	key	bar
8	key	baz

在家憋久了感觉一切都索然无味了。。。😔。。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值