【问题标题】:pandas assign result from list of columns熊猫从列列表中分配结果
【发布时间】:2020-04-25 07:43:34
【问题描述】:

假设我有一个如下所示的数据框:

import pandas as pd
import numpy as np
np.random.seed(42)
df = pd.DataFrame({'A':np.random.randn(5), 'B': np.zeros(5), 'C': np.zeros(5)})
df
>>>
          A    B    C
0  0.496714  0.0  0.0
1 -0.138264  0.0  0.0
2  0.647689  0.0  0.0
3  1.523030  0.0  0.0
4 -0.234153  0.0  0.0

当A 为负数时,我想用值 1 填充列的列表。

idx = df.A < 0
cols = ['B', 'C']

所以在这种情况下,我希望索引 [1, 'B'] 和 [4, 'C'] 设置为 1。

我尝试了什么:

但是,执行df.loc[idx, cols] = 1 会将整行设置为 1,而不仅仅是单个列。我也尝试过df.loc[idx, cols] = pd.get_dummies(cols),结果如下:

          A    B    C
0  0.496714  0.0  0.0
1 -0.138264  0.0  1.0
2  0.647689  0.0  0.0
3  1.523030  0.0  0.0
4 -0.234153  NaN  NaN

我假设这是因为get_dummies 的索引和数据框没有对齐。

预期输出:

          A    B    C
0  0.496714  0.0  0.0
1 -0.138264  1.0  0.0
2  0.647689  0.0  0.0
3  1.523030  0.0  0.0
4 -0.234153  0.0  1.0

那么什么是最好的(阅读最快的)方法来做到这一点。在我的例子中,有 1000 行和 5 列。

结果时间:

TLDR:直接编辑值更快。

%%timeit
df.values[idx, df.columns.get_indexer(cols)] = 1

每个循环 123 µs ± 2.5 µs(7 次运行的平均值 ± 标准偏差,每次 10000 个循环)

%%timeit
df.iloc[idx.array,df.columns.get_indexer(cols)]=1

每个循环 266 µs ± 7 µs(7 次运行的平均值 ± 标准偏差,每次 1000 个循环)

【问题讨论】:

  • df.iloc[idx.array,df.columns.get_indexer(cols)]=1 可能会成功

标签: pandas dataframe


【解决方案1】:

使用 numpy 索引来提高性能:

idx = df.A < 0
res = ['B', 'C']
arr = df.values
arr[idx, df.columns.get_indexer(res)] = 1
print (arr)
[[ 0.49671415  0.          0.        ]
 [-0.1382643   1.          0.        ]
 [ 0.64768854  0.          0.        ]
 [ 1.52302986  0.          0.        ]
 [-0.23415337  0.          1.        ]]

df = pd.DataFrame(arr, columns=df.columns, index=df.index)
print (df)
          A    B    C
0  0.496714  0.0  0.0
1 -0.138264  1.0  0.0
2  0.647689  0.0  0.0
3  1.523030  0.0  0.0
4 -0.234153  0.0  1.0

替代方案:

idx = df.A < 0
res = ['B', 'C']
df.values[idx, df.columns.get_indexer(res)] = 1
print (df)
          A    B    C
0  0.496714  0.0  0.0
1 -0.138264  1.0  0.0
2  0.647689  0.0  0.0
3  1.523030  0.0  0.0
4 -0.234153  0.0  1.0

【讨论】:

  • 我觉得应该有一种方法可以结合df.columns.get_indexer 和loc,绕过重新创建整个数据框选项。无论如何,感谢您的解决方案,将等待一段时间才能接受。
【解决方案2】:
ind = df.index[idx]
for idx,col in zip(ind,res):
   ...:     df.at[idx,col] = 1

In [7]: df
Out[7]:
          A    B    C
0  0.496714  0.0  0.0
1 -0.138264  1.0  0.0
2  0.647689  0.0  0.0
3  1.523030  0.0  0.0
4 -0.234153  0.0  1.0

【讨论】:

  • 在python中尽量避免for循环
  • 我想这是一个答案,但希望更有效。至少 +​​1。
猜你喜欢
  • 2020-09-23
  • 2019-04-23
  • 2021-06-05
  • 2021-01-29
  • 2022-11-15
  • 2015-04-14
  • 2018-07-24
  • 2019-11-26
  • 1970-01-01
相关资源
最近更新 更多