按两列拆分行并保持其他列相同

Split row by two columns and keep other columns the same

我有如下示例:

col1  col2  Name_1  Gender_1   Age_1  I#2_Name  I#2_Gender   I#2_Age   Unique_Col
A1      50     Amy         F    20         NaN         NaN       NaN       Key_01
A2      20    Judy         F    35        Andy           M        37       Key_02
A3      10   James         M    45       Alice           F        45       Key_03
A4     150     Sam         M    23         NaN         NaN       NaN       Key_04  
A5     200   Annie         F    40        John         NaN       NaN       Key_05 

如果有第二个名字,我想将数据框从一行拆分为两行。

col1  col2  Name_new  Gender_new   Age_new        Unique_Col
A1      50     Amy         F            20         Key_01_N1
A2      20    Judy         F            35         Key_02_N1
A2      20    Andy         M            37         Key_02_N2
A3      10   James         M            45         Key_03_N1
A3      10   Alice         F            45         Key_03_N2
A4     150     Sam         M            23         Key_04_N1  
A5     200   Annie         F            40         Key_05_N1 
A5     200    John       NaN           NaN         Key_05_N2 

有时,第二性别和年龄中存在缺失值。
有什么想法吗?

试试 pandas 融化功能。像

pd.melt(df, id_vars = ['Name_1','Name_2'])

您可以使用 pivot_longer from pyjanitor 重塑数据:

(df.pivot_longer(index = ['col1', 'col2', 'Unique_Col'], 
                 names_to = ['Name_new', 'Gender_new', 'Age_new'],  
                 names_pattern = ['Name', 'Gender', 'Age'],
                 sort_by_appearance = True)
)
 
  col1  col2 Unique_Col Name_new Gender_new  Age_new
0   A1    50     Key_01      Amy          F     20.0
1   A1    50     Key_01      NaN        NaN      NaN
2   A2    20     Key_02     Judy          F     35.0
3   A2    20     Key_02     Andy          M     37.0
4   A3    10     Key_03    James          M     45.0
5   A3    10     Key_03    Alice          F     45.0
6   A4   150     Key_04      Sam          M     23.0
7   A4   150     Key_04      NaN        NaN      NaN
8   A5   200     Key_05    Annie          F     40.0
9   A5   200     Key_05     John        NaN      NaN

在上面的代码中,您将新列名列表传递给 names_to。对于每个新列名,您将模式(正则表达式)传递给 names_pattern。因此,对于 Names_new,该函数将搜索包含 Name 的任何列并将所有数据拉入该列,Gender_newAge_new.[=24 也是如此=]

您也可以只使用 pandas 并使用 wide_to_long;首先对列重新排序,使 GenderNameAge 位于最前面:

new_df = df.rename(columns = lambda col: "_".join(col.split("_")[::-1]) 
                              if "#" in col else col)
new_df
  col1  col2 Name_1 Gender_1  Age_1 Name_I#2 Gender_I#2  Age_I#2 Unique_Col
0   A1    50    Amy        F     20      NaN        NaN      NaN     Key_01
1   A2    20   Judy        F     35     Andy          M     37.0     Key_02
2   A3    10  James        M     45    Alice          F     45.0     Key_03
3   A4   150    Sam        M     23      NaN        NaN      NaN     Key_04
4   A5   200  Annie        F     40     John        NaN      NaN     Key_05

让我们重塑:

(pd.wide_to_long(new_df, 
                 stubnames = ['Name', 'Gender', 'Age'], 
                 i = ['col1', 'col2', 'Unique_Col'], 
                 j = 'suffix', 
                 sep = "_", 
                 suffix = ".+")
   .droplevel("suffix")
   .reset_index()
)



  col1  col2 Unique_Col   Name Gender   Age
0   A1    50     Key_01    Amy      F  20.0
1   A1    50     Key_01    NaN    NaN   NaN
2   A2    20     Key_02   Judy      F  35.0
3   A2    20     Key_02   Andy      M  37.0
4   A3    10     Key_03  James      M  45.0
5   A3    10     Key_03  Alice      F  45.0
6   A4   150     Key_04    Sam      M  23.0
7   A4   150     Key_04    NaN    NaN   NaN
8   A5   200     Key_05  Annie      F  40.0
9   A5   200     Key_05   John    NaN   NaN

创建两个具有列 cols1cols2 的日期框(请参阅代码中的值)。

在第二个数据框中,删除所有 Name_xGender_xAge_x 均为 nan 的值,这意味着第二个名字不存在。 在两个数据框中将 Name_xGender_xAge_x 重命名为 Name_newGender_newAge_new

然后使用 pd.concat 垂直连接日期帧。

使用:

cols1 = ['col1', 'col2', 'Name_1', 'Gender_1', 'Age_1', 'Unique_Col']
cols2 = ['col1', 'col2', 'Name', 'Gender_2', 'Age_2', 'Unique_Col']

def rename_col(x):
   return x.split("_")[0] + "_new" if '_' in x else x

df1 = df[cols1].rename(rename_col, axis = 'columns')
df2 = (df[cols2]
          .dropna(subset = ['Name_2', 'Gender_2', 'Age_2'], how = 'all')
          .rename(rename_col, axis = 'columns'))

输出:

>>> out
  col1  col2 Name_new Gender_new  Age_new Unique_new
0   A1    50      Amy          F     20.0     Key_01
1   A2    20     Judy          F     35.0     Key_02
1   A2    20     Andy          M     37.0     Key_02
2   A3    10    James          M     45.0     Key_03
2   A3    10    Alice          F     45.0     Key_03
3   A4   150      Sam          M     23.0     Key_04
4   A5   200    Annie          F     40.0     Key_05
4   A5   200     John        NaN      NaN     Key_05

如果您的性别和名字没有相同的模式,则使用字典映射重命名:

cols1 = ['col1', 'col2', 'Name_1', 'Gender_1', 'Age_1', 'Unique_Col']
cols2 = ['col1', 'col2', 'I#2_Name', 'I#2_Gender', 'I#2_Age', 'Unique_Col']

new_cols = ['col1', 'col2', 'Name_New', 'Gender_New', 'Age_New', 'Unique_Col']

df1 = df[cols1].rename(dict(zip(cols1, new_cols)), axis = 'columns')
df2 = (df[cols2]
          .dropna(subset = cols2[2:5], how = 'all')
          .rename(dict(zip(cols2, new_cols)), axis = 'columns'))

out = pd.concat([df1, df2]).sort_values(by = ['col1'])