【问题标题】:How to format in numpy savetxt such that zeros are saved only as "0"如何在 numpy savetxt 中格式化,以便零仅保存为“0”
【发布时间】:2014-09-01 17:25:58
【问题描述】:

我将 numpy 稀疏数组(密集)保存到 csv 中。结果是我有一个 3GB 的 csv。问题是 95% 的单元格是 0.0000。我用fmt='%5.4f'。如何格式化和保存,使零仅保存为 0 而非零浮点数以'%5.4f' 格式保存?如果我能做到这一点,我相信我可以将 3GB 降低到 300MB。

我正在使用

np.savetxt('foo.csv', arrayDense, fmt='%5.4f', delimiter = ',')

谢谢 问候

【问题讨论】:

  • 使用不同的非密集存储格式可能会产生更好的结果。请参阅stackoverflow.com/questions/8955448/… 了解如何执行此操作。
  • 另外,考虑压缩它。如果文件名以.gz 结尾,savetxtloadtxt 会自动使用 gzip;这可能是缩小文件的一种简单方法。

标签: python numpy


【解决方案1】:

如果您只保存稀疏矩阵中的非零条目(下例中的m)会更好,您可以这样做:

fname = 'row_col_data.txt'
m = m.tocoo()
a = np.vstack((m.row, m.col, m.data)).T
header = '{0}, {1}'.format(*m.shape)
np.savetxt(fname, a, header=header, fmt=('%d', '%d', '%5.4f'))

并且可以重构稀疏矩阵:

row, col, data = np.loadtxt(fname, skiprows=1, unpack=True)
shape = map(int, open(fname).next()[1:].split(','))
m = coo_matrix((data, (row, col)), shape=shape)

【讨论】:

  • 嗨卡斯特罗 - 感谢您的回复。我从中学到了很多。但是,问题是我需要 (n,m) 行列格式的 csv 和所有 m 列。这是因为我需要在 WEKA 中加载它并对其进行 SMOTE。您的方法是创建 xls ,采用 (n1,2) 行列格式,并且还缺少 0 值。
  • CT Zhu 回答正确 - 但由于某种原因,该帖子已被删除。我不能选择它作为正确答案。只有在保存时使用fmt='%.4g' 才能解决它。如果 CT Zhu 在某些日子里没有再次添加该帖子,我将添加一个答案。
  • @Run2 0 值没有丢失,问题是它们没有存储在稀疏矩阵中,这是使用这种类型矩阵的主要目的,所以我相信你没有担心0 值...如果您需要密集数组,您可以使用m.toarray(),在那里您可以看到零...
  • @Run2 如果您使用g 格式化程序,请注意有效位数由%numg 给出,因此如果您有1.12345,则需要%6g,如果您有111.12345 你需要%8g 来获得5 位小数精度
  • @Run2:还要注意%.4g 格式将转换为具有非常大或非常小的数字的科学记数法(例如1.2345e-12)。如果这是可以接受的,或者如果您的数字在不会发生这种情况的范围内,那么 CT Zhu 删除的答案肯定看起来是最简单的解决方案。
【解决方案2】:

如果你查看np.savetxt 的源代码,你会发现,虽然有相当多的代码来处理参数以及 Python 2 和 Python 3 之间的差异,但它最终是一个简单的 Python 循环在行上,其中每一行都被格式化并写入文件。因此,如果您自己编写,您不会失去任何性能。例如,下面是一个精简的函数,它写入紧凑的零:

def savetxt_compact(fname, x, fmt="%.6g", delimiter=','):
    with open(fname, 'w') as fh:
        for row in x:
            line = delimiter.join("0" if value == 0 else fmt % value for value in row)
            fh.write(line + '\n')

例如:

In [70]: x
Out[70]: 
array([[ 0.        ,  0.        ,  0.        ,  0.        ,  1.2345    ],
       [ 0.        ,  9.87654321,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  3.14159265,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ]])

In [71]: savetxt_compact('foo.csv', x, fmt='%.4f')

In [72]: !cat foo.csv
0,0,0,0,1.2345
0,9.8765,0,0,0
0,3.1416,0,0,0
0,0,0,0,0
0,0,0,0,0
0,0,0,0,0

那么,只要你在写自己的savetxt 函数,还不如让它处理稀疏矩阵,这样你就不必在保存之前将其转换为(密集)numpy 数组。 (我假设稀疏数组是使用来自scipy.sparse 的稀疏表示之一实现的。)在以下函数中,唯一的变化是从... for value in row... for value in row.A[0]

def savetxt_sparse_compact(fname, x, fmt="%.6g", delimiter=','):
    with open(fname, 'w') as fh:
        for row in x:
            line = delimiter.join("0" if value == 0 else fmt % value for value in row.A[0])
            fh.write(line + '\n')

例子:

In [112]: a
Out[112]: 
<6x5 sparse matrix of type '<type 'numpy.float64'>'
    with 3 stored elements in Compressed Sparse Row format>

In [113]: a.A
Out[113]: 
array([[ 0.        ,  0.        ,  0.        ,  0.        ,  1.2345    ],
       [ 0.        ,  9.87654321,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  3.14159265,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ]])

In [114]: savetxt_sparse_compact('foo.csv', a, fmt='%.4f')

In [115]: !cat foo.csv
0,0,0,0,1.2345
0,9.8765,0,0,0
0,3.1416,0,0,0
0,0,0,0,0
0,0,0,0,0
0,0,0,0,0

【讨论】:

  • 非常感谢沃伦。这肯定会奏效。我的稀疏矩阵是对 TfidfVectorizer 模型进行转换的结果。它返回一个 float64 二维稀疏数组,如下所示(比如我正在考虑 10 个顶级术语) \n(0, 9) 0.434529124115 (0, 8) 0.506103404485 (0, 6) 0.342163203439 (0, 5) 0.114195114018 (0, 4) 0.228240906166 (0, 0) 0.506863556372 (1, 9) 0.179650406184 (1, 8) 0.650974675792 (1, 5) 0.385568606136 (1, 3) 0.0601214405201 (1, 2) 0.117613972075 (1, 1) 0.34801600856 (1, 0) 0.27164684163 ... 。顺便说一句,0.4g fmt 也可以自己工作。
【解决方案3】:

根据您的要求,另一个可能有效的简单选项是“g”说明符。如果您更关心有效数字而不是确切地看到 x 位数并且不介意它在科学和浮点数之间切换,那么这可以很好地解决问题。例如:

np.savetxt("foo.csv", arrayDense, fmt='%5.4g', delimiter=',') 

如果 arrayDense 是这样的:

matrix([[ -5.54900000e-01,   0.00000000e+00,   0.00000000e+00],
    [  0.00000000e+00,   3.43560000e-08,   0.00000000e+00],
    [  0.00000000e+00,   0.00000000e+00,   3.43422000e+01]])

你的方式会产生:

-0.5549,0.0000,0.0000
0.0000,0.0000,0.0000
0.0000,0.0000,34.3422

上面会产生:

-0.5549,    0,    0
0,3.436e-08,    0
0,    0,34.34

这种方式也更灵活。请注意,使用“g”而不是“f”,您不会丢失数据(即 3.4356e-08 而不是 0.0000)。然而,这显然取决于您设置的精度。

【讨论】:

    猜你喜欢
    • 2014-04-28
    • 1970-01-01
    • 1970-01-01
    • 2018-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    • 1970-01-01
    相关资源
    最近更新 更多