我正在尝试使用Python的Scoop库在从正态分布随机生成的10000000个数据点(4个特征,1个目标变量)上并行运行线性回归。这是代码:

import pandas as pd
import numpy as np
import random
from scoop import futures
import statsmodels.api as sm
from time import time

def linreg(vals):
    global model
    model = sm.OLS(y_vals,X_vals).fit()
    return model
    print(model.summary())

if __name__ == '__main__':

random.seed(42)
vals = pd.DataFrame(np.random.normal(loc = 3, scale = 100, size =(10000000,5)))
vals.columns = ['dep', 'ind1', 'ind2', 'ind3', 'ind4']
y_vals = vals['dep']
X_vals = vals[['ind1', 'ind2', 'ind3', 'ind4']]

bt = time()
model_vals = list(map(linreg, [1,2,3]))
mval = model_vals[0]
print(mval.summary())
serial_time = time() - bt

bt1 = time()
model_vals_1 = list(futures.map(linreg, [1,2,3]))
mval_1 = model_vals_1[0]
print(mval_1.summary())
parallel_time = time() - bt1

print(serial_time, parallel_time)`


但是,在此之后,回归摘要确实是通过Python的标准map函数以串行方式生成的,这是一个错误:


  追溯(最近一次通话最近):文件“ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ runpy.py”,行193,在_run_module_as_main“ main”,mod_spec中) “ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ runpy.py”,行85,在_run_code exec(code,run_globals)文件中,“ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop \ bootstrap__main __。py“,第302行,位于b.main()文件“ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop \ bootstrap__main __。py“,第92行,位于主self.run()文件“ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop \ bootstrap__main __。py“,运行中的futures_startup()文件,第290行,文件“ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop \ bootstrap__main __。py“,位于futures_startup run_name =” main“文件的第271行,文件” C:\ Users \ n iccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop \ futures.py“,第64行,在_startup结果= _controller.switch(rootFuture,* args,** kargs)文件中运行控制器中的“ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop_control.py”行253会引发future.exceptionValue文件“ C:\ Users \ niccolo .gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop_control.py“,第127行,位于runFuture future.resultValue = future.callable(* future.args,** future.kargs)文件“ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ runpy.py”,行263,位于run_path pkg_name = pkg_name,script_name = fname)文件“ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ runpy.py“,第96行,在_run_module_code mod_name,mod_spec,pkg_name,script_name中)文件“ C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ runpy.py“,李ne 85,在_run_code exec(code,run_globals)文件“ Scoop_map_linear_regression1.py”的第33行中,在model_vals_1 = list(futures.map(linreg,[1,2,3]))文件“ C:\ Users \ niccolo。 _mapGenerator中第102行的gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop \ futures.py“行中,以备将来在_waitAll(* futures)中使用:文件” C:\ Users \ niccolo。 _waitAny(future)中_waitAll中的358行中的gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop \ futures.py“行358:文件” C:\ Users \ niccolo.gentile \ AppData \ Local \ Continuum \ anaconda3 \ envs \ tensorenviron \ lib \ site-packages \ scoop \ futures.py“,行335,在_waitAny中引发childFuture.exceptionValue NameError:名称“ y_vals”未定义


之后产生的。这意味着代码在model_vals_1 = list(futures.map(linreg, [1,2,3]))处停止

请仔细注意,为了能够并行运行代码,必须从命令行中指定-m scoop参数来启动它,如下所示:

python -m scoop Scoop_map_linear_regression1.py


确实,如果不使用-m scoop参数启动它,它将不会被并行化并且实际上不会运行,而只是使用内置Python的map函数的两倍(因此,以串行方式运行两次),就可以得到在警告中报告。也就是说,在启动时未指定-m scoop参数,会将futures.map替换为map,而目标是实际上使用futures.map并行运行它。

这样做是为了避免人们回答,只需简单地启动不带-m scoop参数的代码即可解决问题,这已经在这里发生:

Python Parallel Computing - Scoop

因此,该问题被错误地搁置为离题的话题,因为它不再具有可重复性。

在此先感谢您,任何评论都将受到赞赏和欢迎。

最佳答案

解决方案是仅传递[1]作为futures.map(但不一定是map)的第二个参数。

实际上,即使linreg函数不使用传递给map的第二个参数,它仍然确定linreg函数将运行多少次。例如,请考虑以下基本示例:

def welcome(x):
    print('Hello world!')

if __name__ == '__main__':
    a = list(map(welcome, [1,2]))


函数welcome实际上不需要任何参数,但是输出仍然是

Hello world!
Hello world!


重复两次,即作为第二个参数传递的列表的长度。

在此特定情况下,这意味着线性回归将按地图运行3次,尽管事实是,在汇总被调用到地图外部时,回归输出只会出现一次。

关键是,相反,无法使用futures.map运行多次线性回归。问题在于,很显然,在第一次运行后,它实际上删除了使用的数据集,第二次和第三次运行无法从中继续进行,因此


  NameError:未定义名称“ y_vals”


在跟踪结束时抛出。可以通过以下方式查看:scoop.futures source code

并没有解决所有问题,但是我想问题应该与greenlet切换器有关。

08-25 09:12