在python中读取和保存具有可变列数的数据文件

时间:2015-03-05 19:01:17

标签: python python-3.x numpy io

我有一个空格分隔的数据文件,看起来像这样(只是一个切片)

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个空格用于数字。没有最后一列(D0),我可以使用(有一个我不使用的列,因此'%27.1f'

fmt_ = ('%9.2f', '%7.1f', '%11.2f','%10.3f', '%27.1f')
np.savetxt('output.dat', data, fmt=fmt_)

但我怀疑这也行不通。因此,保存np.genfromtxt可能会有所帮助。

对所有这些,一部分或一些指导的帮助表示赞赏。

2 个答案:

答案 0 :(得分:1)

第1部分:

使用熊猫。它专门用于处理这种情况:

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

答案 1 :(得分:1)

以下是使用您的数据运行示例的一部分。

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,因此编写自己的版本并不困难。 e.g。

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的行使用不同的格式。