从数据框创建面板数据

Create panel data from a dataframe

我在这里找不到解决我的问题的方法,希望你能解决。这是我当前的数据框:

| Index | Col_1_data | Col_2_data | Col_3_data | Col_1_new_data | Col_2_new_data | Col_3_new_data |
|   1   |     a      |     d      |     g      |     j          |     m          |     p          |
|   2   |     b      |     e      |     h      |     k          |     n          |     q          |
|   3   |     c      |     f      |     i      |     l          |     o          |     r          |

我的想法是将其融化,使其看起来像这样:

| Index | data | new_data | id_col |
|   1   |    a |     j    | Col_1  |   
|   2   |    b |     k    | Col_1  |  
|   3   |    c |     l    | Col_1  |
|   1   |    d |     m    | Col_2  |
|   2   |    e |     n    | Col_2  |
|   3   |    f |     o    | Col_2  |
....etc....

所以让它成为一个面板但没有任何 ID 列,而是每列相同的部分字符串(例如 Col_1、Col_2 等)有没有办法做它 'pythonically' 还是我需要循环和堆叠?

这是一种方法,但也许还有更有效的方法。

您可以根据列是否为 'new' 将数据集分成两部分,然后使用 pd.melt with pd.concat.

# Create an index column (if not exists already)
df['index']=np.arange(len(df))+1

# melt both datasets and concat together
out = pd.concat([pd.melt(pd.concat([df.filter(like='new'),df[['index']]],axis=1),
                         id_vars='index',var_name=['id_col']).rename({'value':'data'},
                                                                     axis=1).drop(['id_col'],axis=1),
                 pd.melt(df[[i for i in df.columns if 'new' in i or 'index' in i]],
                         id_vars='index',var_name=['id_col']).rename({'value':'new_data'},
                                                                     axis=1)],
                axis=1)

# Remove the '_new_data' from the 'id_col'
out['id_col'] = out['id_col'].str.replace('_new_data','')

# Rearrange the columns to match your output
out = out[['index','data','new_data','id_col']]

打印:

   index data new_data id_col
0      1    a        j  Col_1
1      2    b        k  Col_1
2      3    c        l  Col_1
3      1    d        m  Col_2
4      2    e        n  Col_2
5      3    f        o  Col_2
6      1    g        p  Col_3
7      2    h        q  Col_3
8      3    i        r  Col_3

最后两个步骤只需要精确地达到您想要的结果。

另一个不太好的方法 -

import pandas as pd
import numpy as np

df= pd.read_csv('test.csv')

col1 = ['Index', 'Col_1_data', 'Col_2_data', 'Col_3_data']
col2 =  ['Index', 'Col_1_new_data', 'Col_2_new_data', 'Col_3_new_data']
df1  = df[col1].transpose()
df2 = df[col2]
df2 = df2.rename(columns= dict(zip(col2,col1))).transpose()
def update_header(df):
    new_header = df.iloc[0] #grab the first row for the header
    df = df[1:] #take the data less the header row
    df.columns = new_header 
    return df
    
df1 = update_header(df1)
df2 = update_header(df2)
df1['data'] = df1[df1.columns.values].values.tolist()
df2['new_data'] = df2[df2.columns.values].values.tolist()
merged_df = df1.merge(df2,left_index=True, right_index=True)
merged_df = merged_df[['data', 'new_data']]
final_df = merged_df.apply(pd.Series.explode).reset_index()

输出-

Index   index   data    new_data
0   Col_1_data  a   j
1   Col_1_data  b   k
2   Col_1_data  c   l
3   Col_2_data  d   m
4   Col_2_data  e   n
5   Col_2_data  f   o
6   Col_3_data  g   p
7   Col_3_data  h   q
8   Col_3_data  i   NaN