python - 从 numpy 矩阵中提取子矩阵的快速方法

标签 python python-3.x numpy submatrix

我有一个巨大的.csv我使用 read_csv 在程序中导入的文件(~2GB)然后使用 as_matrix 转换为 numpy 矩阵。生成的矩阵的形式类似于 data_mat在下面给出的示例中。我现在的问题是,我需要提取具有相同 uuid4 的 block (矩阵第一列中的条目)。然后子矩阵由另一个函数处理。看来我下面的例子并不是最好的方法。欢迎使用更快的方法。

import numpy as np
data_mat = np.array([['f9f1dc71-9457-4d17-b5d1-e63b5a766f84', 4, 3, 1],\
                     ['f9f1dc71-9457-4d17-b5d1-e63b5a766f84', 3, 1, 1],\
                     ['f9f1dc71-9457-4d17-b5d1-e63b5a766f84', 3, 3, 1],\
                     ['f9f1dc71-9457-4d17-b5d1-e63b5a766f84', 6, 1, 1],\
                     ['f35fb25b-dddc-458a-9f71-0a9c2c202719', 3, 4, 1],\
                     ['f35fb25b-dddc-458a-9f71-0a9c2c202719', 3, 1, 1],\
                     ['a4cf92fc-0624-4a00-97f6-0d21547e3183', 3, 2, 1],\
                     ['a4cf92fc-0624-4a00-97f6-0d21547e3183', 3, 9, 0],\
                     ['a4cf92fc-0624-4a00-97f6-0d21547e3183', 3, 1, 0],\
                     ['a4cf92fc-0624-4a00-97f6-0d21547e3183', 5, 1, 1],\
                     ['a4cf92fc-0624-4a00-97f6-0d21547e3183', 3, 1, 1],\
                     ['d3a8a9d0-4380-42e3-b35f-733a9f9770da', 3, 6, 10]],dtype=object)

unique_ids, indices = np.unique(data_mat[:,0],return_index=True,axis=None)
length = len(data_mat)
i=0
for idd in unique_ids:
    index = indices[i]
    k=0
    while ((index+k)<length and idd == data_mat[index+k,0]):        
        k+=1
    tmp_mat=data_mat[index:(index+k),:]
    # do something with tmp_mat ...
    print(tmp_mat)
    i+=1

最佳答案

优化这个想法就是在进入循环后最小化计算。因此,考虑到这一点,我们将重新排列数组的行,按第一列排序。然后,获取定义边界的索引。最后,开始循环并简单地对每个组进行切片,以便在每次迭代时获得一个子矩阵。使用数组时,切片实际上是免费的,因此这应该对我们有帮助。

因此,一种实现是 -

a0 = data_mat[:,0]
sidx = a0.argsort()
sd = data_mat[sidx] # sorted data_mat
idx = np.flatnonzero(np.concatenate(( [True], sd[1:,0] != sd[:-1,0], [True] )))
for i,j in zip(idx[:-1], idx[1:]):
    tmp_mat = sd[i:j]
    print tmp_mat

如果您希望将每个子矩阵存储为数组,以便将数组列表作为最终输出,只需执行 -

[sd[i:j] for i,j in zip(idx[:-1], idx[1:])]

对于排序的data_mat

对于 data_mat 已按示例所示进行排序的情况,我们可以避免对整个数组进行排序并直接使用第一列,如下所示 -

a0 = data_mat[:,0]
idx = np.flatnonzero(np.concatenate(( [True], a0[1:] != a0[:-1], [True] )))

for i,j in zip(idx[:-1], idx[1:]):
    tmp_mat = data_mat[i:j]
    print(tmp_mat)

同样,要将所有这些子矩阵作为数组列表,请使用 -

[data_mat[i:j] for i,j in zip(idx[:-1], idx[1:])]

请注意,我们使用此方法获得的子矩阵的顺序将与前一种方法中完成的排序不同。


排序data_mat的基准测试

方法 -

# @Daniel F's soln-2
def split_app(data_mat):
    idx = np.flatnonzero(data_mat[1:, 0] != data_mat[:-1, 0]) + 1
    return np.split(data_mat, idx)

# Proposed in this post
def zip_app(data_mat):
    a0 = data_mat[:,0]
    idx = np.flatnonzero(np.concatenate(( [True], a0[1:] != a0[:-1], [True] )))
    return [data_mat[i:j] for i,j in zip(idx[:-1], idx[1:])]

时间安排 -

在示例中,我们有一个最大长度 6 的子矩阵。因此,让我们扩展到一个更大的案例,并保持相同的模式 -

In [442]: a = np.random.randint(0,100000,(6*100000,4)); a[:,0].sort()

In [443]: %timeit split_app(a)
10 loops, best of 3: 88.8 ms per loop

In [444]: %timeit zip_app(a)
10 loops, best of 3: 40.2 ms per loop

In [445]: a = np.random.randint(0,1000000,(6*1000000,4)); a[:,0].sort()

In [446]: %timeit split_app(a)
1 loop, best of 3: 917 ms per loop

In [447]: %timeit zip_app(a)
1 loop, best of 3: 414 ms per loop

关于python - 从 numpy 矩阵中提取子矩阵的快速方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46023698/

相关文章:

python - LinearSVC中 `penalty`和 `loss`的含义

python - 无法在用户手动设置的 python 中打印环境变量,以便在代码的后面部分使用该变量

python-3.x - Tkinter focus_set 和 focus_force 没有按预期工作

python - 如何在windows后台运行python脚本?

python - Numpy:逐列向矩阵添加向量

python - 从骨灰盒中绘制的 Numpy

python - 在 Jupyterlab 中导入 sklearn.compose.make_column_selector 时遇到问题

Python 2.5 字典 2 键排序

python - t-SNE 的计算瓶颈是内存复杂度吗?

Python:是否有支持大量隧道的 ssh python 模块?