如何更改由元组组成的矩阵中的列?

How to change a column in a matrix made of tuples?

我不确定将元组矩阵转换为更易于操作的列表形式的成本。主要优先事项是能够将矩阵的列更改为 fast 尽可能

我有一个形式为

的矩阵

[(a,b,c),(d,e,f),(g,h,i)]

它可以以 n x m 的任何大小出现,但对于此示例,我们将采用 3x3 矩阵。 我的主要目标是能够更改矩阵中任何列的值(一次只能更改一个)(例如 (b,e,h))。

我最初的尝试是将矩阵转换为列表即

[[a,b,c],[d,e,f],[g,h,i]]

哪个更容易

但我觉得将每个元组转换为列表再转换回元组的成本很高。

我的主要问题可能是如何最大限度地优化它?

In [37]: def change_column_list_comp(old_m, col, value):
    ...:     return [
    ...:         tuple(list(row[:col]) + [value] + list(row[col + 1:]))
    ...:         for row in old_m
    ...:     ]
    ...:

In [38]: def change_column_list_convert(old_m, col, value):
    ...:     list_m = list(map(list, old_m))
    ...:     for row in list_m:
    ...:         row[col] = value
    ...:
    ...:     return list(map(tuple, list_m))
    ...:

In [39]: m = [tuple('abc'), tuple('def'), tuple('ghi')]

In [40]: %timeit change_column_list_comp(m, 1, 2)
2.05 µs ± 89.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [41]: %timeit change_column_list_convert(m, 1, 2)
1.28 µs ± 121 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

看起来转换为 list、修改值并转换回 tuple 的速度更快。请注意,这可能不是编写这些函数的最有效方式。

但是,随着我们扩大矩阵,这些函数似乎开始收敛。

In [6]: m_100k = [tuple(string.printable)] * 100_000

In [7]: %timeit change_column_list_comp(m_100k, 1, 2)
163 ms ± 3.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [8]: %timeit change_column_list_convert(m_100k, 1, 2)
117 ms ± 5.67 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [42]: m_1m = [tuple(string.printable)] * 1_000_000

In [43]: %timeit change_column_list_comp(m_1m, 1, 2)
1.72 s ± 74.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [44]: %timeit change_column_list_convert(m_1m, 1, 2)
1.24 s ± 84.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

归根结底,您应该使用正确的工具来完成工作。虽然它并不真正在 OP 中,但值得一提的是 numpy 只是更好的方法。

In [13]: m_np = np.array([list('abc'), list('def'), list('ghi')])

In [17]: %timeit m_np[:, 1] = 2; m_np
610 ns ± 48.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [20]: m_np_100k = np.array([[string.printable] * 100_000])

In [21]: %timeit m_np_100k[:, 1] = 2; m_np_100k
545 ns ± 63.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [22]: m_np_1m = np.array([[string.printable] * 1_000_000])

# This might be using cached data
In [23]: %timeit m_np_1m[:, 1] = 2; m_np_1m
515 ns ± 31.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

# Avoiding cache
In [24]: %timeit m_np_1m[:, 4] = 9; m_np_1m
557 ns ± 37.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

这可能不是最公平的比较,因为我们手动返回矩阵,但您可以看到有显着改进。