如何将文件的多列导入同一个数组在Python中?

1 投票
2 回答
63 浏览
提问于 2025-04-14 16:53

我有一个.txt文件,内容大致如下:

header line 1
header line 2
x1  y1  x4  y4  x7  y7
x2  y2  x5  y5  x8  y8
x3  y3  x6  y6  x9  y9
footer line

文件里的x和y值是用制表符分开的,在我的例子中,它们是像“2,9 ”这样的数字(包括最后的空格)。例如:

header line 1
header line 2
1,0     1,5     4,0     4,5     7,0     7,5 
2,0     2,5     5,0     5,5     8,0     8,5 
3,0     3,5     6,0     6,5     9,0     9,5 
footer line

这个文件是用latin-1编码的。我想找个简单的方法,把我的x和y转换成浮点数的numpy数组,也就是:

array([1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0])

y的处理方式也是一样的。

我首先创建了一个函数,用来把“,”替换成“.”并去掉末尾的空格:

import numpy as np

def ctf(valstr):
    return float(valstr.replace(',','.').replace(" ",""))

然后我定义了一个可变长度的字典,以便后面使用:

def dic(length):
    dic={}
    for i in range(0,length):
        dic[i]=ctf
    return dic

接着我可以“手动”读取这些列并把它们合并在一起:

xval1,yval1,xval2,yval2,xval3,yval4=np.genfromtxt("file.txt",delimiter="",unpack=True,skip_header=2,skip_footer=1,encoding="latin-1",converters=dic(6))

xvalues=np.concatenate((xval1,xval2,xval3))
yvalues=np.concatenate((yval1,yval2,yval3))

这样是可以工作的,但看起来不太美观,尤其是如果我有更多的列的话。我希望能有一种方法,只需要指定总列数(在这个例子中是6)和我想要得到的数组数量(在我的例子中是2)。

注意:我觉得转换器/字典的部分对我的问题其实并不重要。我提到它是因为我需要任何替代方案都能使用转换器,或者以其他方式达到相同的效果。

2 个回答

1

你的文本示例:

In [33]: txt='''header line 1
    ...: header line 2
    ...: 1,0     1,5     4,0     4,5     7,0     7,5 
    ...: 2,0     2,5     5,0     5,5     8,0     8,5 
    ...: 3,0     3,5     6,0     6,5     9,0     9,5 
    ...: footer line'''.splitlines()

在转换浮点数时,你不需要担心后面的空格:

In [34]: def ctf(valstr):
    ...:     return float(valstr.replace(',','.'))
    ...:         
In [35]: def dic(length):
    ...:     dic={}
    ...:     for i in range(0,length):
    ...:         dic[i]=ctf
    ...:     return dic
    ...:     

先把数据加载到一个二维数组里:

In [36]: data=np.genfromtxt(txt,skip_header=2,skip_footer=1,encoding="latin-1",converters=dic(6))

In [37]: data
Out[37]: 
array([[1. , 1.5, 4. , 4.5, 7. , 7.5],
       [2. , 2.5, 5. , 5.5, 8. , 8.5],
       [3. , 3.5, 6. , 6.5, 9. , 9.5]])

然后在每隔一列的地方进行拆分:

In [38]: data[:,::2]
Out[38]: 
array([[1., 4., 7.],
       [2., 5., 8.],
       [3., 6., 9.]])

In [39]: data[:,::2].ravel(order='F')
Out[39]: array([1., 2., 3., 4., 5., 6., 7., 8., 9.])

In [40]: data[:,1::2].ravel(order='F')
Out[40]: array([1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5])

我使用的 order='F' 和其他答案里的一样。我的 data 和他们的 tonumpy() 数组类似。

如果我保留 unpack,那么 data 就是转置后的结果,我们可以从中选择每隔一行的数据:

In [41]: data=np.genfromtxt(txt,skip_header=2,skip_footer=1,encoding="latin-1",converters=dic(6),unpack=True)

In [42]: data
Out[42]: 
array([[1. , 2. , 3. ],
       [1.5, 2.5, 3.5],
       [4. , 5. , 6. ],
       [4.5, 5.5, 6.5],
       [7. , 8. , 9. ],
       [7.5, 8.5, 9.5]])

In [43]: data[::2,:]
Out[43]: 
array([[1., 2., 3.],
       [4., 5., 6.],
       [7., 8., 9.]])

In [44]: data[::2,:].ravel()
Out[44]: array([1., 2., 3., 4., 5., 6., 7., 8., 9.])

我也可以把 data 作为一个数组列表来获取,然后把每隔一个的数组连接起来:

In [49]: [*data]=np.genfromtxt(txt,skip_header=2,skip_footer=1,encoding="latin-1",converters=dic(6),unpack=True)

In [50]: data
Out[50]: 
[array([1., 2., 3.]),
 array([1.5, 2.5, 3.5]),
 array([4., 5., 6.]),
 array([4.5, 5.5, 6.5]),
 array([7., 8., 9.]),
 array([7.5, 8.5, 9.5])]

In [51]: data[::2]
Out[51]: [array([1., 2., 3.]), array([4., 5., 6.]), array([7., 8., 9.])]

In [52]: np.concatenate(data[::2])
Out[52]: array([1., 2., 3., 4., 5., 6., 7., 8., 9.])

这只是对你 manual 拆分过程的简化。

2

你可以使用Pandas这个工具,只导入文件中相关的行,然后把这些列转换成numpy数组,变得更简单易用:

import pandas as pd

df = pd.read_csv("file.txt", header=None, skiprows=2, skipfooter=1, sep=r"\s+")

df = df.replace(",", ".", regex=True).astype(float)

n = 2

arrays = [df.iloc[:, i::n].to_numpy().flatten(order="F") for i in range(n)]
[array([1., 2., 3., 4., 5., 6., 7., 8., 9.]), array([1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5])]

撰写回答