在Pandas中使用read_csv处理不需要的换行

2024-09-20 22:54:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我对从SAP导出的数据有问题。有时你可以在发布文本中找到一个换行符。应该在一行中的内容,然后在两行中,这会导致一个非常糟糕的数据帧。 最烦人的是,我不能让熊猫意识到这个问题,它只是读错了行,即使列数小于标题。在

错误的例子数据.txt公司名称:

MANDT~BUKRS~BELNR~GJAHR
030~01~0100650326
~2016
030~01~0100758751~2017

您可以看到,第一行在0100650326之后有一个错误的换行符。2016年属于第一排。第三条线应该是这样的。在

如果导入此文件:

^{pr2}$

我明白了。有什么不对的地方:

   MANDT  BUKRS        BELNR   GJAHR
0   30.0      1  100650326.0     NaN
1    NaN   2016          NaN     NaN
2   30.0      1  100758751.0  2016.0

是否可以修复错误的换行符,或者告诉pandas忽略列数小于header的行?在

只是为了完成它。我想要这个:

   MANDT  BUKRS      BELNR  GJAHR
0     30      1  100650326   2016
1     30      1  100758751   2016

我试图将与open一起使用,并将'\n'(换行符)替换为“”(什么都没有),但这会导致一个单一的线性文件。这不是故意的。在


Tags: 文件数据文本标题内容错误nan例子
2条回答

你可以做一些预处理来消除不必要的中断。下面是我测试的例子。在

import fileinput

with fileinput.FileInput('input.csv', inplace=True, backup='.orig.bak') as file:
    for line in file:
        print(line.replace('\n','^'), end='')

with fileinput.FileInput('input.csv', inplace=True, backup='.1.bak') as file:
    for line in file:
        print(line.replace('^~','~'), end='')

with fileinput.FileInput('input.csv', inplace=True, backup='.2.bak') as file:
    for line in file:
        print(line.replace('^','\n'), end='')

正确的方法是在创建时修复文件。如果这不可能,您可以预处理文件或使用包装器。在

下面是一个使用字节级包装器的解决方案,该包装器将行合并,直到获得正确数量的分隔符。我使用字节级包装器来利用io模块的类,并尽可能少地添加自己的代码:RawIOBase从底层字节文件对象读取行,并组合行以获得预期数量的分隔符(仅重写readinto和{})

class csv_wrapper(io.RawIOBase):
    def __init__(self, base, delim):
        self.fd = base           # underlying (byte) file object
        self.nfields = None
        self.delim = ord(delim)  # code of the delimiter (passed as a character)
        self.numl = 0            # number of line for error processing
        self._getline()          # load and process the header line
    def _nfields(self):
        # number of delimiters in current line          
        return len([c for c in self.line if c == self.delim])

    def _getline(self):
        while True:
            # loads a new line in the internal buffer
            self.line = next(self.fd)
            self.numl += 1
            if self.nfields is None:           # store number of delims if not known
                self.nfields = self._nfields()
            else:
                while self.nfields > self._nfields():  # optionaly combine lines
                    self.line = self.line.rstrip() + next(self.fd)
                    self.numl += 1
            if self.nfields != self._nfields():        # too much here...
                print("Too much fields line {}".format(self.numl))
                continue               # ignore the offending line and proceed
            self.index = 0                             # reset line pointers
            self.linesize = len(self.line)
            break
    def readinto(self, b):
        if len(b) == 0: return 0
        if self.index == self.linesize:            # if current buffer is exhausted
            try:                                   # read a new one
                self._getline()
            except StopIteration:
                return 0
        for i in range(len(b)):                    # store in passed bytearray
            if self.index == self.linesize: break
            b[i] = self.line[self.index]
            self.index += 1
        return i
    def readable(self):
        return True

然后可以将代码更改为:

^{pr2}$

相关问题 更多 >

    热门问题