0.背景
在Pandas的使用中,常常需要到行列切換的情況,即所謂的數據透視表,這裏根據Pandas當中的此類專題進行總結,主要解析pivot,melt,stack,unstack幾個函數的使用。**
1.pivot(一定要看下pivot_table)
pivot做的就是從源數據構造透視表的過程,透視表是在數據統計中一個數據彙總的方式。pivot使用例子如下所示。
import pandas as pd
# 原始數據
data = {'date': ['2018-08-01', '2018-08-02', '2018-08-03', '2018-08-01', '2018-08-03', '2018-08-03',
'2018-08-01', '2018-08-02'],
'variable': ['A','A','A','B','B','C','C','C'],
'value': [3.0 ,4.0 ,6.0 ,2.0 ,8.0 ,4.0 ,10.0 ,1.0 ]}
df = pd.DataFrame(data=data, columns=['date', 'variable', 'value'])
print(df)
# date variable value
# 0 2018-08-01 A 3.0
# 1 2018-08-02 A 4.0
# 2 2018-08-03 A 6.0
# 3 2018-08-01 B 2.0
# 4 2018-08-03 B 8.0
# 5 2018-08-03 C 4.0
# 6 2018-08-01 C 10.0
# 7 2018-08-02 C 1.0
# eg1.如果要根據時間統計各variable的值,做法如下
# 讓index爲date,讓variable裏的值變爲單獨的列(pivot)
df1 = df.pivot(index='date', columns='variable', values='value')
print(df1)
# variable A B C
# date
# 2018-08-01 3.0 2.0 10.0
# 2018-08-02 4.0 NaN 1.0
# 2018-08-03 6.0 8.0 4.0
# eg2.如果value有多個情況下,列名會變成Hierarchical columns的結構,即MultiIndex
df['value_other'] = df['value'] * 2
df2 = df.pivot(index='date', columns='variable', values=['value', 'value_other'])
print(df2)
# value value_other
# variable A B C A B C
# date
# 2018-08-01 3.0 2.0 10.0 6.0 4.0 20.0
# 2018-08-02 4.0 NaN 1.0 8.0 NaN 2.0
# 2018-08-03 6.0 8.0 4.0 12.0 16.0 8.0
print(df2['value_other'])
# variable A B C
# date
# 2018-08-01 6.0 4.0 20.0
# 2018-08-02 8.0 NaN 2.0
# 2018-08-03 12.0 16.0 8.0
2.melt
pd.melt或者DataFrame.melt做的是一種和pivot相反的操作。它將一個DataFrame伸展成如下格式(一列或者多列做identifier變量,其他的列做measured variables)。
主要的參數爲:
- id_vars: identifier變量的列
- value_vars: measured變量的列
- var_name: 變量列的名字
- value_name: value列的名字
- col_level: 列索引的級別(如果列是多重索引的話需要)
import numpy as np
import pandas as pd
cheese = pd.DataFrame({'first': ['John', 'Mary'],
'last': ['Doe', 'Bo'],
'height': [5.5, 6.0],
'weight': [130, 150]})
print(cheese)
# first height last weight
# 0 John 5.5 Doe 130
# 1 Mary 6.0 Bo 150
# eg1.idenfier變量爲first和last(其他的列默認爲measured變量)
print(cheese.melt(id_vars=['first', 'last']))
# first last variable value
# 0 John Doe height 5.5
# 1 Mary Bo height 6.0
# 2 John Doe weight 130.0
# 3 Mary Bo weight 150.0
# eg2.自定義variable和value列的名字
print(cheese.melt(id_vars=['first', 'last'], var_name='myVariable', value_name='myValue'))
# first last myVariable myValue
# 0 John Doe height 5.5
# 1 Mary Bo height 6.0
# 2 John Doe weight 130.0
# 3 Mary Bo weight 150.0
3.stack和unstack
DataFrame.stack和unstack是用來操作MultiIndex的。其實多重索引相當於用二維的形式來表徵高維數據。作爲二維數據的行和列都可以來做多重,stack和unstack就是在多重行索引和多重列索引(列名)之間轉化的。詳細使用如下。
import pandas as pd
import numpy as np
tuples = list(zip(*[['bar', 'bar', 'baz', 'baz',
'foo', 'foo', 'qux', 'qux'],
['one', 'two', 'one', 'two',
'one', 'two', 'one', 'two']]))
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
df = pd.DataFrame(np.random.randn(8,2), index=index, columns=['A', 'B'])
print(df)
# A B
# first second
# bar one -0.332862 0.929766
# two 0.857515 0.181623
# baz one -0.769248 0.200083
# two 0.907549 -0.781607
# foo one -1.683440 0.868688
# two -1.556559 -0.591569
# qux one -0.399071 0.115823
# two 1.665903 2.210725
# eg1.stack方法可以來"壓縮"一下列索引,這可能產生一個Series(如果本身列所以那就是一重的),或者一個DataFrame(列是多重索引)
# 這裏的結果就是產生了一個Series,行索引是三重的。
df1 = df.stack()
print(df1)
print(df1.index)
# first second
# bar one A -0.332862
# B 0.929766
# two A 0.857515
# B 0.181623
# baz one A -0.769248
# B 0.200083
# two A 0.907549
# B -0.781607
# foo one A -1.683440
# B 0.868688
# two A -1.556559
# B -0.591569
# qux one A -0.399071
# B 0.115823
# two A 1.665903
# B 2.210725
# MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], [u'one', u'two'], [u'A', u'B']],
# labels=[[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1], [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]],
# names=[u'first', u'second', None])
# eg2.相反的操作是unstack(),即減少一重行索引,增加一重列索引
df2 = df1.unstack()
print(df2)
# A B
# first second
# bar one -0.332862 0.929766
# two 0.857515 0.181623
# baz one -0.769248 0.200083
# two 0.907549 -0.781607
# foo one -1.683440 0.868688
# two -1.556559 -0.591569
# qux one -0.399071 0.115823
# two 1.665903 2.210725
# eg3.如果索引是多重的,我們可以指定去"壓縮"哪一層的索引。對於行索引來說
# - 行索引,從0開始,最左邊最小爲0
# - 列索引,從0開始,最上邊最小爲0
# 也可以不用0和1..等,用索引層的名字,比如這裏的first和second,但是這樣有可能有的索引層沒有名字,比如第一次stack後的df1。
# 數字和名字但不能混用,但是可以同時指定多個level值。
#
df3 = df1.unstack(level=0)
print(df3)
# first bar baz foo qux
# second
# one A -0.332862 -0.769248 -1.683440 -0.399071
# B 0.929766 0.200083 0.868688 0.115823
# two A 0.857515 0.907549 -1.556559 1.665903
# B 0.181623 -0.781607 -0.591569 2.210725
# eg4.stack和unstack內部都實現了排序,如果如果對一個DataFrame進行了stack在進行unstack,DataFrame會按照行索引排好序.
# 經過試驗列索引並不會排好序!
index = pd.MultiIndex.from_product([[2,1], ['a', 'b']])
df4 = pd.DataFrame(np.random.randn(4,1), index=index, columns=[100])
print(all(df4.stack().unstack() == df4.sort_index()))
df5 = pd.DataFrame(np.random.randn(4,3), index=index, columns=[100,99,102])
print(df5)
# True
# 100 99 102
# 2 a 0.094463 1.766611 0.588748
# b -1.262801 0.737156 -0.450470
# 1 a -0.888983 0.903101 -1.179545
# b 1.015863 -0.486976 -1.097248
# eg5.對於缺失值的處理比較智能
# 如下,列是多重索引,最外層不是AABB的形式,而是ABBA的形式,所以看起來列索引怪怪的,不是隻有一個A和B的形式。這些都不影響。
columns = pd.MultiIndex.from_tuples([('A', 'cat'), ('B', 'dog'),
('B', 'cat'), ('A', 'dog')],
names=['exp', 'animal'])
index = pd.MultiIndex.from_product([('bar', 'baz', 'foo', 'qux'),
('one', 'two')],
names=['first', 'second'])
df6 = pd.DataFrame(np.random.randn(8, 4), index=index, columns=columns)
print(df6)
# exp A B A
# animal cat dog cat dog
# first second
# bar one 2.640535 -0.030465 -1.323677 1.748616
# two 0.382401 -1.378172 0.862763 1.646497
# baz one 0.032120 0.140315 -0.073596 -1.402424
# ...
# eg6.缺失值int和float會填充Nan,時間類型填充NaT,也可以用fill_value=-999指定。
df7 = df6.iloc[[0, 1, 4, 7], [1, 2]].unstack()
print(df7)
# animal dog cat
# second one two one two
# first
# bar -0.030465 -1.378172 -1.323677 0.862763
# foo -0.848578 NaN -0.275208 NaN
# qux NaN -0.330900 NaN -0.809930
4.pivot_table
pivot_table根據文檔上的解釋是可以create一些spreadsheet-style類型的數據表。其實對於簡單DataFrame來說和pivot類似。但是在那基礎上增加了更多的一些功能。
主要參數如下:
- data:DataFrame
- index:index列,可以多個。pivot不可以。
- columns:column列
- values:value列
- aggFuc:聚合函數,可以是多個。相同的index和columns確定的值如果有多個,則根據這個函數計算除一個值作爲這個index和columns的值。默認情況是np.mean!,pivot在這種情況會提示有重複值,不能處理這種情況。
df = pd.DataFrame({"A": ["foo", "foo", "foo", "foo", "foo",
"bar", "bar", "bar", "bar"],
"B": ["one", "one", "one", "two", "two",
"one", "one", "two", "two"],
"C": ["small", "large", "large", "small",
"small", "large", "small", "small",
"large"],
"D": [1, 2, 2, 3, 3, 4, 5, 6, 7]})
print(df)
# 原始數據
# A B C D
# 0 foo one small 1
# 1 foo one large 2
# 2 foo one large 2
# 3 foo two small 3
# 4 foo two small 3
# 5 bar one large 4
# 6 bar one small 5
# 7 bar two small 6
# 8 bar two large 7
print(pd.pivot_table(df, index=['A', 'B'], columns=['C'], values=['D'], aggfunc=[np.mean, np.sum, max]))
# mean sum max
# D D D
# C large small large small large small
# A B
# bar one 4.0 5.0 4.0 5.0 4.0 5.0
# two 7.0 6.0 7.0 6.0 7.0 6.0
# foo one 2.0 1.0 4.0 1.0 2.0 1.0
# two NaN 3.0 NaN 6.0 NaN 3.0
5.官方文檔
1.http://pandas.pydata.org/pandas-docs/stable/reshaping.html#reshaping-by-stacking-and-unstacking