pandas 替换多索引 Dataframe 中的特定值

wgx48brx  于 2023-01-28  发布在  其他
关注(0)|答案(4)|浏览(115)

我有一个多索引 Dataframe ,有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

Dataframe 太大了,像df.xs('A,1')...df.xs(A,2)这样一帧一帧地做会很耗时。有什么方法可以让我得到一个掩码,然后在这些位置用新值替换吗?

pxyaymoc

pxyaymoc1#

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

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
svmlkihl

svmlkihl2#

我们可以提取一系列的二级指标:

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
ncecgwcz

ncecgwcz3#

可以在简单的iloc中使用grouper indices

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倍

zysjyyx4

zysjyyx44#

我想你可以这样写:

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

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

相关问题