假设我有一个带有两列A和B的pandas DataFrame。我想修改这个DataFrame(或创建一个副本),这样每当A为0时B总是NaN。我将如何实现?
我尝试了以下
df['A'==0]['B'] = np.nan
和
df['A'==0]['B'].values.fill(np.nan)
没有成功。
答案 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