Python:如何读取具有不同分隔符的csv文件?

3

这是我的文本文件的第一行

0.112296E+02-.121994E-010.158164E-030.158164E-030.000000E+000.340000E+030.328301E-010.000000E+00

应该有8列,有时用“-”分隔,有时用“.”。这很令人困惑,我只需要处理这个文件,而不是生成它。

第二个问题:如何处理不同的列?没有表头,所以可能是:

df.iloc[:,0] .. ?


2
没有csv编写器可以生成这样的文档。因此,它必须手动输入。另外,看起来“-”和“.”不是分隔符。难道“-”不仅仅是负数,“.”是小数吗?在这种情况下,将没有分隔符而是一定的固定宽度。在您的情况下,长度为12位数字(1.12E + 01,-1.22E-02,1.58E-04,1.58E-04,0.00E + 00,3.40E + 02,3.28E-02,0.00E + 00)。 - Ma0
这是与Ansys代码相关的内容,不是从csv编写器生成的。是的,'-'是e的负指数,'.'是小数点。无论如何,我该怎么做? - s.ping
那一行似乎对人来说很难解析!整行都是数据;没有明确定界或分隔符。 - Ébe Isaac
是的,我知道,但我需要与它一起工作,却不知道该怎么做? - s.ping
3个回答

4

正如评论所述,这很可能是一组科学计数法表示的数字,它们没有被任何分隔符分开,只是简单地拼在一起。 它可以被解释为:

0.112296E+02
-.121994E-010
.158164E-030
.158164E-030
.000000E+000
.340000E+030
.328301E-010
.000000E+00

或者作为
0.112296E+02
-.121994E-01
0.158164E-03
0.158164E-03
0.000000E+00
0.340000E+03
0.328301E-01
0.000000E+00

假设第二种解释更好,关键是要将每12个字符均匀分割。
data = [line[i:i+12] for i in range(0, len(line), 12)]

如果第一种解释更好,那么我会使用正则表达式。
import re
line = '0.112296E+02-.121994E-010.158164E-030.158164E-030.000000E+000.340000E+030.328301E-010.000000E+00'
pattern = '[+-]?\d??\.\d+E[+-]\d+'
data = re.findall(pattern, line)

编辑

显然,您需要遍历文件中的每一行,并将其添加到数据帧中。在Pandas中这是一件相当低效的事情。因此,如果您更喜欢固定宽度的解释方式,我建议使用 @Ev. Kounis 的答案:df = pd.read_fwf(myfile, widths=[12]*8)

否则,低效的方法是:

df = pd.DataFrame(columns=range(8))
with open(myfile, 'r') as f_in:
    for i, lines in enumerate(f_in):
        data = re.findall(pattern, line)
        df.loc[i] = [float(d) for d in data]

这里需要注意两点:DataFrame必须使用列名进行初始化(这里使用的是[0,1,2, 3...7]等标识符,但也许您知道更好的标识符); 而且正则表达式给我们提供了必须转换为浮点数的字符串。


重要提示,程序中E后面跟着符号和仅有的两位数字。这一点非常重要,因为'-.121994E-010'和'-.121994E-01'不会转换成相同的浮点数。所以,是的,第二种解释更好,但你正在打印第一种,对吗? - Ma0
2
你可以在正则表达式的末尾使用\d{2}代替\d+,以捕获第二种形式。 - Dunes
第一种解决方案似乎非常有效。但是如果我的文件包含多行,我该如何做呢?我需要按列解决方案。 - s.ping
我扩展了我的答案,但这开始超出了最初问题的范围 :-)(搜索其他QA) - Hugues Fontenelle

3

正如我在评论中所说,这不是多个分隔符的情况,而只是一个固定宽度格式。 Pandas 有一种读取此类文件的方法。请尝试以下内容:

df = pd.read_fwf(myfile, widths=[12]*8)
print(df)  # prints -> [0.112296E+02, -.121994E-01, 0.158164E-03, 0.158164E-03.1, 0.000000E+00, 0.340000E+03, 0.328301E-01, 0.000000E+00.1]

对于宽度,您需要提供单元格宽度,看起来像是12,以及列数,正如您所说必须为8

您可能会注意到读取结果并不完美(请注意第4个和最后一个元素中逗号前面的.1),但我正在努力改进。


或者,您可以这样“手动”完成:

myfile = r'C:\Users\user\Desktop\PythonScripts\a_file.csv'
width = 12
my_content = []
with open(myfile, 'r') as f_in:
    for lines in f_in:
        data = [float(lines[i * width:(i + 1) * width]) for i in range(len(lines) // width)]
        my_content.append(data)
print(my_content)  # prints -> [[11.2296, -0.0121994, 0.000158164, 0.000158164, 0.0, 340.0, 0.0328301, 0.0]]

每一行都将是一个嵌套列表。


1
一种可能的解决方案如下:
row = '0.112296E+02-.121994E-010.158164E-030.158164E-030.000000E+000.340000E+030.328301E-010.000000E+00'
chunckLen = 12
for i in range(0, len(row), chunckLen):
    print(row[0+i:chunckLen+i])

你可以轻松地扩展代码以处理更一般的情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接