【问题标题】:Efficient way to avoid for loops in Pandas DataFrame在 Pandas DataFrame 中避免 for 循环的有效方法
【发布时间】:2017-09-15 00:20:22
【问题描述】:

我正在将 Excel 电子表格转换为 Python,以便自动化和加快多项任务。我需要向 DataFrame 添加几列,并根据前一列中的值向它们添加数据。我使用两个嵌套的 for 循环让它工作,但它真的很慢,而且我知道 Pandas 不是为逐个单元工作而设计的。这是我的问题的一个示例:

import pandas as pd

results = pd.DataFrame({'scores':[78.5, 91.0, 103.5], 'outcomes':[1,0,1]})

thresholds = [103.5, 98.5, 93.5, 88.5, 83.5, 78.5]

for threshold in thresholds:
    results[str(threshold)] = 0
    for index, row in results.iterrows():
        if row['scores'] > threshold:
            results.set_value(index, str(threshold), row['outcomes'])

print (results)

以及正确的输出:

   outcomes  scores  103.5  98.5  93.5  88.5  83.5  78.5
0         1    78.5      0     0     0     0     0     0
1         0    91.0      0     0     0     0     0     0
2         1   103.5      0     1     1     1     1     1

有什么更有效的方法来做到这一点?我一直在玩弄将 DataFrame 转置为按列而不是按行工作的想法,但我什么也做不了。 感谢您的帮助!

【问题讨论】:

标签: python pandas


【解决方案1】:

下面是一个完全矢量化的解决方案,不使用循环或列表理解。

import pandas as pd
import numpy as np
results = pd.DataFrame({'scores':[78.5, 91.0, 103.5], 'outcomes':[1,0,1]})
thresholds = [4.7562029077978352, 4.6952820449271861, 4.6343611820565371, 4.5734403191858881, 103.5, 98.5, 93.5, 88.5, 83.5, 78.5]
thresholds_col = ['{:.16f}'.format(e) for e in thresholds]
data = results.outcomes[:,np.newaxis] * ((results.scores[:,np.newaxis] - thresholds > 0))
results = results.join(pd.DataFrame(data=data, columns=thresholds_col))
print results
print results[thresholds_col]

Out[79]: 
   4.7562029077978352  4.6952820449271861  4.6343611820565371  \
0                   1                   1                   1   
1                   0                   0                   0   
2                   1                   1                   1   

   4.5734403191858881  103.5000000000000000  98.5000000000000000  \
0                   1                     0                    0   
1                   0                     0                    0   
2                   1                     0                    1   

   93.5000000000000000  88.5000000000000000  83.5000000000000000  \
0                    0                    0                    0   
1                    0                    0                    0   
2                    1                    1                    1   

   78.5000000000000000  
0                    0  
1                    0  
2                    1 

【讨论】:

  • 当我在完整数据集上运行此代码时,我得到 KeyError: '4.7562029078'。实际数据集有 200 个阈值,第一个是 4.7562029077978352;您的代码是否以某种方式将阈值四舍五入到设定的位数?
  • 当您使用浮点数作为 Pandas 列名时,它会自动进行舍入。您的阈值是否具有相同的长度和小数点?可以举几个例子吗?
  • 阈值是根据传入数据(max - min) / number_of_bins动态计算的。有时它很整洁,有时则不然。在这个集合上,前四个阈值是4.7562029077978352, 4.6952820449271861, 4.6343611820565371, 4.5734403191858881
  • 嘿,格雷格,我已经更新了代码,现在您可以使用 thresholds_col 访问不应再出现 KeyError 的列。
【解决方案2】:

这样就可以了:

import pandas as pd

results = pd.DataFrame({'scores':[78.5, 91.0, 103.5], 'outcomes':[1,0,1]})

thresholds = [103.5, 98.5, 93.5, 88.5, 83.5, 78.5]

for threshold in thresholds:
    results[str(threshold)] = results[['scores','outcomes']].apply(lambda x: x['outcomes'] if x['scores']>threshold else 0, axis=1)

print (results)

哪个提示

   outcomes  scores  103.5  98.5  93.5  88.5  83.5  78.5
0         1    78.5      0   0.0   0.0   0.0   0.0   0.0
1         0    91.0      0   0.0   0.0   0.0   0.0   0.0
2         1   103.5      0   1.0   1.0   1.0   1.0   1.0

【讨论】:

  • 谢谢!完美运行。
  • 这比最初的尝试慢。这不是矢量化的,它只使用列表和字典理解句法 surgar。将您的解决方案包装成一个函数和这个提议的函数,然后使用 %time 或 %timeit 运行它。使用我的 CPU,这比使用嵌套循环的原始尝试慢两倍。
猜你喜欢
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
  • 2021-09-29
  • 2018-03-15
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多