将行拆分为两列,并保持其他列不变



我有一个如下的示例:

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 

有时,第二性别和年龄的价值缺失
知道吗?

您可以使用pyjanitor中的pivot_langer来重塑数据:

(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也是如此。

你也可以只使用熊猫,并使用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'])

尝试pandas melt函数。类似的东西

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

最新更新