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

时间:2018-09-17 11:26:44

标签: python pandas

我从SAP导出的数据有问题。有时,您可以在发布文本中找到换行符。一行中应该是两行,这会导致非常糟糕的数据帧。 最烦人的是,我无法让熊猫意识到这一问题,即使列数小于标题,它也只会读取那些错误的行。

data.txt错误的示例:

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

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

如果我导入此文件:

data = pd.read_csv(
    path_to_file,
    sep='~',
    encoding='latin1',
    error_bad_lines=True,
    warn_bad_lines=True)

我明白了。怎么了?

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

是否可以解决错误的换行符或告诉熊猫忽略列数小于标题的行?

只需使其完整即可。我想得到这个:

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

我尝试将和open 一起使用,并将'\ n'(换行符)替换为”(什么都没有),但这会生成一个单一的衬纸文件。这不是故意的。

2 个答案:

答案 0 :(得分:0)

您可以进行一些预处理以摆脱不必要的休息。下面是我测试过的示例。

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='')

答案 1 :(得分:0)

正确的方法是在创建时修复文件。如果无法做到这一点,则可以对文件进行预处理或使用包装器。

这是一个使用字节级包装器的解决方案,该包装器组合行,直到您具有正确数量的定界符为止。我使用字节级包装器来利用io模块的类,并尽可能添加自己的代码: <form [formGroup]="testForm"> <input idNumber formControlName="idNumberFormControl" /> <div *ngIf="testForm.get('idNumberFormControl').invalid && testForm.get('idNumberFormControl').errors.customError.inValid" style="color:red"> {{testForm.get('idNumberFormControl').errors.customError.errMsg}} </div> <button type="submit">submit</button> </form>从底层字节文件对象中读取行,并合并行以达到预期的效果分隔符的数量(仅覆盖RawIOBasereadinto

readable

然后您可以将代码更改为:

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