使用多个 numpy 数组+标量编写 txt 文件的语法是什么以及如何再次读取它?

What is the syntax for writing txt file with multiple numpy arrays+scalars and how to read it in again?

我有 2 个相同长度的 numpy 数组,我们称它们为 A 和 B 以及 2 个标量值,名为 C 和 D。我想将这些值存储到一个 txt 文件中。我想到了如下结构:

不一定非要这种格式,我只是觉得它方便明了。我知道如何将 numpy 数组写入 txt 文件并再次读出它们,但我很难将 txt 文件写为数组和标量值的组合以及如何将它们从 txt 再次读出到 numpy。

A = np.array([1, 2, 3, 4, 5])
B = np.array([5, 4, 3, 2, 1])
C = [6]
D = [7]
np.savetxt('file.txt', (A, B))
A_B_load = np.loadtxt('file.txt')
A_load = A_B_load[0,:]
B_load= A_B_load[1,:]

这并没有给我建议的列结构,而是将数组存储在行中,但这并不重要。

我找到了一个有点不方便的解决方案,因为我必须用 0 填充标量值才能使它们与数组 A 和 B 具有相同的长度,因此必须有一个更智能的解决方案。

    A = np.array([1, 2, 3, 4, 5])
    B = np.array([5, 4, 3, 2, 1])
    C = [6]
    D = [7]
    fill = np.zeros(len(A)-1)
    C = np.concatenate((C,fill))
    D = np.concatenate((D, fill))
    np.savetxt('file.txt', (A,B,C,D))
    A_B_load = np.loadtxt('file.txt')
    A_load = A_B_load[0,:]
    B_load = A_B_load[1,:]
    C_load = A_B_load[2,0]
    D_load = A_B_load[3,0]

更聪明的解决方案可能是使用 pandas 而不是 numpy(如果您可以选择):

df = pd.concat([pd.DataFrame(arr) for arr in [A,B,C,D]], axis=1)
df.to_csv("test.txt", na_rep="", sep=" ", header=False, index=False)
a = pd.read_csv("test.txt", sep=" ", header=None).values

第一行通过连接所有数组创建数据框。 Pandas' 默认行为是用 NaN 替换缺失值。第二行写入输出文件,用空字符串替换 NaNs(因为您似乎关心文件大小)。最后一行给你一个 numpy 数组:

In [45]: a
Out[45]: 
array([[ 1.,  5.,  6.,  7.],
       [ 2.,  4., nan, nan],
       [ 3.,  3., nan, nan],
       [ 4.,  2., nan, nan],
       [ 5.,  1., nan, nan]])

编辑:

由于您输入的是整数类型,

In [20]: A.dtype
Out[20]: dtype('int64')

更准确地说是 64-bit signed integer,您可能想要找回相同的类型。

要做到这一点,只需执行以下操作:

a = pd.read_csv("test.txt", sep=" ", header=None).fillna(0).astype(np.int)

因此,您首先用零替换 NaN,因为无论如何您都不使用这些值,然后将所有内容直接转换为 np.int(pandas' Int64 将支持 NA 值,但是你应该再次将你的数组转换为 numpy 的 int64,所以这是不值得的)。

你会得到一个 pandas DataFrame:

In [63]: a
Out[63]: 
   0  1  2  3
0  1  5  6  7
1  2  4  0  0
2  3  3  0  0
3  4  2  0  0
4  5  1  0  0

您可以从中轻松取回数组:

A = a[0].to_numpy(); B=a[1].to_numpy(); C=a.iloc[0,2]; D=a.iloc[0,3]
In [123]: A = np.array([1, 2, 3, 4, 5])
     ...: B = np.array([5, 4, 3, 2, 1])
     ...: C = [6]
     ...: D = [7]

savetxt 旨在以一致的 csv 格式编写二维数组 - 整洁的 table 每行中的列数相同。

In [124]: arr = np.stack((A,B), axis=1)
In [125]: arr
Out[125]: 
array([[1, 5],
       [2, 4],
       [3, 3],
       [4, 2],
       [5, 1]])

这是一种可能的写入格式:

In [126]: np.savetxt('foo.txt', arr, fmt='%d', header=f'{C} {D}', delimiter=',')
     ...: 
In [127]: cat foo.txt
# [6] [7]
1,5
2,4
3,3
4,2
5,1

我将标量放在 header 行中,因为它们与数组不匹配。

loadtxt 可以重新创建 arr 数组:

In [129]: data = np.loadtxt('foo.txt', dtype=int, skiprows=1, delimiter=',')
In [130]: data
Out[130]: 
array([[1, 5],
       [2, 4],
       [3, 3],
       [4, 2],
       [5, 1]])

header 行可以这样读:

In [138]: with open('foo.txt') as f:
     ...:     header = f.readline().strip()
     ...:     line = header[1:]
     ...: 
In [139]: line
Out[139]: ' [6] [7]'

我应该将其保存为更易于解析的内容,例如“# 6,7”

您接受的答案在 csv

中创建了一个包含 nan 个值和空白的数据框
In [143]: import pandas as pd
In [144]: df = pd.concat([pd.DataFrame(arr) for arr in [A,B,C,D]], axis=1)
     ...: df.to_csv("test.txt", na_rep="", sep=" ", header=False, index=False)
In [145]: df
Out[145]: 
   0  0    0    0
0  1  5  6.0  7.0
1  2  4  NaN  NaN
2  3  3  NaN  NaN
3  4  2  NaN  NaN
4  5  1  NaN  NaN
In [146]: cat test.txt
1 5 6.0 7.0
2 4  
3 3  
4 2  
5 1 

请注意 np.nan 是一个浮点数,因此一些列是浮点数。 loadtxt 无法处理那些“空白”列; np.genfromtxt 在这方面更好,但它需要像 , 这样的分隔符来标记它们。

写入和读取全长数组很容易。但是混合类型变得混乱。

这是一种更易于编写和阅读的格式:

In [149]: arr = np.zeros((5,4),int)
     ...: for i,var in enumerate([A,B,C,D]):
     ...:     arr[:,i] = var
     ...: 
In [150]: arr
Out[150]: 
array([[1, 5, 6, 7],
       [2, 4, 6, 7],
       [3, 3, 6, 7],
       [4, 2, 6, 7],
       [5, 1, 6, 7]])
In [151]: np.savetxt('foo.txt', arr, fmt='%d', delimiter=',')
In [152]: cat foo.txt
1,5,6,7
2,4,6,7
3,3,6,7
4,2,6,7
5,1,6,7
In [153]: np.loadtxt('foo.txt', delimiter=',', dtype=int)
Out[153]: 
array([[1, 5, 6, 7],
       [2, 4, 6, 7],
       [3, 3, 6, 7],
       [4, 2, 6, 7],
       [5, 1, 6, 7]])