如何使用Pandas Melt将多列转换为行

时间:2019-05-13 08:17:07

标签: python pandas

我在excel中有如下数据集

   A              B       C           D         E           F        G
1                SKU                 Units                Sales
2               11/5/18  12/5/18    11/5/18   12/5/18    11/5/18   12/5/18
3 Description                       total=5   total=9    total=33  total =60
4 Nail Varnish   2345     2345          2       4          $15      $30
5 Eyeliner       2346     2345          3       5          $18      $30

我正在使用熊猫将其转换为具有以下结构的另一个excel

    Description     date          sku           Units          Sales             
0   Nail Varnish    11/5/18       2345            2            $15 
1    Eye liner      11/5/18       2346            3            $18
2   Nail Varnish    12/5/18       2345            4            $30 
3    Eye liner      12/5/18       2346            5            $30

我之前在熊猫中使用过melt函数将一列转换为行(例如,销售或单位),但我不知道它是否适用于三个多索引列。

df = pd.read_excel(filepath_name,index_col=False,usecols="A:G")
df2=pd.melt(df,id_vars=["SKU ","Units","Sales"], var_name ="Date", value_name='?)

但是我该如何一次性转换所有id vars(SKU,Units和Sales)。

2 个答案:

答案 0 :(得分:2)

创建的想法的索引是第一列,而MultiIndex的索引是前2行,因此可以使用DataFrame.stack

.as-console-wrapper { max-height: 100% !important; top: auto; }

如果excel文件中缺少第二个值,则需要进行预处理:

df = pd.read_excel(filepath_name,index_col=[0],usecols="A:G", header=[0,1])

print (df.columns)
MultiIndex(levels=[['SKU', 'Sales', 'Units'], ['11/5/18', '12/5/18']],
           codes=[[0, 0, 2, 2, 1, 1], [0, 1, 0, 1, 0, 1]])


df = df.stack().rename_axis(('Description','date')).reset_index()
print (df)
    Description     date   SKU Sales  Units
0  Nail Varnish  11/5/18  2345   $15      2
1  Nail Varnish  12/5/18  2345   $30      4
2      Eyeliner  11/5/18  2346   $18      3
3      Eyeliner  12/5/18  2345   $30      5

EDIT1:

如果只需要过滤某些列以进行重塑:

print (df)
                 SKU Unnamed: 1_level_0   Units Unnamed: 3_level_0   Sales  \
             11/5/18            12/5/18 11/5/18            12/5/18 11/5/18   
Nail Varnish    2345               2345       2                  4     $15   
Eyeliner        2346               2345       3                  5     $18   

             Unnamed: 5_level_0  
                        12/5/18  
Nail Varnish                $30  
Eyeliner                    $30 

a = df.columns.get_level_values(0)
b = df.columns.get_level_values(1)
a = a.where(~a.str.startswith('Unnamed')).to_series().ffill()
df.columns = [a, b]

print (df)
                 SKU           Units           Sales        
             11/5/18 12/5/18 11/5/18 12/5/18 11/5/18 12/5/18
Nail Varnish    2345    2345       2       4     $15     $30
Eyeliner        2346    2345       3       5     $18     $30

EDIT1:

cols = ['SKU','Units','Sales']
df = df[cols].stack().rename_axis(('Description','date')).reset_index()
print (df)
    Description     date   SKU Sales  Units
0  Nail Varnish  11/5/18  2345   $15      2
1  Nail Varnish  12/5/18  2345   $30      4
2      Eyeliner  11/5/18  2346   $18      3
3      Eyeliner  12/5/18  2345   $30      5

mux = pd.MultiIndex(levels=[['SKU ', 'Units', 'Unnamed: 0_level_0', 'Sales'], 
                            ['11/5/18', '12/5/18', 'Unnamed: 0_level_1'], 
                            ['total=5', 'total=9', 'total=33', 'total=60', 'Description', 'Unnamed: 1_level_2', 'Unnamed: 2_level_2']], codes=[[2, 0, 0, 1, 1, 3, 3], [2, 0, 1, 0, 1, 0, 1], [4, 5, 6, 1, 0, 2, 3]])

df = pd.DataFrame([range(7),range(7)], columns=mux)
print (df)
  Unnamed: 0_level_0               SKU                       Units          \
  Unnamed: 0_level_1            11/5/18            12/5/18 11/5/18 12/5/18   
         Description Unnamed: 1_level_2 Unnamed: 2_level_2 total=9 total=5   
0                  0                  1                  2       3       4   
1                  0                  1                  2       3       4   

     Sales           
   11/5/18  12/5/18  
  total=33 total=60  
0        5        6  
1        5        6  

a = df.columns.get_level_values(0)
b = df.columns.get_level_values(1)
c = df.columns.get_level_values(2)
#forward fliing missing values
a = a.where(~a.str.startswith('Unnamed')).to_series().ffill()
b = b.where(~b.str.startswith('Unnamed')).to_series().ffill()
#repalce missing values by empty string
c = c.where(~c.str.startswith('Unnamed'), '')

df.columns = [a, b, c]

#convert first column to index
df = df.set_index(df.columns[0])
df.index.name='Desc'
print (df)
        SKU            Units            Sales         
     11/5/18 12/5/18 11/5/18 12/5/18  11/5/18  12/5/18
                     total=9 total=5 total=33 total=60
Desc                                                  
0          1       2       3       4        5        6
0          1       2       3       4        5        6

答案 1 :(得分:0)

informationmelt相反。

  

而且我不知道它是否适用于三个或多个索引列。

是的,它适用于多索引列。如果列是MultiIndex,则使用col_level参数进行融化。 第一个链接中提供了示例。