Быстрый синтаксический анализ строк переменной длины с регулярной структурой в python

#python #pandas #string #split

#python #pandas #строка #разделение

Вопрос:

Я хочу разобрать текстовый файл в фрейм данных pandas. Файл содержит информацию в следующем формате,

Обратите внимание, что количество элементов N отличается для каждой строки.

 # some useless header lines
< ID1 , rest of the line I am not interested in> 
< item1.val1 item1.val2 item1.val3 item2.val1 item2.val2 item2.val3 .... itemN.val1 item2.val2 item3.val3>
< ID2 , rest of the line I am not interested in> 
< item1.val1 item1.val2 item1.val3 item2.val1 item2.val2 item2.val3 .... itemN.val1 item2.val2 item3.val3>
...
  

В настоящее время я использую этот подход,

     file = open(file_path)
    line = file.readline()
    list_dfs = []
    all_df = pd.DataFrame(columns=['ID', 'val1', 'val2', 'val3'])
    while line:
        if line[0] == '#':
            line = file.readline()
            continue
        id = line.split()[0]
        line = file.readline()
        list_dfs.append(process_line_info(line, id))
        line = file.readline()
    file.close()
    all_df = pd.concat(list_dfs)
  
 def process_line_info(txt, id)->pd.DataFrame:
    entries = txt.split()
    if not len(entries)%3 == 0:
        print('Error with line, not a triple, quitting')
        exit(-1)
    
    numItems =  math.ceil(len(entries)/3) 
    df = pd.DataFrame(columns=['val1', 'val2', 'val3', 'id'])
    for i in range(numItems):
        val1 = entries[3*i]
        val2 = entries[3*i   1]
        val3 = entries[3*i   2]
        if(val3) != -1:
            row = pd.Series(
                {
                    'val1': val1,
                    'val2': val2,
                    'val3': val3,
                    'id' : id,
                }
            )
            df = df.append(row, ignore_index=True)
    return df
  

Фрейм данных будет выглядеть примерно так,

 ID val1 val2 val3
0  234  345  112
0  111  333  232
1  ..
1  ..
1  ..
1  ..
2  ..
2  ..
3  .. 
3  ..
3  ..
3  ..
3  ..
.....
.....
N  ..
  

Есть ли способ сделать это более эффективно? Это мучительно медленно.

Вот пример,

 # some random txt
# some more random txt
1 0.851773 0.0165051 0.503764 -0.142941 -0.737434 1.02973 3.74354 
2362.39 248.498 58396 1784.7 268.254 59027 1784.7 268.254 -1
2 0.851773 0.0165051 0.503764 -0.142941 -0.737434 1.02973 3.74354 
1190.83 663.957 23056 1258.77 640.354 59070
  

Комментарии:

1. Можете ли вы предоставить ввод, который позволил бы нам воспроизвести ваш вывод? Возможно, я ошибаюсь, но я не думаю, что смогу воспроизвести этот вывод с помощью предоставленных входных данных и кода. Спасибо, это было бы полезно. По сути, покажите нам, как будут выглядеть входные данные после того, как вы прочитали файл.

Ответ №1:

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

 import io, numpy as np, pandas as pd

with open('input.txt', 'r', encoding = 'utf-8') as f:
    lines = f.read().splitlines()
    
lines = [line.strip() for line in lines]
lines = [line for line in lines if line and not line.startswith('#')]
assert len(lines) % 2 == 0, len(lines)
lines = [
    (
        int(id_line.partition(' ')[0]),
        np.loadtxt(io.StringIO(data_line), dtype = np.float64),
    )
    for id_line, data_line in zip(lines[0::2], lines[1::2])
]
ids = np.concatenate([np.full((v.size // 3,), k, dtype = np.int64) for k, v in lines])
nums = np.concatenate([v.reshape((v.size // 3, 3)) for k, v in lines])
df = pd.DataFrame(index = ids, data = nums, columns = ['val1', 'val2', 'val3'])

print(df)
  

Ответ №2:

ну, вам просто нужен переход из txt-файла в DF, вы можете использовать pandas.read_csv («путь»), и все готово