【问题标题】:Pandas Multiindex Rows and Columns: Replace NaN with Value from Matching RowPandas 多索引行和列:用匹配行中的值替换 NaN
【发布时间】:2016-10-23 06:55:46
【问题描述】:

鉴于以下情况:

import pandas as pd
import numpy as np
df=pd.DataFrame({'County':['A','B','A','B','A','B','A','B','A','B'],
                'Hospital':['a','b','e','f','i','j','m','n','b','r'],
                'Enrollment':[44,55,95,54,81,54,89,76,1,67],
                'Year':['2012','2012','2012','2012','2012','2013',
                        '2013','2013','2013','2013']})
d2=pd.pivot_table(df,index=['County','Hospital'],columns=['Year'])#.sort_columns

d2

        Enrollment
       Year     2012    2013
County Hospital         
A       a       44.0    NaN
        b       NaN     1.0
        e       95.0    NaN
        i       81.0    NaN
        m       NaN     89.0
B       b       55.0    NaN
        f       54.0    NaN
        j       NaN     54.0
        n       NaN     76.0
        r       NaN     67.0

如果像“b”这样的医院不止一次存在并且没有上一年的数据(“b”的第一次出现),我想为另一行分配上一年的 Enrollment 值('b') 并删除不包含第一年数据的'b'行,如下所示:

        Enrollment
       Year     2012    2013
County Hospital         
A       a       44.0    NaN
        b       55.0    1.0
        e       95.0    NaN
        i       81.0    NaN
        m       NaN     89.0
B       f       54.0    NaN
        j       NaN     54.0
        n       NaN     76.0
        r       NaN     67.0

到目前为止,我可以识别重复的行并删除,但我只是坚持用需要的值替换 NaN:

  1. 重置索引后识别重复医院:

    d2=d2.reset_index()    
    d2['dup']=d2.duplicated('Hospital',keep=False)
    
  2. 标记,删除最近一年没有数据的重复医院:

     Hospital=d2.columns.levels[0][1]
    
     Y1=d2.columns.levels[1][0]
    
     Y2=d2.columns.levels[1][1]
    
     d2['Delete']=np.nan
    
     d2.loc[(pd.isnull(d2.Enrollment[Y2]))&(d2['dup']==True),'Delete']='Yes'
    
  3. 保留所有要删除的行:

     d2=d2.loc[d2['Delete']!='Yes']
    

【问题讨论】:

    标签: python-3.x pandas filter group-by multi-index


    【解决方案1】:

    如果我理解正确,问题是在医院匹配时将值从 B 县复制到 A 县。这可以通过groupby/fillna(method='bfill') 完成。 bfill 方法用最接近的后续非 NaN 值回填 NaN。

    那么,当医院匹配时,您可以使用d2.drop_duplicates(subset=['Hospital'], keep='first') 保留第一行。


    例如,

    import pandas as pd
    
    df = pd.DataFrame({'County': ['A', 'B', 'A', 'B', 'A', 'B', 'A', 'B', 'A', 'B'],
                       'Hospital': ['a', 'b', 'e', 'f', 'i', 'j', 'm', 'n', 'b', 'r'],
                       'Enrollment': [44, 55, 95, 54, 81, 54, 89, 76, 1, 67],
                       'Year': ['2012', '2012', '2012', '2012', '2012', '2013',
                                '2013', '2013', '2013', '2013']})
    d2 = pd.pivot_table(df, index=['County', 'Hospital'], columns=['Year'])  
    d2 = d2.groupby(level='Hospital').fillna(method='bfill')
    d2 = d2.reset_index()
    d2 = d2.drop_duplicates(subset=['Hospital'], keep='first')
    

    产量

         County Hospital Enrollment      
    Year                       2012  2013
    0         A        a       44.0   NaN
    1         A        b       55.0   1.0
    2         A        e       95.0   NaN
    3         A        i       81.0   NaN
    4         A        m        NaN  89.0
    6         B        f       54.0   NaN
    7         B        j        NaN  54.0
    8         B        n        NaN  76.0
    9         B        r        NaN  67.0
    

    【讨论】:

    • 关闭,但是医院行保留的标准是基于第一年缺少数据而第二年有数据的(满足这两个标准的就是保留) .
    【解决方案2】:

    操纵d2AB 并排放置。

    e = d2.unstack(0).swaplevel(1, 2, 1).sort_index(1).Enrollment
    print e
    
    County       A           B      
    Year      2012  2013  2012  2013
    Hospital                        
    a         44.0   NaN   NaN   NaN
    b          NaN   1.0  55.0   NaN
    e         95.0   NaN   NaN   NaN
    f          NaN   NaN  54.0   NaN
    i         81.0   NaN   NaN   NaN
    j          NaN   NaN   NaN  54.0
    m          NaN  89.0   NaN   NaN
    n          NaN   NaN   NaN  76.0
    r          NaN   NaN   NaN  67.0
    

    创建一个 apply 函数来分配来自 B 的值,然后使 B 无效。

    def manipulate_rows(row):
        if pd.notnull(row.loc['A'].iloc[1]) & pd.isnull(row.loc['A'].iloc[0]):
            row.A = row.A.combine_first(row.B)
            row.B = np.nan
        return row
    
    d3 = e.apply(manipulate_rows, axis=1).stack(0).swaplevel(0, 1).sort_index()
    

    Stacking 会自然地丢弃枢轴之后的缺失值。

    重新分配 d2

    d3.columns = d2.columns
    
    print d3
    
                    Enrollment      
    Year                  2012  2013
    County Hospital                 
    A      a              44.0   NaN
           b              55.0   1.0
           e              95.0   NaN
           i              81.0   NaN
           m               NaN  89.0
    B      f              54.0   NaN
           j               NaN  54.0
           n               NaN  76.0
           r               NaN  67.0
    

    【讨论】:

    • 几乎可以肯定是来自.swaplevel(1, 2, 1) 部分。在.unstack(0) 之后。这意味着您调用它的数据帧在其索引中只有一个级别,这意味着您在错误的数据帧上调用了它,或者它与问题中表示的不同。
    • 你是对的;我忘记了我已将 reset_index() 添加到我的原始代码中。关于函数定义中的row.loc['A'];有没有办法避免引用标签本身?重复行可能出现在 n 个组中的任何一个中。
    • 目前,我想我必须重新设计逻辑。 row.loc['A'] 正在利用 loc 处理 MultiIndex 的方式。一个直接的解决方法是传递列名:def manipulate_row(row, to='A', from='B') 或类似的东西。
    • 是否可以在原始 DF 上进行 groupby 和 max 来替换 NaN?
    猜你喜欢
    • 2019-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-23
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 2017-07-05
    相关资源
    最近更新 更多