Я пытаюсь извлечь таблицы из файлов журнала в формате .txt. Файл загружается с помощью read_csv() из pandas.

Файл журнала выглядит так:

aaa
bbb
ccc

=====================
A   B   C   D   E   F
=====================
1   2   3   4   5   6
7   8   9   1   2   3
4   5   6   7   8   9
1   2   3   4   5   6
---------------------

=====================
G     H     I     J
=====================
1           3     4
5           6     7
---------------------

=====================
K    L    M    N    O
=====================
1              2    3
4    5              6
7    8         9
---------------------

xxx
yyy
zzz

Вот несколько моментов о файле журнала:

  • Файлы начинаются и заканчиваются комментариями, которые можно игнорировать.
  • В приведенном выше примере есть три таблицы.
  • Заголовки для каждой таблицы расположены между строками "====== ..."
  • Конец каждой таблицы обозначается строкой "------..."

Мой код на данный момент:

import pandas as pd
import itertools

df = pd.read_csv("xxx.txt", sep="\n", header=None)

# delimiters for header and end-of-table

h_dl = "=" * 21
r_dl = "-" * 21

for i in range(len(df.index)-2):

    # if loop to find lines which are table headers & convert to list    

    if (df.iloc[i].any() == h_dl) & (df.iloc[i+2].any() == h_dl):

        h = df.iloc[i+1].str.split().tolist()
        h = list(itertools.chain(*h))


        # while loop to find lines which are table rows & append to one list

        x = 3
        r = []

        while True:

            if df.iloc[i+x].any() == r_dl:
                break

            r.append(df.iloc[i+x].str.split().tolist())
            x += 1

        r = list(itertools.chain(*r))

        # create pandas dataframe with header and rows obtained above
        t = pd.DataFrame(data=r, columns=h)

Этот код возвращает AssertionError: 14 columns passed, passed data had 15 columns. Я знаю, что это связано с тем, что для строк таблицы я использую .str.split(), который по умолчанию разделяется на пробелы. Поскольку в некоторых столбцах отсутствуют значения, количество элементов в заголовках таблицы и количество элементов в строках таблицы не совпадают для второй и htird таблиц. Я изо всех сил пытаюсь обойти это, так как количество пробельных символов для обозначения пропущенных значений различно для каждой таблицы.

У меня вопрос: есть ли способ учесть пропущенные значения в некоторых столбцах, чтобы я мог получить DataFrame в качестве вывода, где есть либо NULL, либо NaN для пропущенных значений в зависимости от ситуации?

1
ry-wat 16 Авг 2019 в 10:46

2 ответа

Лучший ответ

С использованием метода Виктора Руиза я добавил опции для обработки заголовков разных размеров.

= ^ .. ^ =

Описание в коде:

import re
import pandas as pd
import itertools

df = pd.read_csv("stack.txt", sep="\n", header=None)

# delimiters for header and end-of-table

h_dl = "=" * 21
r_dl = "-" * 21

for i in range(len(df.index)-2):

    # if loop to find lines which are table headers & convert to list
    if (df.iloc[i].any() == h_dl) & (df.iloc[i+2].any() == h_dl):

        h = df.iloc[i+1].str.split().tolist()
        h = list(itertools.chain(*h))

        # get header string
        head = df.iloc[i+1].to_string()
        # get space distance in header
        space_range = 0
        for result in re.findall('([ ]*)', head):
            if len(result) > 0:
                space_range = len(result)

        x = 3
        r = []
        while True:
            if df.iloc[i+x].any() == r_dl:
                break

            # strip line
            line = df.iloc[i+x].to_string()[5::]

            # collect items based on elements distance
            items = []
            for result in re.finditer('(\d+)([ ]*)', line):
                item, delimiter = result.groups()
                items.append(item)
                if len(delimiter) > space_range*2+1:
                    items.append('NaN')
                    items.append('NaN')
                if len(delimiter) < space_range*2+2 and len(delimiter) > space_range:
                    items.append('NaN')
            r.append([items])

            x += 1

        r = list(itertools.chain(*r))

        # create pandas dataframe with header and rows obtained above
        t = pd.DataFrame(data=r, columns=h)

Выход:

   A  B  C  D  E  F
0  1  2  3  4  5  6
1  7  8  9  1  2  3
2  4  5  6  7  8  9
3  1  2  3  4  5  6

   G    H  I  J
0  1  NaN  3  4
1  5  NaN  6  7

   K    L    M    N     O
0  1  NaN  NaN    2     3
1  4    5  NaN  NaN     6
2  7    8  NaN    9  None
1
Zaraki Kenpachi 16 Авг 2019 в 10:15

Может быть, это может помочь вам. Предположим, у нас есть следующая строка текста:

1           3     4

Проблема состоит в том, чтобы определить, сколько пробелов разграничивает два последовательных элемента, не учитывая, что между ними существует пропущенное значение.
Давайте рассмотрим, что 5 пробелов является разделителем, а более 5 - пропущенным значением.

Вы можете использовать регулярные выражения для анализа элементов:

from re import finditer

line = '1           3     4'
items = []

for result in finditer('(\d+)([ ]*)', line):
    item, delimiter = result.groups()
    items.append(item)
    if len(delimiter) > 5:
        items.append(nan)
print(items)

Выход:

['1', nan, '3', '4']

Более сложная ситуация может возникнуть, если могут появиться два или более последовательных пропущенных значения (приведенный выше код будет просто инъектировать только одну нан)

0
Victor Ruiz 16 Авг 2019 в 09:10