如何使用 pandas 重塑特定数据列 table?

How to reshape the specific columns of data table using pandas?

我正在努力重塑 table,发现它比我想象的要复杂。

原始数据为

                                |----- Category 1----------------|----- Category 2-----------------|
         Date     ID    Cycle   Type 1   Type 2   Type 3  Type 4  Type 1   Type 2   Type 3   Type 4
0      Somedate   1      1        v1       v2      v3        v4       v5      v6      v7       v8
1      Somedate          2        v9       v10     v11       v12      v13     v14     v15      v16
2      Somedate          3        v17      v18     v19       v20      v21     v22     v23      v24
3      Somedate   2      1        c1       c2      c3        c4       c5      c6      c7       c8   
4      Somedate          2        c9       c10     c11       c12      c13     c14     c15      c16
5      Somedate          3        c17      c18     c19       c20      c21     c22     c23      c24    

我想做的是

         Date     ID     Category   Type    Cycle 1   Cycle 2   Cycle 3
0      Somedate   1         1      Type 1     v1        v9       v17
1      Somedate   1         1      Type 2     v2       v10       v18
0      Somedate   1         1      Type 3     v3       v11       v19
0      Somedate   1         1      Type 4     v4       v12       v20
0      Somedate   1         2      Type 1     v5       v13       v21
0      Somedate   1         2      Type 2     v6       v14       v22
0      Somedate   1         2      Type 3     v7       v15       v23
0      Somedate   1         2      Type 4     v8       v16       v24

并继续 ID = 2

基本思路是保留 Date 和 ID 列,扩展和转置 Categories 和 Types。

数据原来是这样的: csv file

因为你的列比 CycleType 多,你不能简单地使用转置,而是需要堆叠 Type 和旋转 Cycle。此外,它变得更加复杂,因为您有一个带有 Category 的分层索引(无论您是否认为需要,带索引的两行都是分层的)和一堆缺失的字段。

我猜你想怎么对待这一切。我用

读取了你的数据
In [28]: df = pd.read_csv('../Downloads/Whosebug.csv', header=1).rename(columns={'A1': 'A1.0', 'A4': 'A4.0', 'A7': 'A7.0', 'E0': 'E0.0', 'E1': 'E1.0'})                                               

In [29]: df['ID'].ffill(inplace=True)                                                                                                                                                                      

In [30]: df                                                                                                                                                                                                
Out[30]: 
          Date   ID  Cycle    A1.0  A4.0  A7.0    E0.0  E1.0  A1.1  A4.1  A7.1   E0.1  E1.1  A1.2  A4.2  A7.2   E0.2  E1.2  A1.3  A4.3  A7.3   E0.3  E1.3
0   2021-01-14  1.0      1   124.0     8     9     8.0    96    90     8  1235   62.0    98    90     8  1235   62.0    98    90     8  1235   62.0    98
1   2021-01-15  1.0      2   127.0    76   987     NaN    86     8     6   234    NaN   234     8     6   234    NaN   234     8     6   234    NaN   234
2   2021-01-16  1.0      3     0.3  7869     9    22.0    48     8     0     7   67.0     2     8     0     7   67.0     2     8     0     7   67.0     2
3   2021-01-17  1.0      4   809.0    89     8    89.0     0    34    23   529  651.0  6929    34    23   529  651.0  6929    34    23   529  651.0  6929
4   2021-01-18  2.0      1   245.0    65    97     5.0     3     7     7   978   75.0  7857     7     7   978   75.0  7857     7     7   978   75.0  7857
5   2021-01-19  2.0      2   744.0    76   345   768.0    78     7    76   756  675.0  7692     7    76   756  675.0  7692     7    76   756  675.0  7692
6   2021-01-20  2.0      3     3.0     4    32     NaN    34     6  3456    34   37.0    37     6  3456    34   37.0    37     6  3456    34   37.0    37
7   2021-01-21  2.0      4     7.0     7  9781     1.0     2     3    64     7   75.0    54     3    64     7   75.0    54     3    64     7   75.0    54
8   2021-01-22  3.0      1     6.0   123   854   584.0    13    46    56    54   54.0     2    46    56    54   54.0     2    46    56    54   54.0     2
9   2021-01-23  3.0      2  1515.0     3     1   146.0    14     1     6  3456    2.0    45     1     6  3456    2.0    45     1     6  3456    2.0    45
10  2021-01-24  3.0      3   412.0   461    46  1461.0  4613   146    61     1   56.0     7   146    61     1   56.0     7   146    61     1   56.0     7
11  2021-01-24  3.0      4    54.0     7   889     2.0     1    17   177   571    1.0     5    17   177   571    1.0     5    17   177   571    1.0     5

默认情况下忽略类别并利用 pandas 将删除带有后缀的列名称的重复项。如果这不是您想要的,您应该提供一个可重现的示例 ;)

然后从类型中解开类别,将 TypesCategory 后缀拆分为 pd.wide_to_longTypes 拉入索引,然后重置索引:

In [32]: df2 = pd.wide_to_long(df, stubnames=['A1', 'A4', 'A7', 'E0', 'E1'], i=['Date', 'ID', 'Cycle'], j='Category', sep='.')                                                                                   
Out[32]: 
                                  A1   A4    A7    E0  E1
Date       ID  Cycle Category                            
2021-01-14 1.0 1     0         124.0    8     9   8.0  96
                     1          90.0    8  1235  62.0  98
                     2          90.0    8  1235  62.0  98
                     3          90.0    8  1235  62.0  98
2021-01-15 1.0 2     0         127.0   76   987   NaN  86
...                              ...  ...   ...   ...  ..
2021-01-24 3.0 3     3         146.0   61     1  56.0   7
               4     0          54.0    7   889   2.0   1
                     1          17.0  177   571   1.0   5
                     2          17.0  177   571   1.0   5
                     3          17.0  177   571   1.0   5

In [41]: df2.columns.rename('Type', inplace=True)

In [48]: df3 = df2.stack().reset_index()                                                                                                                                                                         
Out[48]: 
           Date   ID  Cycle  Category Type      0
0    2021-01-14  1.0      1         0   A1  124.0
1    2021-01-14  1.0      1         0   A4    8.0
2    2021-01-14  1.0      1         0   A7    9.0
3    2021-01-14  1.0      1         0   E0    8.0
4    2021-01-14  1.0      1         0   E1   96.0
..          ...  ...    ...       ...  ...    ...
230  2021-01-24  3.0      4         3   A1   17.0
231  2021-01-24  3.0      4         3   A4  177.0
232  2021-01-24  3.0      4         3   A7  571.0
233  2021-01-24  3.0      4         3   E0    1.0
234  2021-01-24  3.0      4         3   E1    5.0

现在这开始看起来像一个合适的 DataFrame。这被称为 long format。要将其转换为您想要的输出,您只需要一个数据透视操作

In [52]: df3.pivot(index=['Date', 'ID', 'Category', 'Type'], columns='Cycle', values=0)                                                                                                                    
Out[52]: 
Cycle                             1   2      3      4
Date       ID  Category Type                         
2021-01-14 1.0 0        A1    124.0 NaN    NaN    NaN
                        A4      8.0 NaN    NaN    NaN
                        A7      9.0 NaN    NaN    NaN
                        E0      8.0 NaN    NaN    NaN
                        E1     96.0 NaN    NaN    NaN
...                             ...  ..    ...    ...
2021-01-24 3.0 3        A1      NaN NaN  146.0   17.0
                        A4      NaN NaN   61.0  177.0
                        A7      NaN NaN    1.0  571.0
                        E0      NaN NaN   56.0    1.0
                        E1      NaN NaN    7.0    5.0

在您提供的示例中,没有在任何给定日期测量一堆周期,这就是您所有 NaN 的来源。默认情况下,堆栈也会丢弃缺失值,您可能需要对其进行调整,类别从 0 开始计数,可能还需要调整一些小细节。

我希望这能让您走上正确的道路。你的问题本身是通过一个简单的数据透视操作解决的,但是为了让你 csv 成为实际可用的东西而进行的数据争论并不是微不足道的。您可能想阅读一些关于 tidy data 的内容(link 在 R 中,但这个概念仍然很重要)。