在 python 中读取并保存具有可变列数的数据文件
Read and save data file with variable number of columns in python
我有一个 space 分隔的数据文件,看起来像这样(只是一个切片)
Wavelength Ele Excit loggf D0
11140.324 108.0 3.44 -7.945 4.395
11140.357 26.1 12.09 -2.247
11140.361 108.0 2.39 -8.119 4.395
11140.365 25.0 5.85 -9.734
11140.388 23.0 4.56 -4.573
11140.424 608.0 5.12 -10.419 11.09
11140.452 606.0 2.12 -11.054 6.25
11140.496 108.0 2.39 -8.119 4.395
11140.509 606.0 1.70 -7.824 6.25
第 1 部分
首先我想阅读 lá np.loadtxt
的文件。这不起作用,所以我尝试了
d = np.genfromtxt('file.dat', skiprows=1, filling_value=0.0, missing_values=' ')
以及它的不同版本。全部报错:Line #3 (got 4 columns instead of 5)
。我想我已经接近能够读取该文件了。请注意,我更喜欢 np.genfromtxt
之类的解决方案,而不是打开文件并逐行查看它:
with open('test.dat', 'r') as lines:
for line in lines:
# put numbers in arrays/lists
第 2 部分
读取文件成功后,需要以特定格式保存。简而言之,此文件将作为 Fotran 程序的输入,每列 10 spaces 用于数字。如果没有最后一列 (D0
),我可以使用(有一列我不使用,因此 '%27.1f'
)
fmt_ = ('%9.2f', '%7.1f', '%11.2f','%10.3f', '%27.1f')
np.savetxt('output.dat', data, fmt=fmt_)
但我怀疑这也行不通。所以 s np.genfromtxt
用于保存可能会有所帮助。
帮助全部,部分或只是一些指导表示赞赏。
第 1 部分:
使用pandas。它是专门为处理这种情况而设计的:
import pandas as pd
df = pd.read_csv('test.csv', sep='\s+')
print(df)
给你:
Wavelength Ele Excit loggf D0
0 11140.324 108.0 3.44 -7.945 4.395
1 11140.357 26.1 12.09 -2.247 NaN
2 11140.361 108.0 2.39 -8.119 4.395
3 11140.365 25.0 5.85 -9.734 NaN
4 11140.388 23.0 4.56 -4.573 NaN
5 11140.424 608.0 5.12 -10.419 11.090
6 11140.452 606.0 2.12 -11.054 6.250
7 11140.496 108.0 2.39 -8.119 4.395
8 11140.509 606.0 1.70 -7.824 6.250
第 2 部分
您也可以为此使用 pandas,尽管正确设置格式有点复杂:
formatters = ['{: >9.2f}'.format, '{: >7.1f}'.format,
'{: >11.2f}'.format,'{: >10.3f}'.format,
lambda x: ' '*27 if np.isnan(x) else '{: >27.1f}'.format(x)]
lines = df.to_string(index=False, header=False, formatters=formatters)
with open('out.dat', 'w') as outfile:
outfile.write(lines)
给你:
11140.32 108.0 3.44 -7.945 4.4
11140.36 26.1 12.09 -2.247
11140.36 108.0 2.39 -8.119 4.4
11140.36 25.0 5.85 -9.734
11140.39 23.0 4.56 -4.573
11140.42 608.0 5.12 -10.419 11.1
11140.45 606.0 2.12 -11.054 6.2
11140.50 108.0 2.39 -8.119 4.4
11140.51 606.0 1.70 -7.824 6.2
这是包含您的数据的示例 运行 的一部分。
In [62]: txt=b"""Wavelength Ele Excit loggf D0
11140.324 108.0 3.44 -7.945 4.395
...
11140.509 606.0 1.70 -7.824 6.25 """
In [63]: txt=txt.splitlines()
In [64]: def foo(astr):
# add a 'NaN' field to the short lines
if len(astr)<35:
astr += b' NaN' # or filler of your choice
return astr
....:
In [65]: data=np.loadtxt([foo(t) for t in txt], skiprows=1)
In [66]: data
Out[66]:
array([[ 1.11403240e+04, 1.08000000e+02, 3.44000000e+00,
-7.94500000e+00, 4.39500000e+00],
[ 1.11403570e+04, 2.61000000e+01, 1.20900000e+01,
-2.24700000e+00, nan],
...
[ 1.11405090e+04, 6.06000000e+02, 1.70000000e+00,
-7.82400000e+00, 6.25000000e+00]])
In [67]: np.savetxt('test.dat',x,fmt=fmt_)
In [69]: cat test.dat
11140.32 108.0 3.44 -7.945 4.4
11140.36 26.1 12.09 -2.247 nan
11140.36 108.0 2.39 -8.119 4.4
11140.36 25.0 5.85 -9.734 nan
...
11140.51 606.0 1.70 -7.824 6.2
文件可以像这样通过foo
传递:
with open('test.dat') as f:
xx = np.loadtxt((foo(t) for t in f),skiprows=1)
savetxt
本质上是逐行 write
,因此编写您自己的版本并不难。例如
In [120]: asbytes=np.lib.npyio.asbytes
In [121]: fmt__='%9.2f %7.1f %11.2f %10.3f %10.1f'
In [122]: with open('test.dat','wb') as f:
for row in x:
f.write(asbytes(fmt__%tuple(row)+'\n'))
.....:
In [123]: cat test.dat
11140.32 108.0 3.44 -7.945 4.4
11140.36 26.1 12.09 -2.247 nan
11140.36 108.0 2.39 -8.119 4.4
11140.36 25.0 5.85 -9.734 nan
...
11140.51 606.0 1.70 -7.824 6.2
有了这个就不难测试每一行,并对带有 nan
.
的行使用不同的格式
我有一个 space 分隔的数据文件,看起来像这样(只是一个切片)
Wavelength Ele Excit loggf D0
11140.324 108.0 3.44 -7.945 4.395
11140.357 26.1 12.09 -2.247
11140.361 108.0 2.39 -8.119 4.395
11140.365 25.0 5.85 -9.734
11140.388 23.0 4.56 -4.573
11140.424 608.0 5.12 -10.419 11.09
11140.452 606.0 2.12 -11.054 6.25
11140.496 108.0 2.39 -8.119 4.395
11140.509 606.0 1.70 -7.824 6.25
第 1 部分
首先我想阅读 lá np.loadtxt
的文件。这不起作用,所以我尝试了
d = np.genfromtxt('file.dat', skiprows=1, filling_value=0.0, missing_values=' ')
以及它的不同版本。全部报错:Line #3 (got 4 columns instead of 5)
。我想我已经接近能够读取该文件了。请注意,我更喜欢 np.genfromtxt
之类的解决方案,而不是打开文件并逐行查看它:
with open('test.dat', 'r') as lines:
for line in lines:
# put numbers in arrays/lists
第 2 部分
读取文件成功后,需要以特定格式保存。简而言之,此文件将作为 Fotran 程序的输入,每列 10 spaces 用于数字。如果没有最后一列 (D0
),我可以使用(有一列我不使用,因此 '%27.1f'
)
fmt_ = ('%9.2f', '%7.1f', '%11.2f','%10.3f', '%27.1f')
np.savetxt('output.dat', data, fmt=fmt_)
但我怀疑这也行不通。所以 s np.genfromtxt
用于保存可能会有所帮助。
帮助全部,部分或只是一些指导表示赞赏。
第 1 部分:
使用pandas。它是专门为处理这种情况而设计的:
import pandas as pd
df = pd.read_csv('test.csv', sep='\s+')
print(df)
给你:
Wavelength Ele Excit loggf D0
0 11140.324 108.0 3.44 -7.945 4.395
1 11140.357 26.1 12.09 -2.247 NaN
2 11140.361 108.0 2.39 -8.119 4.395
3 11140.365 25.0 5.85 -9.734 NaN
4 11140.388 23.0 4.56 -4.573 NaN
5 11140.424 608.0 5.12 -10.419 11.090
6 11140.452 606.0 2.12 -11.054 6.250
7 11140.496 108.0 2.39 -8.119 4.395
8 11140.509 606.0 1.70 -7.824 6.250
第 2 部分
您也可以为此使用 pandas,尽管正确设置格式有点复杂:
formatters = ['{: >9.2f}'.format, '{: >7.1f}'.format,
'{: >11.2f}'.format,'{: >10.3f}'.format,
lambda x: ' '*27 if np.isnan(x) else '{: >27.1f}'.format(x)]
lines = df.to_string(index=False, header=False, formatters=formatters)
with open('out.dat', 'w') as outfile:
outfile.write(lines)
给你:
11140.32 108.0 3.44 -7.945 4.4
11140.36 26.1 12.09 -2.247
11140.36 108.0 2.39 -8.119 4.4
11140.36 25.0 5.85 -9.734
11140.39 23.0 4.56 -4.573
11140.42 608.0 5.12 -10.419 11.1
11140.45 606.0 2.12 -11.054 6.2
11140.50 108.0 2.39 -8.119 4.4
11140.51 606.0 1.70 -7.824 6.2
这是包含您的数据的示例 运行 的一部分。
In [62]: txt=b"""Wavelength Ele Excit loggf D0
11140.324 108.0 3.44 -7.945 4.395
...
11140.509 606.0 1.70 -7.824 6.25 """
In [63]: txt=txt.splitlines()
In [64]: def foo(astr):
# add a 'NaN' field to the short lines
if len(astr)<35:
astr += b' NaN' # or filler of your choice
return astr
....:
In [65]: data=np.loadtxt([foo(t) for t in txt], skiprows=1)
In [66]: data
Out[66]:
array([[ 1.11403240e+04, 1.08000000e+02, 3.44000000e+00,
-7.94500000e+00, 4.39500000e+00],
[ 1.11403570e+04, 2.61000000e+01, 1.20900000e+01,
-2.24700000e+00, nan],
...
[ 1.11405090e+04, 6.06000000e+02, 1.70000000e+00,
-7.82400000e+00, 6.25000000e+00]])
In [67]: np.savetxt('test.dat',x,fmt=fmt_)
In [69]: cat test.dat
11140.32 108.0 3.44 -7.945 4.4
11140.36 26.1 12.09 -2.247 nan
11140.36 108.0 2.39 -8.119 4.4
11140.36 25.0 5.85 -9.734 nan
...
11140.51 606.0 1.70 -7.824 6.2
文件可以像这样通过foo
传递:
with open('test.dat') as f:
xx = np.loadtxt((foo(t) for t in f),skiprows=1)
savetxt
本质上是逐行 write
,因此编写您自己的版本并不难。例如
In [120]: asbytes=np.lib.npyio.asbytes
In [121]: fmt__='%9.2f %7.1f %11.2f %10.3f %10.1f'
In [122]: with open('test.dat','wb') as f:
for row in x:
f.write(asbytes(fmt__%tuple(row)+'\n'))
.....:
In [123]: cat test.dat
11140.32 108.0 3.44 -7.945 4.4
11140.36 26.1 12.09 -2.247 nan
11140.36 108.0 2.39 -8.119 4.4
11140.36 25.0 5.85 -9.734 nan
...
11140.51 606.0 1.70 -7.824 6.2
有了这个就不难测试每一行,并对带有 nan
.