修改pandas数据帧中的行子集

时间:2012-09-06 19:32:26

标签: python pandas

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

我尝试了以下

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

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

没有成功。

5 个答案:

答案 0 :(得分:204)

使用.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会返回结果的副本,有时它会返回原始对象的视图。根据文档here,此行为取决于潜在的numpy行为。我发现在一次操作中访问所有内容(而不是[一次] [两次])更有可能用于设置。

答案 1 :(得分:73)

Here来自pandas docs on advanced indexing:

该部分将准确解释您的需求!结果df.loc(因为.ix已被弃用 - 正如下面许多人所指出的那样)可以用于数据帧的冷切片/切割。和。它也可以用来设置东西。

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

所以Bren的回答是说'找到df.A == 0的所有地方,选择专栏B并将其设为np.nan'

答案 2 :(得分:23)

从pandas 0.20 ix is deprecated开始。正确的方法是使用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
>>> 

说明:

正如文档here中所述,.loc 主要是基于标签的,但也可以与布尔数组一起使用

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

  • 利用loc可以将布尔数组作为掩码的事实告诉pandas我们要在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

有关详细信息,请查看高级索引文档here

答案 3 :(得分:5)

为了大幅提速,请使用NumPy的功能。

设置

创建一个包含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)

Numpy的where大约快4倍

答案 4 :(得分:3)

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

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