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


143

假设我有一个带有两列A和B的pandas DataFrame。我想修改此DataFrame(或创建一个副本),以便每当A为0时B始终为NaN。我将如何实现?

我尝试了以下

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

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

没有成功。


如果你正在寻找一个非常快速的解决方案使用NumPy的真实where所看到的这个解决方案如下
泰德·彼得鲁

Answers:


243

使用.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

我对pandas内部没有足够的了解,无法确切知道它为什么起作用,但是基本的问题是有时索引到DataFrame中会返回结果的副本,有时会返回原始对象的视图。根据此处的文档,此行为取决于基础的numpy行为。我发现在一个操作(而不是[one] [two])中访问所有内容更可能用于设置。


第二部分是一个甚至没有被问到的问题的好答案;-)我想知道这是否仍然是规范的大熊猫答案,特别是b / c这是明显的DRY违规,尽管我认为这是对的。鉴于熊猫内部的约束,违反DRY的必要事实吗?(我可能会更详细地发布这类问题,但想在您回答之前先看看您是否有一个快速的答案)
JohnE

如何子集没有列名的数据框,如何仅通过索引子集df?df.loc [df [0] == 0]不起作用...还有什么选择?谢谢
amipro

89

是有关高级索引的熊猫文档:

本节将确切说明您的需求!事实证明df.loc(如已弃用.ix -正如许多人在下面指出的那样)可以用于数据帧的酷切片/切块。和。它也可以用来设置事物。

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

因此,布伦的回答是说“找到我所有的位置df.A == 0,选择列B并将其设置为np.nan


2
你让我今天一整天都感觉很好。明确的解释。
TwinPenguins

1
是的,某种程度上loc[selection criteria, columns I want]您完全可以记住...
EmEs

29

从熊猫0.20开始不推荐使用ix。正确的方法是使用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
>>> 

说明:

如在doc解释这里.loc 主要是基于标签,但也可以用布尔阵列使用

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

  • 利用loc可以将布尔数组作为掩码的事实,该掩码告诉熊猫我们要更改的行的子集row_index
  • 利用这样的事实loc也是基于标签来选择使用标签列'B'column_index

我们可以使用逻辑,条件或返回一系列布尔值的任何操作来构造布尔值数组。在上面的示例中,我们希望rows包含的任何对象都0可以使用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

有关更多信息,请在此处查看高级索引文档。


11

要大幅提高速度,请使用NumPy的where函数。

建立

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

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)

Numpy的where速度快约4倍


我对此感到很好奇,因此我自己进行了测试,使用其他参数的差异甚至更大。用整数而不是np.nan替换0时,Numpy快了将近10倍。我想知道需要什么额外的时间。
亚历山大

是否有必要使用.valuesnp.where(df.a.values == 0, np.nan, df.b.values)?看起来np.where(df.a == 0, np.nan, df.b)还可以吗?
hsl

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.