以双行标题为深度数据框的枢轴宽数据框

pivot wide dataframe with double row heading to deep dataframe

我有信心我可以蒙混过关,甚至可能找到一些优雅的东西,但我很好奇其他人会如何解决这个问题:

我想采用这样的数据框:

| a1   | b1   | c1  |
| ---- | ---- | --- |
| a2   | b2   | c2  |
| ---  | ---  | --- |
| v1   | v2   | v3  |
| ...  | ...  | ... |
| v100 | v101 | v102|

并转换为这样的数据框,其中 x* 是自定义的 headers,我可以提供以下列表:

| x1  | x2  | x3   |
| --- | --- | ---- |
| a1  | a2  | v1   |
| ... | ... | ...  |
| a1  | a2  | v100 |
| b1  | b2  | v2   |
| ... | ... | ...  |
| b1  | b2  | v101 |
| c1  | c2  | v3   |
| ... | ... | ...  |
| c1  | c2  | v102 |

上下文是需要转换的 CSV 导入,但有两行 headers,在这种情况下将变为 x1x2

非常感谢任何提示或建议!同样,有信心可以用一些肘部油脂来做到这一点,但我想提高我的旋转和 index-ing 直觉。

更新:根据评论,这里是源和目标数据框示例:

# source dataframe
df1 = pd.DataFrame(columns=['a1','b1','c1'], data=[['a2','b2','c2'],['v1','v2','v3'],['v100','v101','v102']])

"""
In [14]: df1                                                                                                                                                    
Out[14]: 
     a1    b1    c1
0    a2    b2    c2
1    v1    v2    v3
2  v100  v101  v102
"""

# target dataframe (where "x*" headers will be provided)
df2 = pd.DataFrame(columns=['x1','x2','x3'], data=[['a1','a2','v1'],['a1','a2','v100'],['b1','b2','v2'],['b1','b2','v101'],['c1','c2','v3'],['c1','c2','v102']])

"""
In [16]: df2                                                                                                                                                    
Out[16]: 
   x1  x2    x3
0  a1  a2    v1
1  a1  a2  v100
2  b1  b2    v2
3  b1  b2  v101
4  c1  c2    v3
5  c1  c2  v102
"""

如果我正确理解了您的初始 DataFrame,我可以这样创建它:

import pandas as pd
n = 100
listA = [f'V{x}' for x in range(1,n+1)]
listA.insert(0,("a1"))
listA.insert(1,"a2")
listB = [f'V{x}' for x in range(n+1,2*n+1)]
listB.insert(0,("b1"))
listB.insert(1,"b2")
listC = [f'V{x}' for x in range(2*n+1,3*n+1)]
listC.insert(0,("c1"))
listC.insert(1,"c2")
data = [listA, listB, listC]
df = pd.DataFrame(data).T

现在您创建一个包含三列的空 DataFrame:“x1”、“x2”、“x3”:

newDF = pd.DataFrame( columns=["x1", "x2", "x3"])

然后在 for 循环中添加行,选择元素在原始 DataFrame 中的位置:

for i in range(3):
    for j in range(n):
        row = [df.iloc[0][i],df.iloc[1][i], df.iloc[j+2][i]]
        newDF.loc[len(newDF.index)] = row

希望对你有用。

更新
根据您的更新:
您从 header 列创建一个 row0 :

row0 = pd.DataFrame(list(df1.columns)).T

您更改 row0 和 df1 的列名称:

row0.columns = ["x1","x2","x3"]
df1.columns = ["x1","x2","x3"]

您在 dnew DataFrame 中连接 row0 和 df1:

dnew = pd.concat([row0, df])

您创建 df2 :

df2 = pd.DataFrame(columns=["x1", "x2", "x3"])
for i in range(len(dnew.columns)):
    for j in range(len(dnew)-2):
        row = [dnew.iloc[0][i],dnew.iloc[1][i], dnew.iloc[j+2][i]]
        df2.loc[len(df2)] = row

这是multi-step整形:

(df1.T
 .set_index(0, append=True)
 .rename_axis(['x1', 'x2'])
 .stack()
 .droplevel(-1)
 .reset_index(name='x3')
)

输出:

   x1  x2    x3
0  a1  a2    v1
1  a1  a2  v100
2  b1  b2    v2
3  b1  b2  v101
4  c1  c2    v3
5  c1  c2  v102