美文网首页数据科学
python--pandas长宽数据变形

python--pandas长宽数据变形

作者: FTDdata | 来源:发表于2021-04-23 11:20 被阅读0次

    长型数据(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
    

    相关文章

      网友评论

        本文标题:python--pandas长宽数据变形

        本文链接:https://www.haomeiwen.com/subject/mmzlhltx.html