python--pandas長寬數據變形

長型數據(long format dataframe)與寬型數據(wide format dataframe)是兩種形式的數據框,在數據分析中高頻出現,在數據處理過程中,
常常需要在兩者之間相互轉換。本文基于pandas,介紹長型數據與寬型數據的相互轉換操作。

環境

  • python3.9
  • win10 64bit
  • pandas==1.2.1

寬轉長

在pandas中,寬型轉長型數據有meltwide_to_long兩種方法。

melt

melt方法叫做數據融合,是dataFrame擁有的方法,使用較為頻繁。參數解釋如下:

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)
# 寬型數據
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
  • 當不傳入任何參數時,默認會融合全部的列。
# 全部融合
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
  • 設置id_vars參數,選擇部分列作為識別符不參與融合,剩余的列將全部融合。
# 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
  • 設置value_vars參數,選擇部分列作為融合列。

注意剩余的列不會自動作為標識符列。

# 只融合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
  • 設置var_name(默認variable),value_name(默認value)參數,為融合的變量與值設置名字。
# 設置融合后變量名與值名
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
  • 設置ignore_index=False可以保留原數據的索引。
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
  • 設置col_level參數,可以選擇多重列索引數據來融合數據。
# 列多重索引數據
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函數是pandas自帶的,是對melt的一種補充,在特殊的寬轉長情況下更適用。

pandas.wide_to_long(df, stubnames, i, j, sep='', suffix='\d+')

  • df:[pd.dataframe],寬型數據框
  • stubnames:[str,list-like],列名中的存根名字
  • i:[str,list-like],列中的索引變量
  • j:[str],后綴的重命名
  • sep:[str,default ""],存根名與后綴之間的分隔符
  • suffix:[str,default "\d+"],后綴
# 寬型數據
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

在數據中,A1970,B1980,A1980,B1970這幾列名字具有相同的結構,如果需要將它們分開,就可以用long_to_wide函數。

# 特定列的寬轉長
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
  • 設置stubnames,函數會根據設置的字符去數據列中匹配目標列,然后轉換為長數據
# 只轉換包含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參數設置的字符在原數據框的列中無法找到,則返回空數據框。

# 列名中不存在C字符,返回空數據框
pd.wide_to_long(s_df,stubnames=['C',],j='year',i='x')
Empty DataFrame
Columns: [B1970, y, A1980, B1980, A1970, C]
Index: []
  • 參數i可以設置為多列,返回多個索引。
# 設置多索引
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
  • 參數sep表示分隔符,默認"",可以根據實際情況設置。
# 寬型數據(-分隔符)
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

數據中列名的分隔符為-,則轉換的時候需要設置sep='-'

# 設置sep參數
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
  • 參數suffix表示后綴,默認是"\d+",是正則表達式,表示匹配數字,可以根據實際情況替換。
# 寬型數據
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

長轉寬

長型數據轉為寬型數據可以通過透視的功能實現,類似于excel中的透視表功能。在pandas中用pivot方法實現。

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],透視的值
# 長型數據
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列作為透視的列,里面的元素會展開成新數據框的列,baz作為透視的值,填充在新數據框中。

# 透視數據
l_df.pivot(index='foo',columns='bar',values='baz')
bar  A  B  C
foo         
one  1  2  3
two  4  5  6
  • 設置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
  • 設置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
  • 設置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
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容