【问题标题】:Follow up - Creating new columns based on value from another column in pandas跟进 - 根据 pandas 中另一列的值创建新列
【发布时间】:2019-12-27 13:31:00
【问题描述】:

跟进我之前的问题 -- Creating new columns based on value from another column in pandas

我现在的目标是:

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

以 Scott Boston 的代码为基础,到目前为止:

match   0   1   2
0       A   A   A
1       A   AM  AM
2       A   AM  AMB
3       A   AM  AMS
4       D   D   D
5       D   DB  DB
6       D   DB  DBB
7       D   DB  DBD

我的方法是遍历每一列并删除与该列中的其余值长度不同但似乎无法弄清楚逻辑的行。

示例代码:

df = pd.read_excel(r'/Users/BoBoMann/Desktop/Sequence.xlsx')

df['Codes'] = [[*i] for i in df['Code']]
df_level = df['Code'].str.extractall('(.)')[0].unstack('match').fillna('').cumsum(axis=1)
df_level

感谢您的帮助!

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    让我们试试吧:

    df['Codes'] = [[*i] for i in df['Code']]
    df_level = df['Code'].str.extractall('(.)')[0].unstack('match', fill_value='')
    df_level = df_level.cumsum(axis=1).mask(df_level == '')
    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    NaN    NaN        USA            NaN          NaN
    1   AM  Massachusetts      A     AM    NaN        USA  Massachusetts          NaN
    2  AMB         Boston      A     AM    AMB        USA  Massachusetts       Boston
    3  AMS    Springfield      A     AM    AMS        USA  Massachusetts  Springfield
    4    D        Germany      D    NaN    NaN    Germany            NaN          NaN
    5   DB    Brandenburg      D     DB    NaN    Germany    Brandenburg          NaN
    6  DBB         Berlin      D     DB    DBB    Germany    Brandenburg       Berlin
    7  DBD        Dresden      D     DB    DBD    Germany    Brandenburg      Dresden
    

    【讨论】:

    • 再次感谢您提供出色的解决方案。可以解释一下cumsum之后mask函数的用法吗?为什么一定要按这个顺序?
    • 掩码方法采用 ('') 空字符串,并将它们转换为 NaN。空字符串是前一个语句的乘积,其中 fill_value='' 在 unstack 中。所以,我们对所有的掩码求和,或者在字符串为空的地方设置 null 值。
    • 希望您度过了一个愉快的假期。谢谢!现在一切都尘埃落定了。
    【解决方案2】:

    此方法使用apply 和函数:

    import pandas as pd
    l = ['A', 'AM', 'AMB', 'AMS', 'D', 'DB', 'DBB', 'DBD']
    df = pd.DataFrame(l).rename(columns={0:'code'})
    
    def level2(col):
      if len(col) == 1:
        return ''
      elif len(col) >= 2:
        return col[:2]
    
    def level3(col):
      if len(col) <= 2:
        return ''
      elif len(col) > 2:
        return col[:3]
    
    df['Level1'] = df['code'].apply(lambda col: col[0])
    df['Level2'] = df['code'].apply(level2)
    df['Level3'] = df['code'].apply(level3)
    
    print(df)
    

    输出:

      code Level1 Level2 Level3
    0    A      A              
    1   AM      A     AM       
    2  AMB      A     AM    AMB
    3  AMS      A     AM    AMS
    4    D      D              
    5   DB      D     DB       
    6  DBB      D     DB    DBB
    7  DBD      D     DB    DBD
    

    这些函数也可以重构为一个函数,但你明白了要点。我建议使用 apply 而不是其他 pandas 方法,因为 apply 更容易记住和自定义。希望这会有所帮助。

    【讨论】:

    • 这绝对有帮助。但是,此数据是在另一个数据集之后的模型,其中最多可以有 20 层。非常感谢您的建议,我现在肯定可以看到自己在其他领域使用 apply 功能。
    【解决方案3】:

    我采用了不同的方法:循环遍历代码的长度,假设您不会有太多的级别。

    import pandas as pd
    df=pd.DataFrame({
        'Code':['A','AM','AMB'],
        'Name':['USA','Massachusetts',"Boston"]
    })
    # prepare
    res=pd.DataFrame({
        'Code':[]
    })
    df['len']=df['Code'].str.len()
    cols=[]
    for x in range(df['len'].max()):
        dfX=df[df['len']==x+1].copy()
        dfX['prefix']=dfX['Code'].str.slice(stop=x)
    
        dfX=dfX.merge(res,how='left',left_on='prefix',right_on='Code')
    
        dfX[f'Level{x+1}']=dfX['Code_x']
        dfX[f'Level{x+1}Name']=dfX['Name']
        dfX[f'Code']=dfX['Code_x']
        cols+=[f'Level{x+1}',f'Level{x+1}Name']
        res=res.append(dfX[['Code']+cols],sort=False)
    
    res
    
    Code    Level1  Level1Name  Level2  Level2Name  Level3  Level3Name
    0   A   A   USA NaN NaN NaN NaN
    0   AM  A   USA AM  Massachusetts   NaN NaN
    0   AMB A   USA AM  Massachusetts   AMB Boston
    

    想法是首先将级别 1 添加到查找表中;然后2级和3级... 代码看起来很丑,但希望很容易理解。

    【讨论】:

    • 感谢您的代码。这很容易遵循。然而,这个数据集是根据一个更大的数据集建模的,其中大约有 20 层。
    猜你喜欢
    • 2020-04-16
    • 2022-10-15
    • 1970-01-01
    • 2021-12-02
    • 2022-08-12
    • 1970-01-01
    • 2023-01-04
    • 1970-01-01
    • 2018-03-14
    相关资源
    最近更新 更多