如何将多维数组写入文本文件?

时间:2010-09-10 14:13:22

标签: python file-io numpy

在另一个问题中,如果我可以提供我遇到问题的阵列,其他用户会提供一些帮助。但是,我甚至在基本的I / O任务中失败,例如将数组写入文件。

任何人都可以解释将4x11x14 numpy数组写入文件需要什么样的循环?

这个数组由四个11 x 14数组组成,所以我应该用一个漂亮的换行符来格式化它,以便在其他数据上更容易阅读文件。

编辑:所以我尝试了numpy.savetxt函数。奇怪的是,它给出了以下错误:

TypeError: float argument required, not numpy.ndarray

我认为这是因为该函数不适用于多维数组?我想在一个文件中找到任何解决方案吗?

12 个答案:

答案 0 :(得分:173)

如果您想将其写入磁盘,以便以numpy数组的形式轻松读回,请查看numpy.save。酸洗它也可以正常工作,但是对于大型阵列来说它效率较低(不是你的,所以要么非常好)。

如果您希望它具有人类可读性,请查看numpy.savetxt

编辑:因此,似乎savetxt对于具有> 2维度的数组来说并不是一个很好的选择...但只是为了得出所有内容的完整结论:

我刚刚意识到numpy.savetxt在超过2维的ndarray上窒息......这可能是设计的,因为没有固有的方法来指示文本文件中的其他维度。

E.g。这个(2D数组)工作正常

import numpy as np
x = np.arange(20).reshape((4,5))
np.savetxt('test.txt', x)

虽然同样的事情会因3D数组失败而导致错误(TypeError: float argument required, not numpy.ndarray}:

import numpy as np
x = np.arange(200).reshape((4,5,10))
np.savetxt('test.txt', x)

一种解决方法是将3D(或更高)数组分解为2D切片。 E.g。

x = np.arange(200).reshape((4,5,10))
with file('test.txt', 'w') as outfile:
    for slice_2d in x:
        np.savetxt(outfile, slice_2d)

但是,我们的目标是明确人类可读,同时仍然可以使用numpy.loadtxt轻松阅读。因此,我们可能会更冗长,并使用注释掉的行来区分切片。默认情况下,numpy.loadtxt将忽略以#开头的任何行(或comments kwarg指定的任何字符)。 (这看起来比实际上更冗长......)

import numpy as np

# Generate some test data
data = np.arange(200).reshape((4,5,10))

# Write the array to disk
with open('test.txt', 'w') as outfile:
    # I'm writing a header here just for the sake of readability
    # Any line starting with "#" will be ignored by numpy.loadtxt
    outfile.write('# Array shape: {0}\n'.format(data.shape))

    # Iterating through a ndimensional array produces slices along
    # the last axis. This is equivalent to data[i,:,:] in this case
    for data_slice in data:

        # The formatting string indicates that I'm writing out
        # the values in left-justified columns 7 characters in width
        # with 2 decimal places.  
        np.savetxt(outfile, data_slice, fmt='%-7.2f')

        # Writing out a break to indicate different slices...
        outfile.write('# New slice\n')

这会产生:

# Array shape: (4, 5, 10)
0.00    1.00    2.00    3.00    4.00    5.00    6.00    7.00    8.00    9.00   
10.00   11.00   12.00   13.00   14.00   15.00   16.00   17.00   18.00   19.00  
20.00   21.00   22.00   23.00   24.00   25.00   26.00   27.00   28.00   29.00  
30.00   31.00   32.00   33.00   34.00   35.00   36.00   37.00   38.00   39.00  
40.00   41.00   42.00   43.00   44.00   45.00   46.00   47.00   48.00   49.00  
# New slice
50.00   51.00   52.00   53.00   54.00   55.00   56.00   57.00   58.00   59.00  
60.00   61.00   62.00   63.00   64.00   65.00   66.00   67.00   68.00   69.00  
70.00   71.00   72.00   73.00   74.00   75.00   76.00   77.00   78.00   79.00  
80.00   81.00   82.00   83.00   84.00   85.00   86.00   87.00   88.00   89.00  
90.00   91.00   92.00   93.00   94.00   95.00   96.00   97.00   98.00   99.00  
# New slice
100.00  101.00  102.00  103.00  104.00  105.00  106.00  107.00  108.00  109.00 
110.00  111.00  112.00  113.00  114.00  115.00  116.00  117.00  118.00  119.00 
120.00  121.00  122.00  123.00  124.00  125.00  126.00  127.00  128.00  129.00 
130.00  131.00  132.00  133.00  134.00  135.00  136.00  137.00  138.00  139.00 
140.00  141.00  142.00  143.00  144.00  145.00  146.00  147.00  148.00  149.00 
# New slice
150.00  151.00  152.00  153.00  154.00  155.00  156.00  157.00  158.00  159.00 
160.00  161.00  162.00  163.00  164.00  165.00  166.00  167.00  168.00  169.00 
170.00  171.00  172.00  173.00  174.00  175.00  176.00  177.00  178.00  179.00 
180.00  181.00  182.00  183.00  184.00  185.00  186.00  187.00  188.00  189.00 
190.00  191.00  192.00  193.00  194.00  195.00  196.00  197.00  198.00  199.00 
# New slice
只要我们知道原始数组的形状,读回来就很容易。我们可以做numpy.loadtxt('test.txt').reshape((4,5,10))。作为一个例子(你可以在一行中做到这一点,我只是在详细说明事情):

# Read the array from disk
new_data = np.loadtxt('test.txt')

# Note that this returned a 2D array!
print new_data.shape

# However, going back to 3D is easy if we know the 
# original shape of the array
new_data = new_data.reshape((4,5,10))

# Just to check that they're the same...
assert np.all(new_data == data)

答案 1 :(得分:28)

我不确定这是否符合您的要求,因为我认为您有兴趣让人们可以阅读该文件,但如果这不是主要问题,那么只需pickle

要保存它:

import pickle

my_data = {'a': [1, 2.0, 3, 4+6j],
           'b': ('string', u'Unicode string'),
           'c': None}
output = open('data.pkl', 'wb')
pickle.dump(my_data, output)
output.close()

要读回来:

import pprint, pickle

pkl_file = open('data.pkl', 'rb')

data1 = pickle.load(pkl_file)
pprint.pprint(data1)

pkl_file.close()

答案 2 :(得分:10)

如果您不需要人类可读的输出,您可以尝试的另一个选项是将数组保存为MATLAB .mat文件,这是一个结构化数组。我鄙视MATLAB,但我可以在很少的行中读写.mat这一事实很方便。

与Joe Kington的回答不同,这样做的好处是你不需要知道.mat文件中数据的原始形状,即无需在阅读时重新塑造与使用pickle不同,MATLAB可以读取.mat文件,也可能是其他一些程序/语言。

以下是一个例子:

import numpy as np
import scipy.io

# Some test data
x = np.arange(200).reshape((4,5,10))

# Specify the filename of the .mat file
matfile = 'test_mat.mat'

# Write the array to the mat file. For this to work, the array must be the value
# corresponding to a key name of your choice in a dictionary
scipy.io.savemat(matfile, mdict={'out': x}, oned_as='row')

# For the above line, I specified the kwarg oned_as since python (2.7 with 
# numpy 1.6.1) throws a FutureWarning.  Here, this isn't really necessary 
# since oned_as is a kwarg for dealing with 1-D arrays.

# Now load in the data from the .mat that was just saved
matdata = scipy.io.loadmat(matfile)

# And just to check if the data is the same:
assert np.all(x == matdata['out'])

如果您忘记了.mat文件中指定数组的键,您可以随时执行:

print matdata.keys()

当然,您可以使用更多密钥存储许多数组。

所以是的 - 用你的眼睛看不懂,但只需要2行就可以写入和读取数据,我认为这是一个公平的权衡。

查看scipy.io.savemat的文档 和scipy.io.loadmat 以及本教程页面:scipy.io File IO Tutorial

答案 3 :(得分:7)

ndarray.tofile()也应该有效

e.g。如果你的数组被称为a

a.tofile('yourfile.txt',sep=" ",format="%s")

不知道如何获取换行格式。

修改(信用Kevin J. Black的评论here):

  

从版本1.5.0开始,np.tofile()采用可选参数   newline='\n'允许多行输出。   https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.savetxt.html

答案 4 :(得分:3)

有专门的库可以做到这一点。 (加上python的包装器)

希望这会有所帮助

答案 5 :(得分:1)

您可以在三个嵌套循环中遍历数组并将其值写入文件。对于阅读,您只需使用相同的精确循环结构。您将以完全正确的顺序获取值,以便再次正确填充数组。

答案 6 :(得分:0)

我有一种方法可以使用简单的filename.write()操作。它适用于我,但我正在处理具有~1500个数据元素的数组。

我基本上只有for循环遍历文件并在csv样式输出中逐行写入输出目标。

import numpy as np

trial = np.genfromtxt("/extension/file.txt", dtype = str, delimiter = ",")

with open("/extension/file.txt", "w") as f:
    for x in xrange(len(trial[:,1])):
        for y in range(num_of_columns):
            if y < num_of_columns-2:
                f.write(trial[x][y] + ",")
            elif y == num_of_columns-1:
                f.write(trial[x][y])
        f.write("\n")

if和elif语句用于在数据元素之间添加逗号。无论出于何种原因,当以nd数组的形式读取文件时,这些都会被删除。我的目标是将文件输出为csv,因此这种方法有助于解决这个问题。

希望这有帮助!

答案 7 :(得分:0)

Pickle最适合这些情况。假设您有一个名为x_train的ndarray。您可以将其转储到文件中,然后使用以下命令将其还原:

import pickle

###Load into file
with open("myfile.pkl","wb") as f:
    pickle.dump(x_train,f)

###Extract from file
with open("myfile.pkl","rb") as f:
    x_temp = pickle.load(f)

答案 8 :(得分:0)

将JSON模块用于多维数组,例如

65001

答案 9 :(得分:0)

Write to a file with Python's print()

import numpy as np
import sys

stdout_sys = sys.stdout
np.set_printoptions(precision=8) # Sets number of digits of precision.
np.set_printoptions(suppress=True) # Suppress scientific notations.
np.set_printoptions(threshold=sys.maxsize) # Prints the whole arrays.
with open('myfile.txt', 'w') as f:
    sys.stdout = f
    print(nparr)
    sys.stdout = stdout_sys

使用set_printoptions() to customize的对象显示方式。

答案 10 :(得分:0)

文件 I/O 通常是代码中的瓶颈。这就是为什么知道 ASCII I/O 总是比二进制 I/O 慢很多的原因很重要。我已经将一些建议的解决方案与 perfplot 进行了比较:

enter image description here

重现情节的代码:

import json
import pickle

import numpy as np
import perfplot
import scipy.io


def numpy_save(data):
    np.save("test.dat", data)


def numpy_savetxt(data):
    np.savetxt("test.txt", data)


def numpy_savetxt_fmt(data):
    np.savetxt("test.txt", data, fmt="%-7.2f")


def pickle_dump(data):
    with open("data.pkl", "wb") as f:
        pickle.dump(data, f)


def scipy_savemat(data):
    scipy.io.savemat("test.dat", mdict={"out": data})


def numpy_tofile(data):
    data.tofile("test.txt", sep=" ", format="%s")


def json_dump(data):
    with open("test.json", "w") as f:
        json.dump(data.tolist(), f)


perfplot.save(
    "out.png",
    setup=np.random.rand,
    n_range=[2 ** k for k in range(20)],
    kernels=[
        numpy_save,
        numpy_savetxt,
        numpy_savetxt_fmt,
        pickle_dump,
        scipy_savemat,
        numpy_tofile,
        json_dump,
    ],
    equality_check=None,
)

答案 11 :(得分:0)

如果您的数组是 numpy.array 或 torch.tensor 并且维度小于 4。
使用此代码。

# from util.npa2csv import Visualarr; Visualarr(x)
import numpy as np
import torch

def Visualarr(arr, out = 'array_out.txt'):
    dim = arr.ndim 
    if isinstance(arr, np.ndarray):
        # (#Images, #Chennels, #Row, #Column)
        if dim == 4:
            arr = arr.transpose(3,2,0,1)
        if dim == 3:
            arr = arr.transpose(2,0,1)

    if isinstance(arr, torch.Tensor):
        arr = arr.numpy()
    
    
    with open(out, 'w') as outfile:    
        outfile.write('# Array shape: {0}\n'.format(arr.shape))
        
        if dim == 1 or dim == 2:
            np.savetxt(outfile, arr, fmt='%-7.3f')

        elif dim == 3:
            for i, arr2d in enumerate(arr):
                outfile.write('# {0}-th channel\n'.format(i))
                np.savetxt(outfile, arr2d, fmt='%-7.3f')

        elif dim == 4:
            for j, arr3d in enumerate(arr):
                outfile.write('\n# {0}-th Image\n'.format(j))
                for i, arr2d in enumerate(arr3d):
                    outfile.write('# {0}-th channel\n'.format(i))
                    np.savetxt(outfile, arr2d, fmt='%-7.3f')

        else:
            print("Out of dimension!")

    

def test_va():
    arr = np.random.rand(4,2)
    tens = torch.rand(2,5,6,3)
    Visualarr(arr)

test_va()