【问题标题】:How add element to a NumPy array in a Python function如何在 Python 函数中向 NumPy 数组添加元素
【发布时间】:2020-02-29 08:16:00
【问题描述】:

我正在尝试使用具有多处理模块的工作池从文本文件创建一系列 NumPy 数组。

def process_line(line, x,y,z,t):
    sl = line.split()
    x = np.append(x,float(sl[0].replace(',','')))
    y = np.append(y,float(sl[1].replace(',','')))
    z = np.append(z,float(sl[2].replace(',','')))
    t = np.append(t,float(sl[3].replace(',','')))

def txt_to_HDF_converter(name, path_file):

    #init objects
    x = np.empty(0)
    y = np.empty(0)
    z = np.empty(0)
    t = np.empty(0)
    pool = mp.Pool(4)
    jobs = []

with open(path_file) as f:
    for line in f:
        jobs.append(pool.apply_async(process_line,(line,x,y,z,t)))

#wait for all jobs to finish
for job in jobs:
    job.get()
#clean up
pool.close()

当数组在process_line 函数中分配时,问题就出现了,就好像参数按值传递一样,在循环结束时,我最终得到只有一个元素的数组。 知道如何解决这个问题吗?

【问题讨论】:

  • 你确定工人是线程吗?如果它们是进程,那么它们各自在自己的数据结构上工作,最后(加入时)您必须将它们的所有结果收集到主节点中。
  • 你好@Alfe,此时我刚刚删除了多处理部分并运行代码调用任何工人或线程的函数(process_line(line,x,y,z,t)) 并且数组在每次迭代中仍然没有增长,它只是附加最后一个值。

标签: python pass-by-reference numpy-ndarray


【解决方案1】:

您在此处的代码中将值作为元组的一部分传递:

        jobs.append(pool.apply_async(process_line,(line,x,y,z,t)))

然后你在函数中隐式解包这个元组:

def process_line(line, x,y,z,t):

然后你不改变现有的值,而是用这些行创建新的值:

    x = np.append(x,float(sl[0].replace(',','')))
    y = np.append(y,float(sl[1].replace(',','')))
    z = np.append(z,float(sl[2].replace(',','')))
    t = np.append(t,float(sl[3].replace(',','')))

让我重复一遍:您不会更改原始数组(正如您所期望的那样)。相反,您只需使用旧值创建新值,然后将其分配给局部变量 xyzt。然后您离开该函数并忘记新值。我想说这永远不会在函数之外产生任何影响(也不会影响最后一个值)。

您有多种选择来解决这个问题。

  1. 使用全局变量。这是一个快速修复但不好的风格,从长远来看,你会讨厌我的这个建议。但如果您只需要它快速工作,那么这可能是您的选择。

  2. 返回您的值。创建新值后,以某种方式返回它们并确保下一次调用再次获取先前返回的值作为输入。这是函数式方法。

  3. 通过引用传递您的值。您可以通过创建一个单元素列表而不是传递 x 来做到这一点。请参阅下面的代码以了解如何执行此操作。传递引用是典型的 C 风格编程,不是很 Pythonic(但它有效)。许多 IDE 会警告你这样做,典型的 Python 开发人员将很难理解你在做什么。一个更好的变体不是使用简单的列表,而是将您的数据放入某种对象中,该对象将通过引用传递。

x_ref = [x]
y_ref = [y]
y_ref = [y]
t_ref = [t]

with open(path_file) as f:
    for line in f:
        jobs.append(pool.apply_async(process_line,(line,x_ref,y_ref,z_ref,t_ref)))

那么process_line 也需要调整以期望引用:

def process_line(line, x_ref,y_ref,z_ref,t_ref):
    sl = line.split()
    x_ref[0] = np.append(x_ref[0],float(sl[0].replace(',','')))
    y_ref[0] = np.append(y_ref[0],float(sl[1].replace(',','')))
    z_ref[0] = np.append(z_ref[0],float(sl[2].replace(',','')))
    t_ref[0] = np.append(t_ref[0],float(sl[3].replace(',','')))

【讨论】:

    猜你喜欢
    • 2017-01-18
    • 2020-06-06
    • 2019-04-08
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    相关资源
    最近更新 更多