如何使用 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
因为你的列比 Cycle
和 Type
多,你不能简单地使用转置,而是需要堆叠 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 将删除带有后缀的列名称的重复项。如果这不是您想要的,您应该提供一个可重现的示例 ;)
然后从类型中解开类别,将 Types
从 Category
后缀拆分为 pd.wide_to_long
将 Types
拉入索引,然后重置索引:
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 中,但这个概念仍然很重要)。
我正在努力重塑 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
因为你的列比 Cycle
和 Type
多,你不能简单地使用转置,而是需要堆叠 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 将删除带有后缀的列名称的重复项。如果这不是您想要的,您应该提供一个可重现的示例 ;)
然后从类型中解开类别,将 Types
从 Category
后缀拆分为 pd.wide_to_long
将 Types
拉入索引,然后重置索引:
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 中,但这个概念仍然很重要)。