長型數(shù)據(jù)(long format dataframe)與寬型數(shù)據(jù)(wide format dataframe)是兩種形式的數(shù)據(jù)框吆玖,在數(shù)據(jù)分析中高頻出現(xiàn)筒溃,在數(shù)據(jù)處理過程中,
常常需要在兩者之間相互轉(zhuǎn)換沾乘。本文基于pandas怜奖,介紹長型數(shù)據(jù)與寬型數(shù)據(jù)的相互轉(zhuǎn)換操作。
環(huán)境
- python3.9
- win10 64bit
- pandas==1.2.1
寬轉(zhuǎn)長
在pandas中翅阵,寬型轉(zhuǎn)長型數(shù)據(jù)有melt
和wide_to_long
兩種方法歪玲。
melt
melt
方法叫做數(shù)據(jù)融合,是dataFrame擁有的方法掷匠,使用較為頻繁滥崩。參數(shù)解釋如下:
DataFrame.melt(id_vars=None, value_vars=None, var_name=None, value_name='value', col_level=None, ignore_index=True)
- id_vars:[tuple, list, ndarray],列中識別符變量槐雾,不參與融合夭委。
- value_vars:[tuple, list, ndarray],列中融合變量募强,默認全部融合株灸。
- var_name:[scalar],融合后變量名字擎值,默認variable慌烧。
- value_name:[scalar],融合后值名字鸠儿,默認value屹蚊。
- col_level:[int, str],多重列索引時選擇列进每。
- ignore_index:[bool]汹粤,融合后索引是否重新排序,默認True田晚。
import pandas as pd
pd.set_option('display.notebook_repr_html',False)
# 寬型數(shù)據(jù)
w_df = pd.DataFrame({'A': [1,2,3],
'B': [4,5,6],
'C': [7,8,9]})
w_df
A B C
0 1 4 7
1 2 5 8
2 3 6 9
- 當不傳入任何參數(shù)時嘱兼,默認會融合全部的列。
# 全部融合
w_df.melt()
variable value
0 A 1
1 A 2
2 A 3
3 B 4
4 B 5
5 B 6
6 C 7
7 C 8
8 C 9
- 設(shè)置
id_vars
參數(shù)贤徒,選擇部分列作為識別符不參與融合芹壕,剩余的列將全部融合。
# A標識接奈,B踢涌,C融合
w_df.melt(id_vars=['A'])
A variable value
0 1 B 4
1 2 B 5
2 3 B 6
3 1 C 7
4 2 C 8
5 3 C 9
# A,B標識序宦,C融合
w_df.melt(id_vars=['A','B'])
A B variable value
0 1 4 C 7
1 2 5 C 8
2 3 6 C 9
- 設(shè)置
value_vars
參數(shù)睁壁,選擇部分列作為融合列。
注意剩余的列不會自動作為標識符列。
# 只融合A
w_df.melt(value_vars=['A'])
variable value
0 A 1
1 A 2
2 A 3
# 只融合A,B
w_df.melt(value_vars=['A','B'])
variable value
0 A 1
1 A 2
2 A 3
3 B 4
4 B 5
5 B 6
- 設(shè)置
var_name
(默認variable),value_name
(默認value)參數(shù)潘明,為融合的變量與值設(shè)置名字糠惫。
# 設(shè)置融合后變量名與值名
w_df.melt(var_name='code',value_name='count')
code count
0 A 1
1 A 2
2 A 3
3 B 4
4 B 5
5 B 6
6 C 7
7 C 8
8 C 9
- 設(shè)置
ignore_index=False
可以保留原數(shù)據(jù)的索引。
w_df.melt(ignore_index=False)
variable value
0 A 1
1 A 2
2 A 3
0 B 4
1 B 5
2 B 6
0 C 7
1 C 8
2 C 9
- 設(shè)置
col_level
參數(shù)钉疫,可以選擇多重列索引數(shù)據(jù)來融合數(shù)據(jù)硼讽。
# 列多重索引數(shù)據(jù)
mi_w_df=w_df.copy()
mi_w_df.columns=[list('ABC'),list('DEF')]
mi_w_df
A B C
D E F
0 1 4 7
1 2 5 8
2 3 6 9
# 融合第一索引列
mi_w_df.melt(col_level=0)
variable value
0 A 1
1 A 2
2 A 3
3 B 4
4 B 5
5 B 6
6 C 7
7 C 8
8 C 9
# 融合第二索引列
mi_w_df.melt(col_level=1)
variable value
0 D 1
1 D 2
2 D 3
3 E 4
4 E 5
5 E 6
6 F 7
7 F 8
8 F 9
wide_to_long
wide_to_long
函數(shù)是pandas自帶的,是對melt的一種補充牲阁,在特殊的寬轉(zhuǎn)長情況下更適用固阁。
pandas.wide_to_long(df, stubnames, i, j, sep='', suffix='\d+')
- df:[pd.dataframe],寬型數(shù)據(jù)框
- stubnames:[str,list-like]城菊,列名中的存根名字
- i:[str,list-like]备燃,列中的索引變量
- j:[str],后綴的重命名
- sep:[str,default ""]凌唬,存根名與后綴之間的分隔符
- suffix:[str,default "\d+"]并齐,后綴
# 寬型數(shù)據(jù)
s_df = pd.DataFrame({"A1970" : [1,33,3],
"B1980" : [3,5,7],
"A1980" : [13,15,17],
"B1970" : [6,8,14],
"x" : [1,2,3],
"y" : [4,5,6]})
s_df
A1970 B1980 A1980 B1970 x y
0 1 3 13 6 1 4
1 33 5 15 8 2 5
2 3 7 17 14 3 6
在數(shù)據(jù)中,A1970
,B1980
,A1980
,B1970
這幾列名字具有相同的結(jié)構(gòu)客税,如果需要將它們分開况褪,就可以用long_to_wide
函數(shù)。
# 特定列的寬轉(zhuǎn)長
pd.wide_to_long(s_df,stubnames=['A','B'],j='year',i='x')
y A B
x year
1 1970 4 1 6
1980 4 13 3
2 1970 5 33 8
1980 5 15 5
3 1970 6 3 14
1980 6 17 7
- 設(shè)置
stubnames
更耻,函數(shù)會根據(jù)設(shè)置的字符去數(shù)據(jù)列中匹配目標列测垛,然后轉(zhuǎn)換為長數(shù)據(jù)
# 只轉(zhuǎn)換包含A的列
pd.wide_to_long(s_df,stubnames=['A',],j='year',i='x')
B1970 y B1980 A
x year
1 1970 6 4 3 1
2 1970 8 5 5 33
3 1970 14 6 7 3
1 1980 6 4 3 13
2 1980 8 5 5 15
3 1980 14 6 7 17
如果stubnames
參數(shù)設(shè)置的字符在原數(shù)據(jù)框的列中無法找到,則返回空數(shù)據(jù)框秧均。
# 列名中不存在C字符食侮,返回空數(shù)據(jù)框
pd.wide_to_long(s_df,stubnames=['C',],j='year',i='x')
Empty DataFrame
Columns: [B1970, y, A1980, B1980, A1970, C]
Index: []
- 參數(shù)
i
可以設(shè)置為多列,返回多個索引目胡。
# 設(shè)置多索引
pd.wide_to_long(s_df,stubnames=['A','B'],j='year',i=['x','y'])
A B
x y year
1 4 1970 1 6
1980 13 3
2 5 1970 33 8
1980 15 5
3 6 1970 3 14
1980 17 7
- 參數(shù)
sep
表示分隔符锯七,默認""
,可以根據(jù)實際情況設(shè)置誉己。
# 寬型數(shù)據(jù)(-分隔符)
sep_df = pd.DataFrame({"A-1970" : [1,33,3],
"B-1980" : [3,5,7],
"A-1980" : [13,15,17],
"B-1970" : [6,8,14],
"x" : [1,2,3],
"y" : [4,5,6]})
sep_df
A-1970 B-1980 A-1980 B-1970 x y
0 1 3 13 6 1 4
1 33 5 15 8 2 5
2 3 7 17 14 3 6
數(shù)據(jù)中列名的分隔符為-
眉尸,則轉(zhuǎn)換的時候需要設(shè)置sep='-'
。
# 設(shè)置sep參數(shù)
pd.wide_to_long(sep_df,stubnames=['A','B'],j='year',i='x',sep='-')
y A B
x year
1 1970 4 1 6
1980 4 13 3
2 1970 5 33 8
1980 5 15 5
3 1970 6 3 14
1980 6 17 7
- 參數(shù)
suffix
表示后綴巫延,默認是"\d+"
效五,是正則表達式地消,表示匹配數(shù)字炉峰,可以根據(jù)實際情況替換。
# 寬型數(shù)據(jù)
suf_df = pd.DataFrame({"Aone" : [1,33,3],
"Btwo" : [3,5,7],
"Atwo" : [13,15,17],
"Bone" : [6,8,14],
"x" : [1,2,3],
"y" : [4,5,6]})
suf_df
Aone Btwo Atwo Bone x y
0 1 3 13 6 1 4
1 33 5 15 8 2 5
2 3 7 17 14 3 6
# 指定后綴
pd.wide_to_long(suf_df,stubnames=['A','B'],j='year',i='x',suffix='(one|two)')
y A B
x year
1 one 4 1 6
two 4 13 3
2 one 5 33 8
two 5 15 5
3 one 6 3 14
two 6 17 7
長轉(zhuǎn)寬
長型數(shù)據(jù)轉(zhuǎn)為寬型數(shù)據(jù)可以通過透視的功能實現(xiàn)脉执,類似于excel中的透視表功能疼阔。在pandas中用pivot
方法實現(xiàn)。
DataFrame.pivot(index=None, columns=None, values=None)
- index:[str ,object ,a list of str],透視的索引
- columns:[str ,object ,a list of str]婆廊,透視的列
- values:[str, object ,a list of the previous]迅细,透視的值
# 長型數(shù)據(jù)
l_df = pd.DataFrame({'foo': ['one', 'one', 'one', 'two', 'two','two'],
'bar': ['A', 'B', 'C', 'A', 'B', 'C'],
'cat':['alpha','alpha','alpha','beta','beta','beta'],
'baz': [1, 2, 3, 4, 5, 6],
'zoo': [4, 6, 8, 1, 2, 9]})
l_df
foo bar cat baz zoo
0 one A alpha 1 4
1 one B alpha 2 6
2 one C alpha 3 8
3 two A beta 4 1
4 two B beta 5 2
5 two C beta 6 9
選擇foo
列作為透視后的索引,bar
列作為透視的列淘邻,里面的元素會展開成新數(shù)據(jù)框的列茵典,baz
作為透視的值,填充在新數(shù)據(jù)框中宾舅。
# 透視數(shù)據(jù)
l_df.pivot(index='foo',columns='bar',values='baz')
bar A B C
foo
one 1 2 3
two 4 5 6
- 設(shè)置
index
為多個列名统阿,透視表將具有多個行索引。
# 多索引透視
l_df.pivot(index=['foo','bar'],columns='cat',values='baz')
cat alpha beta
foo bar
one A 1.0 NaN
B 2.0 NaN
C 3.0 NaN
two A NaN 4.0
B NaN 5.0
C NaN 6.0
- 設(shè)置
columns
為多個列名筹我,透視表將具有多個列索引扶平。
# 多列透視
l_df.pivot(index='foo',columns=['bar','cat'],values='baz')
bar A B C A B C
cat alpha alpha alpha beta beta beta
foo
one 1.0 2.0 3.0 NaN NaN NaN
two NaN NaN NaN 4.0 5.0 6.0
- 設(shè)置
values
為多個列名。
l_df.pivot(index='foo',columns='bar',values=['baz','zoo'])
baz zoo
bar A B C A B C
foo
one 1 2 3 4 6 8
two 4 5 6 1 2 9