Я пытаюсь извлечь таблицы из файлов журнала в формате .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 для пропущенных значений в зависимости от ситуации?
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 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']
Более сложная ситуация может возникнуть, если могут появиться два или более последовательных пропущенных значения (приведенный выше код будет просто инъектировать только одну нан)
Похожие вопросы
Новые вопросы
python
Python — это мультипарадигмальный многоцелевой язык программирования с динамической типизацией. Он предназначен для быстрого изучения, понимания и использования, а также обеспечивает чистый и унифицированный синтаксис. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Если у вас есть вопросы о версии Python, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas, NumPy) укажите это в тегах.