Обработка нежелательных разрывов строк с помощью read_csv в Pandas - PullRequest
0 голосов
/ 17 сентября 2018

У меня проблема с данными, которые экспортируются из 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

Я пытался использовать с открытым и заменить '\ n' (разрыв строки) на '' (ничего), но это приводит кодин файл лайнера.Это не предназначено.

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

Правильный способ будет исправить файл во время создания. Если это невозможно, вы можете предварительно обработать файл или использовать оболочку.

Вот решение, использующее упаковщик байтового уровня, который объединяет строки, пока у вас не будет правильного количества разделителей. Я использую обертку уровня байтов, чтобы использовать классы модуля io, и добавляю как можно меньше собственного кода: RawIOBase читает строки из базового объекта файла байтов и объединяет строки, чтобы получить ожидаемое число разделители (только readinto и 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

Затем вы можете изменить свой код на:

data = pd.read_csv(
    csv_wrapper(open(path_to_file, 'rb'), '~'),
    sep='~',
    encoding='latin1',
    error_bad_lines=True,
    warn_bad_lines=True)
0 голосов
/ 17 сентября 2018

Вы можете выполнить некоторую предварительную обработку, чтобы избавиться от нежелательных перерывов. Пример ниже, который я тестировал.

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='')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...