1

我有一个包含上部“三角形”矩阵的文本文件,省略了较低的值(下面是一个示例):

3 5 3 5 1 8 1 6 5 8

5 8 1 1 6 2 9 6 4

2 0 5 2 1 0 0 3

2 2 5 1 0 1 0

1 3 6 3 6 1

4 2 4 3 7

4 0 0 1

0 1 8

2 1

1

由于有问题的文件大小约为 10000 行,我想知道是否有一种“智能”方法可以从中生成numpy矩阵,例如使用该genfromtxt函数。但是,直接使用它会引发错误, Line #12431 (got 6 columns instead of 12437)而 usingfilling_values将不起作用,因为无法指定无缺失值占位符。

现在我不得不求助于手动打开和关闭文件:

import numpy as np
def load_updiag(filename, size):
    output = np.zeros((size,size))
    line_count = 0
    for line in f:
        data = line.split()
        output[line_count,line_count:size]= data
        line_count += 1
    return output

我觉得对于大文件大小可能不是很有可扩展性。有没有办法genfromtxt在这样的矩阵上正确使用(或 numpy 库中的任何其他优化函数)?

4

1 回答 1

2

您可以将文件中的原始数据读入字符串,然后用于np.fromstring获取矩阵上三角部分的一维数组:

with open('data.txt') as data_file:
    data = data_file.read()

arr = np.fromstring(data, sep=' ')

或者,您可以定义一个生成器来一次读取一行文件,然后用于np.fromiter从该生成器读取一维数组:

def iter_data(path):
    with open(path) as data_file:
        for line in data_file:
            yield from line.split()

arr = np.fromiter(iter_data('data.txt'), int)

如果您知道矩阵的大小(您可以从文件的第一行确定),则可以指定count关键字参数 ofnp.fromiter以便函数将准确地预先分配正确的内存量,这将更快。这就是这些函数的作用:

def iter_data(fileobj):
    for line in fileobj:
        yield from line.split()

def read_triangular_array(path):
    with open(path) as fileobj:
        n = len(fileobj.readline().split())

    count = int(n*(n+1)/2)

    with open(path) as fileobj:
        return np.fromiter(iter_data(fileobj), int, count=count)

这“浪费”了一些工作,因为它打开文件两次以读取第一行并获取条目数。“改进”是保存第一行并将其与迭代器链接到文件的其余部分,如以下代码所示:

from itertools import chain

def iter_data(fileobj):
    for line in fileobj:
        yield from line.split()

def read_triangular_array(path):
    with open(path) as fileobj:
        first = fileobj.readline().split()
        n = len(first)
        count = int(n*(n+1)/2)
        data = chain(first, iter_data(fileobj))
        return np.fromiter(data, int, count=count)

所有这些方法都会产生

>>> arr
array([ 3.,  5.,  3.,  5.,  1.,  8.,  1.,  6.,  5.,  8.,  5.,  8.,  1.,
        1.,  6.,  2.,  9.,  6.,  4.,  2.,  0.,  5.,  2.,  1.,  0.,  0.,
        3.,  2.,  2.,  5.,  1.,  0.,  1.,  0.,  1.,  3.,  6.,  3.,  6.,
        1.,  4.,  2.,  4.,  3.,  7.,  4.,  0.,  0.,  1.,  0.,  1.,  8.,
        2.,  1.,  1.])

这种紧凑的表示可能是您所需要的,但如果您想要完整的方阵,您可以分配一个正确大小的零矩阵并arr使用复制到其中np.triu_indices_from,或者您可以使用scipy.spatial.distance.squareform

>>> from scipy.spatial.distance import squareform
>>> squareform(arr)
array([[ 0.,  3.,  5.,  3.,  5.,  1.,  8.,  1.,  6.,  5.,  8.],
       [ 3.,  0.,  5.,  8.,  1.,  1.,  6.,  2.,  9.,  6.,  4.],
       [ 5.,  5.,  0.,  2.,  0.,  5.,  2.,  1.,  0.,  0.,  3.],
       [ 3.,  8.,  2.,  0.,  2.,  2.,  5.,  1.,  0.,  1.,  0.],
       [ 5.,  1.,  0.,  2.,  0.,  1.,  3.,  6.,  3.,  6.,  1.],
       [ 1.,  1.,  5.,  2.,  1.,  0.,  4.,  2.,  4.,  3.,  7.],
       [ 8.,  6.,  2.,  5.,  3.,  4.,  0.,  4.,  0.,  0.,  1.],
       [ 1.,  2.,  1.,  1.,  6.,  2.,  4.,  0.,  0.,  1.,  8.],
       [ 6.,  9.,  0.,  0.,  3.,  4.,  0.,  0.,  0.,  2.,  1.],
       [ 5.,  6.,  0.,  1.,  6.,  3.,  0.,  1.,  2.,  0.,  1.],
       [ 8.,  4.,  3.,  0.,  1.,  7.,  1.,  8.,  1.,  1.,  0.]])
于 2015-11-12T16:13:06.240 回答