假设我有一个带有两列 A 和 B 的 pandas DataFrame。我想修改这个 DataFrame(或创建一个副本),以便在 A 为 0 时 B 始终为 NaN。我将如何实现?
我尝试了以下
df['A'==0]['B'] = np.nan
和
df['A'==0]['B'].values.fill(np.nan)
没有成功。
用于.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])更有可能用于设置。
以下是关于高级索引的 pandas 文档:
该部分将准确解释您的需求!事实证明df.loc
(因为 .ix 已被弃用——正如许多人在下面指出的那样)可用于数据帧的冷切片/切块。和。它也可以用来设置东西。
df.loc[selection criteria, columns I want] = value
所以布伦的回答是“找到我所有的地方df.A == 0
,选择列B
并将其设置为np.nan
”
从 pandas 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
>>>
正如此处文档中所解释的,.loc
主要基于标签,但也可以与布尔数组一起使用。
因此,我们在上面所做的是df.loc[row_index, column_index]
通过以下方式申请:
loc
可以将布尔数组作为掩码的事实,告诉熊猫我们要更改的行子集row_index
loc
也是基于标签的,使用标签'B'
中的标签选择列column_index
我们可以使用逻辑、条件或任何返回一系列布尔值的操作来构造布尔值数组。在上面的示例中,我们想要rows
包含 a 的任何内容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
有关更多信息,请查看此处的高级索引文档。
要大幅提高速度,请使用 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)
Numpy 的where
速度大约快 4 倍
要替换多个列,请使用以下命令转换为 numpy 数组.values
:
df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2
备择方案:
no 1 在我看来最好,但奇怪的是我找不到它的支持文档
dataframe.column[过滤条件]=要更改为的值
df.B[df.A==0] = np.nan
dataframe.loc[过滤条件,要更改的列]=要更改的值
df.loc[df.A == 0, 'B'] = np.nan
dataframe.column=np.where(过滤条件,值为真,值为假)
import numpy as np
df.B = np.where(df.A== 0, np.nan, df.B)
dataframe.column=df.apply(lambda row: value if condition true else value if false, 使用行而不是列)
df.B = df.apply(lambda x: np.nan if x['A']==0 else x['B'],axis=1)
dataframe.column=[如果条件为真则取值,否则对于列 a 和 b 的 zip 函数列表中的元素 a、b 为假则取值]
df.B = [np.nan if a==0 else b for a,b in zip(df.A,df.B)]
要在 Pandas 中修改 DataFrame,您可以使用“语法糖”运算符,如,+=
等。因此,请不要:*=
/=
df.loc[df.A == 0, 'B'] = df.loc[df.A == 0, 'B'] / 2
你可以写:
df.loc[df.A == 0, 'B'] /= 2
要替换值,NaN
可以使用 Pandas 方法mask
或where
. 例如:
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