Повышение эффективности обработки текстовых файлов с помощью Pandas - PullRequest
1 голос
/ 08 октября 2019

У меня есть текстовый файл с> 1 миллионом наблюдений, который я пытаюсь преобразовать в информационный фрейм. Проблема в том, что это выглядит так:

product/productId: blah blah
product/title: blue shirt
product/price: unknown
review/userId: blah blah
review/text: blah blah

product/productId: blah blah
product/title: pair of jeans
product/price: unknown
review/userId: blah blah
review/text: blah blah

Каждый блок текста является уникальным наблюдением, и мне нужно сгруппировать их и превратить в строки в аккуратном кадре данных. В общем, это более 5 миллионов строк, которые необходимо обработать.

Я довольно новичок в Python, поэтому я не совсем уверен, каким будет лучший способ убрать это. Я начал с чтения файла в Pandas df:

initialData = pd.read_csv(args["data_file"], sep="\n", header=None, dtype=str)
initialData.columns = [ "data" ]

print(initialData.head(5), "\n\n", initialData.shape)

Вывод:

                                                data
0                      product/productId:  blah blah
1   product/title: blah blah
2                             product/price: unknown
3                      review/userId: blah blah
4   review/profileName: blah blah

 (5819330, 1)

Затем я пытаюсь использовать следующую функцию, чтобы организовать данные в каждой строке в соответствующую строку сименованные столбцы:

def organize_data(df):
    df["col"] = 0
    # group lines by observation represented
    for line_count in range(0, len(df), 10):
        indices = [ line_count, line_count + 1, line_count + 2,
                    line_count + 3, line_count + 4, line_count + 5,
                    line_count + 6, line_count + 7, line_count + 8, line_count + 9 ]
        # iterate through grouped lines
        for index in indices:
            row = df.iloc[index]
            # split inputs, assign one to "col" column
            # that'll be used to assign each value to its
            # respective column
            split_row = row["data"].split(" ", 1)
            new_label = split_row[0]
            last_split = new_label.split("/")
            future_col_name = last_split[1]
            row["col"] = future_col_name
    organized_df = df.pivot(columns="col", values="data")

    return organized_df

Как вы можете себе представить, учитывая, что он перебирает буквально каждую строку в файле, он невероятно медленный. И он дает мне SettingWithCopyWarning для загрузки, так что он даже не делает то, что я хочу, когда он закончил. Как я могу справиться с этими проблемами?

Ответы [ 2 ]

1 голос
/ 08 октября 2019

Вы можете выполнить некоторую предварительную обработку ваших данных вместо использования read_csv. Я бы порекомендовал defaultdict из модуля коллекций для группировки всех столбцов в списке. Затем мы можем передать defaultdict в конструктор DataFrame, чтобы получить окончательный результат:

from collections import defaultdict
import pandas as pd

with open('reviews.txt', 'r') as f:
    lines = f.readlines()
    data = defaultdict(list)
    for line in lines:
        col,value = line.split(':')
        data[col.strip()].append(value.strip())

    df = pd.DataFrame(data)
    print(df)

   product/productId  product/title product/price review/userId review/text
0          blah blah     blue shirt       unknown     blah blah   blah blah
1          blah blah  pair of jeans       unknown     blah blah   blah blah
0 голосов
/ 08 октября 2019

Мой совет - переключиться на Dask или Spark .

Если вы хотите продолжить использование панд, попробуйте следующие советы, чтобы прочитать файл CSV: pandas.read_csv :

  1. chunksizeПараметр: который позволяет вам читать часть файлов одновременно. Например, в вашем случае вы можете использовать размер фрагмента, равный миллиону, вы получите 5 фрагментов и сможете работать с каждым фрагментом индивидуально. Таким образом, вы будете использовать итератор и chunksize=1000000, чтобы дать вам объект считывателя, который итерирует 1000000-строчный DataFrames вместо чтения всего объекта.
    Другими словами, чтобы перебирать (потенциально очень большой) файл лениво, а не считывать весь файл в память - укажите вызов chunksize to read_csv (с указанием количества строк для чтения за одну итерацию)

  2. dtype параметр: с помощью этого параметра вы можете указать тип данных каждого столбца, просто передав словарь следующим образом: {‘a’: np.float32, ‘b’: np.int32, ‘c’: ‘Int32’}
    Панды могут использовать 64-битные типы данных, в то время как 32-битныеможет быть достаточно для вас. С помощью этого трюка вы можете сэкономить 50% пространства.

...