修改熊猫数据框架中的行子集

假设我有一个包含两列 A 和 B 的熊猫数据框架,我想修改这个数据框架(或者创建一个副本) ,这样当 A 为0时,B 总是 NaN。我怎么才能做到呢?

我试过以下方法

df['A'==0]['B'] = np.nan

还有

df['A'==0]['B'].values.fill(np.nan)

没有成功。

191032 次浏览

使用 .loc进行基于标签的索引:

df.loc[df.A==0, 'B'] = np.nan

df.A==0表达式创建一个对行进行索引的布尔序列,'B'选择该列。您也可以使用它来转换列的子集,例如:

df.loc[df.A==0, 'B'] = df.loc[df.A==0, 'B'] / 2

我对熊猫内部结构的了解还不足以确切地知道其中的原理,但基本的问题是,有时索引到 DataFrame 会返回结果的一个副本,有时它会返回原始对象的一个视图。根据文档 给你,这种行为取决于底层的麻木行为。我发现,在一个操作(而不是[一][二])中访问所有内容更有可能用于设置。

这里 来自熊猫高级索引文档:

这个部分会准确地解释你需要什么!原来 df.loc(作为。Ix 已经被弃用了——正如下面许多人指出的那样) ,可以用于对数据框架进行冷静的切片/切块。还有。它也可以用来设置东西。

df.loc[selection criteria, columns I want] = value

所以布伦的回答是‘找到所有 df.A == 0的位置,选择 B列并设置为 np.nan

从熊猫0.20开始。正确的方法是使用 Df.loc

这里有一个实用的例子

>>> import pandas as pd
>>> import numpy as np
>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
A   B
0  0 NaN
1  1   0
2  0 NaN
>>>

说明:

如文档 给你.loc 主要是基于标签的,但也可以与布尔数组一起使用所解释的。

因此,我们上面所做的就是通过以下方式应用 df.loc[row_index, column_index]:

  • 利用 loc可以采用布尔数组作为掩码的事实,该掩码告诉熊猫我们希望在 row_index中更改哪些行子集
  • 利用 loc也是基于标签的这一事实,使用 column_index中的标签 'B'选择列

我们可以使用逻辑、条件或任何返回一系列布尔值的操作来构造布尔值数组。在上面的例子中,我们需要任何包含 0rows,因为我们可以使用 df.A == 0,正如您在下面的例子中看到的,这将返回一系列布尔值。

>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df
A  B
0  0  2
1  1  0
2  0  5
>>> df.A == 0
0     True
1    False
2     True
Name: A, dtype: bool
>>>

然后,我们使用上面的布尔值数组来选择和修改必要的行:

>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
A   B
0  0 NaN
1  1   0
2  0 NaN

有关更多信息,请查看高级索引文档 给你

使用 .values替换多列转换为 numpy 数组:

df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2

为了大幅度提高速度,使用 NumPy 的 where 函数。

设置

创建一个包含100,000行和一些零的两列 DataFrame。

df = pd.DataFrame(np.random.randint(0,3, (100000,2)), columns=list('ab'))

numpy.where快速解决方案

df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)

时机

%timeit df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)
685 µs ± 6.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)


%timeit df.loc[df['a'] == 0, 'b'] = np.nan
3.11 ms ± 17.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

努比的 where要快4倍

备选方案:

No 1对我来说最好,但奇怪的是我找不到它的支持文档

  1. 将列作为序列进行筛选(注意: 过滤器在写入列之后,而不是之前)

Column [ filter 條件] = 要更改为的值

df.B[df.A==0] = np.nan
  1. 洛克

Loc [过滤条件,要更改的列] = 要更改为的值

df.loc[df.A == 0, 'B'] = np.nan
  1. 麻木的地方

Column = np.where (过滤条件,值为 true,值为 false)

import numpy as np
df.B = np.where(df.A== 0, np.nan, df.B)
  1. 应用 Lambda

Column = df.application (lambda row: value if Ordinance true else value if false,use rows not column)

df.B = df.apply(lambda x: np.nan if x['A']==0 else x['B'],axis=1)
  1. 和列表语法

Column = [ valuse if 條 is true else value if false for element a,b in list from zip function of column a and b ]

df.B = [np.nan if a==0 else b for a,b in zip(df.A,df.B)]

要修改熊猫中的数据框架,你可以使用“语法糖”操作符,如 +=*=/=等,所以不要使用:

df.loc[df.A == 0, 'B'] = df.loc[df.A == 0, 'B'] / 2

你可以写:

df.loc[df.A == 0, 'B'] /= 2

要用 NaN代替值,你可以使用熊猫方法 maskwhere。例如:

df  = pd.DataFrame({'A': [1, 2, 3], 'B': [0, 0, 4]})


A  B
0  1  0
1  2  0
2  3  4


df['A'].mask(df['B'] == 0, inplace=True) # other=np.nan by default
# df['A'].where(df['B'] != 0, inplace=True)

结果:

     A  B
0  NaN  0
1  NaN  0
2  3.0  4