【问题标题】:Replace specific values in multiindex dataframe替换多索引数据框中的特定值
【发布时间】:2020-10-23 03:20:39
【问题描述】:

我有一个包含 3 个索引级别和 2 个数字列的多索引数据框。

A   1   2017-04-01  14.0    87.346878
        2017-06-01  4.0     87.347504
    2   2014-08-01  1.0     123.110001
        2015-01-01  4.0     209.612503
B   3   2014-07-01  1.0     68.540001
        2014-12-01  1.0     64.370003
    4   2015-01-01  3.0     75.000000

我想在新的第二级索引开始的地方替换第三级索引的第一行中的值。 例如:每个第一行

(A,1,2017-04-01)->0.0   0.0 
(A,2,2014-08-01)->0.0   0.0  
(B,3,2014-07-01)->0.0   0.0  
(B,4,2015-01-01)->0.0   0.0

数据框太大,像df.xs('A,1')...df.xs(A,2) 这样逐个数据框进行操作会很耗时。有什么方法可以让我获得掩码并在这些位置用新值替换?

【问题讨论】:

    标签: python pandas dataframe multi-index


    【解决方案1】:

    level=2上使用DataFrame.reset_index,然后在level=[0, 1]上使用DataFrame.groupby并使用first聚合level_2,然后使用pd.MultiIndex.from_arrays创建一个多级索引,最后使用这个多级索引 更改数据框中的值:

    idx = df.reset_index(level=2).groupby(level=[0, 1])['level_2'].first()
    idx = pd.MultiIndex.from_arrays(idx.reset_index().to_numpy().T)
    df.loc[idx, :] = 0
    

    结果:

    # print(df)
                   col1        col2
    A 1 2017-04-01  0.0    0.000000
        2017-06-01  4.0   87.347504
      2 2014-08-01  0.0    0.000000
        2015-01-01  4.0  209.612503
    B 3 2014-07-01  0.0    0.000000
        2014-12-01  1.0   64.370003
      4 2015-01-01  0.0    0.000000
    

    【讨论】:

      【解决方案2】:

      我们可以提取一系列二级索引:

      df.index.get_level_values(1)
      # output: Int64Index([1, 1, 2, 2, 3, 3, 4], dtype='int64')
      

      并检查它的变化:

      idx = df.index.get_level_values(1)
      np.where(idx != np.roll(idx, 1))[0]
      # output: array([0, 2, 4, 6])
      

      所以我们可以简单地使用第二条语句的返回值和iloc 来获取每个二级索引的第一行并修改它们的值,如下所示:

      idx = df.index.get_level_values(1)
      df.iloc[np.where(idx != np.roll(idx, 1))[0]] = 0
      

      输出:

                        value1      value2
      A 1 2017-04-01       0.0    0.000000
          2017-06-01       4.0   87.347504
        2 2014-08-01       0.0    0.000000
          2015-01-01       4.0  209.612503
      B 3 2014-07-01       0.0    0.000000
          2014-12-01       1.0   64.370003
        4 2015-01-01       0.0    0.000000
      

      【讨论】:

      • 这在一般情况下不起作用,例如例如,当第 5 个索引为 ('B', 2, '2014-07-01').
      【解决方案3】:

      您可以在简单的iloc 中使用石斑鱼indeces

      df.iloc[[a[0] for a in df.groupby(level=[0, 1]).indices.values()]] = 0
      

      例子:

      df = pd.DataFrame({'col1': [14., 4., 1., 4., 1., 1., 3.],
                         'col2': [ 87.346878, 87.347504, 123.110001, 209.612503, 68.540001, 64.370003, 75.]},
                         index = pd.MultiIndex.from_tuples(([('A', 1, '2017-04-01'), ('A', 1, '2017-06-01'),
                                                             ('A', 2, '2014-08-01'), ('A', 2, '2015-01-01'),
                                                             ('B', 3, '2014-07-01'), ('B', 3, '2014-12-01'),
                                                             ('B', 4, '2015-01-01')])))
      

      结果:

                      col1        col2
      A 1 2017-04-01   0.0    0.000000
          2017-06-01   4.0   87.347504
        2 2014-08-01   0.0    0.000000
          2015-01-01   4.0  209.612503
      B 3 2014-07-01   0.0    0.000000
          2014-12-01   1.0   64.370003
        4 2015-01-01   0.0    0.000000
      

      时间安排:

      %%timeit
      idx = df.reset_index(level=2).groupby(level=[0, 1])['level_2'].first()
      idx = pd.MultiIndex.from_arrays(idx.reset_index().to_numpy().T)
      df.loc[idx, :] = 0
      #6.7 ms ± 40 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
      %%timeit
      df.iloc[[a[0] for a in df.groupby(level=[0, 1]).indices.values()]] = 0
      #897 µs ± 6.99 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
      

      所以这比 accepted answer 快了大约 7 倍

      【讨论】:

        【解决方案4】:

        我认为你可以使用这样的东西:

        import pandas as pd
        import numpy as np
        arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
           ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]
        tuples = list(zip(*arrays))
        
        df = pd.DataFrame([['A', 'B'], ['bar', 'two'],
                           ['foo', 'one'], ['foo', 'two']],
                         columns=['first', 'second'])
        index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
        df = pd.DataFrame(np.random.randn(8, 4), index=arrays)
        df
        

        您可以根据索引创建唯一值列表。然后获取索引位置,以替换列上与行值重合的行值。

        lst = ['bar','foo', 'qux']
        ls = []
        for i in lst:
            base = df.index.get_loc(i)
            a = base.indices(len(df))
            a = a[0]
            ls.append(a)
            
            for ii in ls:
            #print(ii)
                df[0][ii] = 0
        
        df
        

        幸运的是,这可以帮助你。

        干杯!

        【讨论】:

          猜你喜欢
          • 2022-08-18
          • 2017-07-23
          • 2021-01-05
          • 2013-12-28
          • 2021-01-24
          • 1970-01-01
          • 2017-04-22
          • 2019-02-25
          • 1970-01-01
          相关资源
          最近更新 更多