【问题标题】:Creating new columns based on value from another column in pandas根据 pandas 中另一列的值创建新列
【发布时间】:2020-04-16 09:57:08
【问题描述】:

我有这个带有“代码”列的熊猫数据框,其中包含顺序分层代码。我的目标是使用每个层次级别代码及其名称创建新列,如下所示:

原始数据:

    Code    Name
0   A       USA
1   AM      Massachusetts
2   AMB     Boston
3   AMS     Springfield
4   D       Germany
5   DB      Brandenburg
6   DBB     Berlin
7   DBD     Dresden

我的目标:

Code    Name           Level1   Level1Name      Level2  Level2Name      Level3      Level3Name
0   A   USA             A           USA          AM     Massachusetts   AMB         Boston
1   AM  Massachusetts   A           USA          AM     Massachusetts   AMB         Boston
2   AMB Boston          A           USA          AM     Massachusetts   AMB         Boston
3   AMS Springfield     A           USA          AM     Massachusetts   AMS         Springfiled
4   D   Germany         D           Germany      DB     Brandenburg     DBB         Berlin
5   DB  Brandenburg     D           Germany      DB     Brandenburg     DBB         Berlin
6   DBB Berlin          D           Germany      DB     Brandenburg     DBB         Berlin
7   DBD Dresden         D           Germany      DB     Brandenburg     DBD         Dresden

我的代码:

import pandas as pd
df = pd.read_excel(r'/Users/BoBoMann/Desktop/Sequence.xlsx')
df['Length']=test.Code.str.len() ## create a column with length of each cell in Code
df['Level1']=test.Code.str[:1]   ## create the first level using string indexing
df['Level1Name'] = df[df['Length']==1]['Name']
df.head() ## This yields:



Code    Name          Length    Level1  Level1Name
0   A       USA             1         A     USA
1   AM      Massachusetts   2         A     NaN
2   AMB     Boston          3         A     NaN
3   AMS     Springfield     3         A     NaN
4   D       Germany         1         D     Germany
5   DB      Brandenburg     2         D     NaN
6   DBB     Berlin          3         D     NaN
7   DBD     Dresden         3         D     NaN

对于我目前的方法,如何在 Level1Name 列中将这些 NaN 分别转换为 USA 和 Germany?

一般来说,有没有更好的方法来实现我为每个分层层创建列并将它们与另一列中各自的名称相匹配的目标?

【问题讨论】:

  • 要回答您关于将这些 NaN 转换为美国和德国的问题,您可以使用 ffill 像这样 df['Level1Name'].ffill()。但是,我在下面提供了一种不同的方法。
  • 我很困惑为什么所有Springfield和Dresden都没有4级,你能解释一下为什么
  • @anky_91:Springfield 和 Dresden 没有第 4 级,因为它们的代码长度仍然是 3。这是根据会计结构建模的,其中每个附加字母代表一个层次结构。与德累斯顿和斯普林菲尔德的情况一样,同一层可能有不同的分支——希望能回答你的问题

标签: pandas dataframe python-3.6 hierarchical


【解决方案1】:

IIUC,让我们使用这个代码:

df['Codes'] = [[*i] for i in df['Code']]
df_level = df['Code'].str.extractall('(.)')[0].unstack('match').bfill().cumsum(axis=1)
s_map = df.explode('Codes').drop_duplicates('Code', keep='last').set_index('Code')['Name']
df_level.columns = [f'Level{i+1}' for i in df_level.columns]
df_level_names =  pd.concat([df_level[i].map(s_map) for i in df_level.columns], 
                            axis=1, 
                            keys=df_level.columns+'Name')
df_out = df.join([df_level, df_level_names]).drop('Codes', axis=1)
df_out

输出:

  Code           Name Level1 Level2 Level3 Level1Name     Level2Name   Level3Name
0    A            USA      A     AM    AMB        USA  Massachusetts       Boston
1   AM  Massachusetts      A     AM    AMB        USA  Massachusetts       Boston
2  AMB         Boston      A     AM    AMB        USA  Massachusetts       Boston
3  AMS    Springfield      A     AM    AMS        USA  Massachusetts  Springfield
4    D        Germany      D     DB    DBB    Germany    Brandenburg       Berlin
5   DB    Brandenburg      D     DB    DBB    Germany    Brandenburg       Berlin
6  DBB         Berlin      D     DB    DBB    Germany    Brandenburg       Berlin
7  DBD        Dresden      D     DB    DBD    Germany    Brandenburg      Dresden

解释:

  • 将字符串解压缩到创建“代码”列的字符列表中
  • 使用extractall 和正则表达式. 创建“LevelX”列以获得 单个字符,然后是 bfill NaN 和 cumsum 沿行到 创建“LevelX”列
  • 通过在“代码”上调用 explode 创建一个 pd.Series 以与 map 一起使用 上面的列创建和drop_duplicates 保留最后一个值 “代码”,然后在“代码”上 set_index 并将“名称”列保留为 创建“s_map”。
  • 重命名 df_level 列以获取 Level1 而不是 Level0。
  • 使用pd.concat 与map df_level 列的列表理解 df_level_names 使用 s_map。另外,使用keys 参数重命名 新列并附加“名称”
  • 使用join 将df 与df_levels 和df_level_names 连接,然后使用drop 'Codes' 列,创建所需的输出。

【讨论】:

  • @BoBoMann 这个答案对你有帮助吗?
  • @anky_91 是的,很大程度上取决于您回答问题的时间。我只是喜欢研究有趣的问题。
  • @Scott Boston:抱歉,我花了一点时间才回复。起初,我不知道为什么explode 功能不起作用,我花了很长时间才意识到我使用的是pandas 0.22 版本而不是0.25。一旦我更新了我的 jupyter 和 pandas,你的代码就会完美运行。非常感谢!
  • @Scott Boston:顺便问一下,有没有办法按照“我的目标”部分中的说明,按照 Level1、Level1Name、Level2、Level2Name 等的顺序排列 df_out 中的列名.该数据以会计结构为模型,最多可有 20 个级别。谢谢!
  • 当然。将 sort_index 与 axis=1 一起使用,它将按字母顺序对它们进行排序。您将所有不想排序的列移动到索引中,然后使用 axis=1 的 sort_index 基本上对列进行排序,然后使用 reset_index 将这些其他列从索引中带回数据框。
猜你喜欢
  • 2022-10-15
  • 1970-01-01
  • 1970-01-01
  • 2021-12-02
  • 2022-08-12
  • 1970-01-01
  • 2023-01-04
  • 1970-01-01
  • 2018-03-14
相关资源
最近更新 更多