繁体   English   中英

如何使用melt()将pandas DataFrame重新整形为列表,从交叉表列创建索引并在其位置创建新变量?

[英]How can I use melt() to reshape a pandas DataFrame to a list, creating an index from a crosstab column and creating a new variable in its place?

我有一个数据矩阵29523行x 503 cols,其中3 cols是索引(下面是例如子集)。

IDX1|  IDX2  | IDX3 | 1983 Q4   |  X  | Y |  Z  |1984 Q1 |   X  | Y | Z 
---------------------------------------------------------------------------
A   |   A1   |  Q   |   10      |  A  | F | NaN | 110    |   A  | F | NaN
A   |   A2   |  Q   |   20      |  B  | C | 40  | 120    |   B  | C | 240
A   |   A3   |  Q   |   30      |  A  | F | NaN | 130    |   A  | F | NaN
A   |   A4   |  Q   |   40      |  B  | C | 80  | 140    |   B  | C | 280
A   |   A5   |  Q   |   50      |  A  | F | NaN | 150    |   A  | F | NaN
A   |   A6   |  Q   |   60      |  B  | F | 120 | 160    |   B  | F | 320

我将其读入DataFrame其中包含:

>>> df = pd.read_csv(C:\filename.csv, low_memory=False, mangle_dupe_cols=False)

然后使用pandas.melt()来旋转数据:

df1 = pd.melt(df, id_vars=['IDX1', 'IDX2', 'IDX3'], var_name='ValueType',
              value_name = 'Value')

我也尝试过stack()但是这里说得更好melt()

IDX1    |   IDX2    |   IDX3    |   ValueType   |   Value
---------------------------------------------------------------
A       |   A1      |   Q       |   1983 Q4     |   10
A       |   A1      |   Q       |   X           |   A
A       |   A1      |   Q       |   Y           |   F
A       |   A1      |   Q       |   Z           |   NaN
A       |   A1      |   Q       |   1984 Q1     |   110
A       |   A1      |   Q       |   X           |   A
A       |   A1      |   Q       |   Y           |   F
A       |   A1      |   Q       |   Z           |   NaN
A       |   A2      |   Q       |   1983 Q4     |   20
A       |   A2      |   Q       |   X           |   B
A       |   A2      |   Q       |   Y           |   C
A       |   A2      |   Q       |   Z           |   40

选项mangle_dupe_colsread_csv如果True会放置一个.int对所有后缀ValueType是重复秒。 这并不理想,但如果没有它,就无法将变量的值链接到正确的时间段。

我更愿意做的是将Period (1984 Q1)作为ValueType ,给Period对应的Value一个变量'W'并让每个句点形成IDX一部分,如下所示:

IDX1    |   IDX2    |   IDX3 | IDX4    |    ValueType   |   Value
---------------------------------------------------------------
A       |   A1      |   Q    |  1983 Q4|    W           |   10
A       |   A1      |   Q    |  1983 Q4|    X           |   A
A       |   A1      |   Q    |  1983 Q4|    Y           |   F
A       |   A1      |   Q    |  1983 Q4|    Z           |   NaN
A       |   A1      |   Q    |  1984 Q1|    W           |   110
A       |   A1      |   Q    |  1984 Q1|    X           |   A
A       |   A1      |   Q    |  1984 Q1|    Y           |   F
A       |   A1      |   Q    |  1984 Q1|    Z           |   NaN
A       |   A2      |   Q    |  1983 Q4|    W           |   20
A       |   A2      |   Q    |  1983 Q4|    X           |   B
A       |   A2      |   Q    |  1983 Q4|    Y           |   C
A       |   A2      |   Q    |  1983 Q4|    Z           |   40

以上是否可能与熊猫或numpy?

我的最终DataFrame将是14,761,500行x 6 cols。

特定

In [189]: df
Out[189]: 
  IDX1 IDX2 IDX3  1983 Q4  X  Y    Z  1984 Q1 X.1 Y.1  Z.1
0    A   A1    Q       10  A  F  NaN      110   A   F  NaN
1    A   A2    Q       20  B  C   40      120   B   C  240
2    A   A3    Q       30  A  F  NaN      130   A   F  NaN
3    A   A4    Q       40  B  C   80      140   B   C  280
4    A   A5    Q       50  A  F  NaN      150   A   F  NaN
5    A   A6    Q       60  B  F  120      160   B   F  320

我们先设置['IDX1', 'IDX2', 'IDX3']作为索引。

df = df.set_index(['IDX1', 'IDX2', 'IDX3'])

其他列具有周期性质量; 我们希望将每4列作为一个组来处理 这种“作为一个组进行处理”的想法自然会导致为列索引分配新的索引级别; 一些值,每4列相同。 这将是理想的:

               1983 Q4            1984 Q1           
                     W  X  Y    Z       W  X  Y    Z
IDX1 IDX2 IDX3                                      
A    A1   Q         10  A  F  NaN     110  A  F  NaN
     A2   Q         20  B  C  240     120  B  C  240
     A3   Q         30  A  F  NaN     130  A  F  NaN
     A4   Q         40  B  C  280     140  B  C  280
     A5   Q         50  A  F  NaN     150  A  F  NaN
     A6   Q         60  B  F  320     160  B  F  320

我们可以通过构建MultiIndex并将其分配给df.columnsdf.columns

columns = [col for col in df.columns if col[0] not in set(list('XYZ'))]
df.columns = pd.MultiIndex.from_product([columns, list('WXYZ')])

现在可以通过调用df.stack将列级别移动到行索引中来获得所需的长格式DataFrame:

df.columns.names = ['IDX4', 'ValueType']
series = df.stack(['IDX4', 'ValueType'], dropna=False)

另请注意,当mangle_dupe_cols=False ,重复的列XYZ 会被覆盖 所以你使用mangle_dupe_cols=False丢失了数据。 例如,当您使用mangle_dupe_cols=False ,无论周期如何,最后一行的Z值都会分配给每个Z列。

所以我们必须使用mangle_dupe_cols=True ,(或者只是保留它,因为这是默认值)并相应地调整代码。 幸运的是,这并不难,因为我们无论如何都要将df.columns重新分配给自定义构建的MultiIndex。


把它们放在一起:

import numpy as np
import pandas as pd
df = pd.read_table('data', sep=r'\s*[|]\s*')
df = df.set_index(['IDX1', 'IDX2', 'IDX3'])
columns = [col for col in df.columns if col[0] not in set(list('XYZ'))]
df.columns = pd.MultiIndex.from_product([columns, list('WXYZ')])
df.columns.names = ['IDX4', 'ValueType']
series = df.stack(['IDX4', 'ValueType'], dropna=False)
print(series.head())

产量

IDX1  IDX2  IDX3  IDX4     ValueType
A     A1    Q     1983 Q4  W             10
                           X              A
                           Y              F
                           Z            NaN
                  1984 Q1  W            110
dtype: object

请注意,由于我们删除了所有列级别,因此结果是一个系列。 如果您想要一个包含6列的DataFrame,那么我们应该跟进:

series.name = 'Value'
df = series.reset_index()
print(df.head())

产量

  IDX1 IDX2 IDX3     IDX4 ValueType Value
0    A   A1    Q  1983 Q4         W    10
1    A   A1    Q  1983 Q4         X     A
2    A   A1    Q  1983 Q4         Y     F
3    A   A1    Q  1983 Q4         Z   NaN
4    A   A1    Q  1984 Q1         W   110
...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM