【问题标题】:Fastest way to combine and normalise data from mutiple multi-dimensional arrays组合和规范化来自多个多维数组的数据的最快方法
【发布时间】:2014-02-18 10:05:29
【问题描述】:

我有一组数据,它具有 X、Y、Z 三个维度,顺序为 24、67、95 和 8 个变量:a,b,c,d,e,f,g,h

每个变量都存储在 [X,Y,Z] numpy array() 中,即具有 24*67*95=152760 个值。

数组被组合成一个 OrderedDict() ,键是变量的名称。

因此,维度 x,y,z 的变量 a 的值由 data['a'][x][y][z] 给出

我想将此数据以标准化格式插入到 MySQL 表中,该表由 x,y,z 索引:

 ---------------------
|x|y|z|a|b|c|d|e|f|g|h|
 ---------------------
| | | | | | | | | | | |

我按以下方式执行此操作,它在 x 的每一步生成一个 67*95 = 6365 个条目的插入语句,我理解这是 MySQL 的最佳数量级:

cur = db.cursor()
Xs = 24
Ys = 67
Zs = 95    
variables = ['a','b','c','d','e','f','g','h']
for x in range(Xs):
    sql="insert into mytable (X,Y,Z"
    for variable in variables:
        sql+=","+variable
    sql+=") values"
    for y in range(Ys):
        for z in range(Zs):
            sql+="(%d,%d,%d" % (x,y,z)
            for variable in variables:
                sql+=","+str(data[variable][x][y][z])
            sql+="),"
    cur.execute(sql[:-1])

在我的四核 PC 上,X 的每次迭代运行整个循环大约需要 24 秒,而执行插入语句只占用了大约 0.5 秒。

有没有更快的方法来组合和规范内存中的这些变量?

(我知道标准化数据库可能不是此类多维数据的最佳存储格式,这是我随后将测试的内容 - 出于本问题的目的,假设它是)

谢谢!

【问题讨论】:

  • 用生成的浮点数尝试了你的代码,并用 SQL 命令生成了一个长字符串——在我的笔记本电脑上只用了不到 2.5 秒。如果我理解你的帖子是正确的,你有 24*67*95*8 个数字。其他东西似乎占用了你的时间。
  • 两个小建议:(1) Numpy 数组被索引为array[x,y,z],但你使用了array[x][y][z]。 (2) 将 SQL 命令的各个部分收集在一个列表中,最后执行str.join,以避免每次分配越来越长的字符串(在 Python 中,您不能真正附加到字符串,因为它们是不可变的)。
  • 也许更好的是,在数组上调用tolist() 方法并索引嵌套列表,因为它比索引numpy 数组更快。
  • 你尝试过 numpy 记录数组吗?这样你就只有一个 4D numpy 数组,你也可以在其中使用你的变量名
  • 谢谢stackoverflow.com/users/1879010/dietrich - 因为你的回答,我进一步调查,似乎我正在访问的数据集的结构可能比我意识到的更复杂,减慢了访问每个元素的操作.通过将数据集中的数组提取为处理前描述的形式,现在每次迭代需要 0.2 秒,而无需更改任何其他内容。仍然不确定为什么最初的数据结构如此缓慢,但至少现在可以工作了!

标签: python mysql arrays numpy


【解决方案1】:

单看这段代码,我认为有很多地方可以改进。这是我的看法:

cur = db.cursor()
Xs = 24
Ys = 67
Zs = 95    
variables = ['a','b','c','d','e','f','g','h']
sql = ("INSERT INTO mytable (X, Y, Z, " +
       ', '.join(variables) +
       ') VALUES ({0})').format(','.join(['%s'] * (len(variables) + 3)))

for x in range(Xs):
    for y in range(Ys):
        values = []
        for z in range(Zs):
            values = [x, y, z]
            for variable in variables:
                values.append(data[variable][x][y][z])
            cur.execute(sql, values)

SQL 语句只创建一次。这些值存储在一个列表中,该列表在何时传递给光标的execute() 方法。

进一步改进它的方法是将所有值存储在一个列表中并使用executemany()

all_values = []
for x in range(Xs):
    for y in range(Ys):
        values = []
        for z in range(Zs):
            values = [x, y, z]
            for variable in variables:
                values.append(data[variable][x][y][z])
            all_values.append(values)

cur.executemany(sql, all_values)

由于没有测试数据,我无法测试上述内容,但我希望很清楚发生了什么变化。

【讨论】:

  • 正如我在上面的评论中,似乎逐个元素访问原始数据结构的调用是缓慢的部分,并且通过将所有数据提取到新字典中,该过程已加快超过 100 次。但是,我也实施了您的解决方案,它再次将速度提高了一倍,因此我会将其标记为上述问题的正确答案。谢谢!
猜你喜欢
  • 2019-08-09
  • 2012-10-27
  • 1970-01-01
  • 1970-01-01
  • 2011-11-24
  • 1970-01-01
  • 2014-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多