【问题标题】:Split row by two columns and keep other columns the same将行分成两列并保持其他列相同
【发布时间】:2021-04-19 22:52:29
【问题描述】:

我有一个如下示例:

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 

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

【问题讨论】:

  • 在第一个表中,John 没有Age_2 或Gender_2。
  • 有时,第二性别和年龄存在缺失值。

标签: python pandas dataframe data-manipulation


【解决方案1】:

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

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

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

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

【讨论】:

  • 如果我的姓名、性别和年龄列没有相同的模式。我怎样才能做到这一点?另外,如果数据框中有很多列,是否有任何有效的方法可以传递给index?
  • 请分享一个示例,预期输出@PeterChen
  • 快速问题:是否也可以将列Unique_Col 操作为Key_02_N1 和Key_02_N2?
  • 不确定我理解@PeterChen,你能解释得更好吗?一个例子会有所帮助
  • 啊……这就像一个全新的问题。你介意创建一个新问题并联系我吗?我(和社区中的其他人)将尝试解决它。另外,请解释Unique_Col中N1和N2后缀的逻辑
【解决方案2】:

创建两个包含cols1 和cols2 列的日期框(参见代码中的值)。

在第二个数据框中,删除所有Name_x、Gender_x、Age_x 为nan 的值,这意味着第二个名称不存在。 将两个数据帧中的 Name_x、Gender_x、Age_x 重命名为 Name_new、Gender_new、Age_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'])

【讨论】:

    【解决方案3】:

    试试 pandas 的融化功能。类似的东西

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

    【讨论】:

    • 你检查输出了吗?
    猜你喜欢
    • 2021-11-19
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 2021-12-21
    • 2023-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多