【问题标题】:Mask dataframe with another multi-indexed Series使用另一个多索引系列屏蔽数据框
【发布时间】:2018-12-18 11:32:13
【问题描述】:

我有一个数据框,我想用多索引系列的布尔值屏蔽(转换为 NaN),其中系列的多索引也是数据框中的列名。例如,如果df 是:

df = pd.DataFrame({ 'A': (188, 750, 1330, 1385, 188, 750, 810, 1330, 1385),
                     'B': (1, 2, 4, 5, 1, 2, 3, 4, 5),
                     'C': (2, 5, 7, 2, 5, 5, 3, 7, 2),
                     'D': ('foo', 'foo', 'foo', 'foo', 'bar', 'bar', 'bar', 'bar', 'bar') })

    A    B  C   D
0   188  1  2   foo
1   750  2  5   foo
2   1330 4  7   foo
3   1385 5  2   foo
4   188  1  5   bar
5   750  2  5   bar
6   810  3  3   bar
7   1330 4  7   bar
8   1385 5  2   bar

而多索引系列ser 是:

arrays = [('188', '750', '810', '1330', '1385'),
          ('1', '2', '3', '4', '5')]
tuples = list(zip(*arrays))
index = pd.MultiIndex.from_tuples(tuples, names=['A', 'B'])
ser = pd.Series([False, False, True, False, True], index=index)

A     B
188   1    False
750   2    False
810   3    True
1330  4    False
1385  5    True
dtype: bool

如何屏蔽(转换为 NaN)df 中的列 C 上的值,其中条目为系列 False 中的 ser,以便以最终的 Dataframe 结束,如下所示:

    A    B  C   D
0   188  1  2   foo
1   750  2  5   foo
2   1330 4  7   foo
3   1385 5  NaN foo
4   188  1  5   bar
5   750  2  5   bar
6   810  3  NaN bar
7   1330 4  7   bar
8   1385 5  NaN bar

【问题讨论】:

    标签: python python-3.x pandas dataframe multi-index


    【解决方案1】:

    更改ser的初始化步骤:

    arrays = [('188', '750', '810', '1330', '1385'),
              ('1', '2', '3', '4', '5')]
    # Note: The change is in this step - make the levels numeric.
    tuples = list(zip(*map(pd.to_numeric, arrays)))
    index = pd.MultiIndex.from_tuples(tuples, names=['A', 'B'])
    ser = pd.Series([False, False, True, False, True], index=index)
    

    初始化index 的关卡,使其具有与“A”和“B”相同的数据类型。希望这不应该是一个问题。

    这将使我们使用loc 和基于索引的选择和分配来构建一个更简单的解决方案。

    u = df.set_index(['A', 'B'])
    u.loc[ser.index[ser], 'C'] = np.nan
    
    u.reset_index()
          A  B    C    D
    0   188  1  2.0  foo
    1   750  2  5.0  foo
    2  1330  4  7.0  foo
    3  1385  5  NaN  foo
    4   188  1  5.0  bar
    5   750  2  5.0  bar
    6   810  3  NaN  bar
    7  1330  4  7.0  bar
    8  1385  5  NaN  bar
    

    如果您遇到给定ser 并需要更改索引的dtype 的情况,您可以使用pd.Index.set_levels 中的列表推导快速重新构建它。

    ser.index = ser.index.set_levels([l.astype(int) for l in ser.index.levels]) 
    # Alternative,
    # ser.index = ser.index.set_levels([
    #     pd.to_numeric(l) for l in ser.index.levels]) 
    

    现在,这可行:

    u = df.set_index(['A', 'B'])
    u.loc[ser.index[ser], 'C'] = np.nan
    
    u.reset_index()
    
          A  B    C    D
    0   188  1  2.0  foo
    1   750  2  5.0  foo
    2  1330  4  7.0  foo
    3  1385  5  NaN  foo
    4   188  1  5.0  bar
    5   750  2  5.0  bar
    6   810  3  NaN  bar
    7  1330  4  7.0  bar
    8  1385  5  NaN  bar
    

    注意loc中的ser.index[ser]索引步骤,我们直接使用ser的索引而不是index

    【讨论】:

    • 我刚刚在问题中从头开始构建ser,但实际上系列本身来自以前的代码。已经拥有 Series 后,如何更改多索引的 dtype?
    • @PedroA 要么将 ser 的索引改为 int,要么将 A 和 B 的 dtype 改为 str。我认为前者效率更高,假设 ser 小得多。见编辑。
    • @PedroA 找到了更好的转换解决方案 :)
    【解决方案2】:

    使用isin 来检查MultiIndex 之间的成员关系:

    #convert columns to strings for same types of levels
    df[['A','B']] = df[['A','B']].astype(str)
    df.loc[df.set_index(['A','B']).index.isin(ser.index[ser]), 'C'] = np.nan
    print (df)
          A  B    C    D
    0   188  1  2.0  foo
    1   750  2  5.0  foo
    2  1330  4  7.0  foo
    3  1385  5  NaN  foo
    4   188  1  5.0  bar
    5   750  2  5.0  bar
    6   810  3  NaN  bar
    7  1330  4  7.0  bar
    8  1385  5  NaN  bar
    

    【讨论】:

      【解决方案3】:

      用途:

      # Converting ser to a dataframe 
      ndf = pd.DataFrame(ser).reset_index()
      
      # Fetching B values against which C values needs to be mapped to NaN
      idx = ndf[ndf.iloc[:,2] == True].B.values
      
      # Fetching df index where C values needs to be mapped to NaN
      idx_ = df[df.B.isin(idx)].index
      
      # Mapping of C values to NaN
      df.loc[idx_,'C'] = np.NaN
      
      
      +---+------+---+-----+-----+
      |   |   A  | B |  C  |  D  |
      +---+------+---+-----+-----+
      | 0 |  188 | 1 | 2.0 | foo |
      | 1 |  750 | 2 | 5.0 | foo |
      | 2 | 1330 | 4 | 7.0 | foo |
      | 3 | 1385 | 5 | NaN | foo |
      | 4 |  188 | 1 | 5.0 | bar |
      | 5 |  750 | 2 | 5.0 | bar |
      | 6 |  810 | 3 | NaN | bar |
      | 7 | 1330 | 4 | 7.0 | bar |
      | 8 | 1385 | 5 | NaN | bar |
      +---+------+---+-----+-----+
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-17
        • 2014-03-17
        • 1970-01-01
        • 2018-04-19
        • 1970-01-01
        • 1970-01-01
        • 2012-04-21
        • 2017-08-30
        相关资源
        最近更新 更多