修改 pandas 数据框中的行子集
Posted
技术标签:
【中文标题】修改 pandas 数据框中的行子集【英文标题】:Modifying a subset of rows in a pandas dataframe 【发布时间】:2012-08-31 16:30:13 【问题描述】:假设我有一个带有两列 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
,如 this solution below 所示
【参考方案1】:
使用.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 行为。我发现在一次操作中访问所有内容(而不是 [one][two])更有可能用于设置。
【讨论】:
本文的第二部分很好地回答了一个甚至没有被问到的问题 ;-) 我想知道这是否仍然是规范的 pandas 答案,特别是 b/c 它是一个明显的 DRY违反,尽管我认为鉴于熊猫内部结构的限制,实际上有必要违反 DRY? (我可能会更详细地发布这类问题,但想在我这样做之前看看你是否有一个快速的答案) 如何对没有列名的数据框进行子集化,如何仅通过索引对 df 进行子集化? df.loc[df[0]==0] 不起作用...有什么替代方法?谢谢 只是一个提示,如果你想分配另一个 DF 例如df.loc[df.A==0, df2] 请注意,如果 df2 从 0 到 end 连续索引,它将执行索引分配。因此,如果过滤后的 df 具有索引 [1, 4, 5] 并且 df2 具有 [1, 2, 3] 则只会分配索引 1。这可以通过在右侧使用未索引的结构来防止,例如df.loc[df.A==0, np.array(df2)],那么它将被成对分配。 pandas .mask() 和 .where() 函数也是如此!【参考方案2】:Here 来自 pandas 高级索引文档:
该部分将准确解释您的需求!原来df.loc
(因为 .ix 已被弃用——正如许多人在下面指出的那样)可用于数据帧的冷切片/切块。和。它也可以用来设置东西。
df.loc[selection criteria, columns I want] = value
所以布伦的回答是'找到df.A == 0
的所有地方,选择B
列并将其设置为np.nan
'
【讨论】:
是的,不知怎的,loc[selection criteria, columns I want]
完美地印在了你的脑海中……【参考方案3】:
从 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]
by:
loc
可以将布尔数组作为掩码,告诉pandas 我们要在row_index
中更改哪些行子集
利用loc
这一事实也是基于标签的,以使用column_index
中的标签'B'
选择列
我们可以使用逻辑、条件或任何返回一系列布尔值的操作来构造布尔值数组。在上面的示例中,我们想要任何包含0
的rows
,为此我们可以使用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。
【讨论】:
【参考方案4】:要大幅提高速度,请使用 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 在用整数而不是 np.nan 替换 0 时快了近 10 倍。我想知道什么需要额外的时间。np.where(df.a.values == 0, np.nan, df.b.values)
中是否需要使用.values
?看起来np.where(df.a == 0, np.nan, df.b)
也有效?【参考方案5】:
使用.values
替换多个列转换为numpy数组:
df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2
【讨论】:
【参考方案6】:替代方案:
no 1 在我看来最好,但奇怪的是我找不到它的支持文档
-
将列过滤为系列(注意:过滤器出现在写入列之后,而不是之前)
dataframe.column[过滤条件]=要更改为的值
df.B[df.A==0] = np.nan
-
loc
dataframe.loc[过滤条件,要更改的列]=要更改的值
df.loc[df.A == 0, 'B'] = np.nan
-
numpy where
dataframe.column=np.where(过滤条件,值为真,值为假)
import numpy as np
df.B = np.where(df.A== 0, np.nan, df.B)
-
apply lambda
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)
-
zip 和列表语法
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)]
【讨论】:
【参考方案7】:要在 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
【讨论】:
以上是关于修改 pandas 数据框中的行子集的主要内容,如果未能解决你的问题,请参考以下文章
折叠 Pandas 数据框中的行,每列具有不同的逻辑 [重复]
Pandas:如何根据特定列上特定值的条件选择数据框中的行[重复]