Проблемы со скоростью с пандами и списками - PullRequest
0 голосов
/ 10 января 2019

У меня есть набор данных с 4-мя строками данных, и я разбил его на куски, используя pd.read_csv (размер куска ...), а затем выполнил простой код очистки данных, чтобы получить нужный мне формат.

tqdm.pandas()
print("Merging addresses...")

df_adds = chunk.progress_apply(merge_addresses, axis = 1)

[(chunk.append(df_adds[idx][0], ignore_index=True),chunk.append(df_adds[idx][1], \
ignore_index=True)) for idx in tqdm(range(len(chunk))) \
if pd.notnull(df_adds[idx][0]['street_address'])]


def merge_addresses(row):
    row2 = pd.Series(
            {'Org_ID' : row.Org_ID,
            'org_name': row.org_name,
            'street_address': row.street_address2})
    row3 = pd.Series(
            {'Org_ID' : row.Org_ID,
            'org_name': row.org_name,
            'street_address': row.street_address3})
    return row2, row3

Я использую tqdm для анализа скорости двух операций, во-первых, функция применения панд работает нормально со скоростью около 1,5 Кбит / с, а во-вторых, понимание списка начинается со скоростью около 2 Кбит / с, а затем быстро падает до 200 л / с. Может кто-нибудь помочь объяснить, как я могу улучшить скорость этого?

Моя цель - взять street_address 2 & 3, объединить и скопировать все они, которые не равны NULL, в столбец street_address1, дублируя org_id и org_name, как требуется.

Обновление

Я пытался захватить любые NaN в merge_addresses и заменить их в виде строк. Моя цель - перенести address2 и address3 в их собственную строку (с org_name и org_id (поэтому эти два поля будут дубликатами) в том же столбце, что и address 1. Таким образом, потенциально может быть три строки для одного и того же org_id, но адреса могут отличаться.

df_adds = chunk.progress_apply(merge_addresses, axis = 1)

[(chunk.append(x[0]), chunk.append(x[1])) for x in tqdm(df_adds) if (pd.notnull(x[0][3]),pd.notnull(x[0][3]))]

def merge_addresses(row):
    if pd.isnull(row.street_address2):
        row.street_address2 = ''
    if pd.isnull(row.street_address3):
        row.street_address3 = ''
    return ([row.Org_ID, row.pub_name_adj, row.org_name, row.street_address2], [row.Org_ID, row.pub_name_adj, row.org_name, row.street_address3])

Я получаю сообщение об ошибке '<' not supported between instances of 'str' and 'int', sort order is undefined for incomparable objects result = result.union(other)

Используя tqdm, кажется, что понимание списка работает, но мучительно медленно (24 л / с)

Обновление

Просто чтобы уточнить, данные в текущем формате: enter image description here

И моя цель состоит в том, чтобы получить следующее:

enter image description here

Я играл с разными размерами чанка:

20 тыс. Строк = 70 ит / с 100к строк = 35 ит / с 200 тыс. = 31 ит / с

Похоже, что лучший размер для компромисса - 200 000 строк.

Ответы [ 2 ]

0 голосов
/ 10 января 2019

Как доказано в комментариях, узкое место здесь вызвано созданием и кормлением слишком большого количества объектов, что поглощает слишком много памяти. Также создание объекта стоит времени на выделение памяти и замедляет его

Проверено на наборе данных 100k:

# create sample dataframe
s = []
for i in range(100000):
    s.append(tuple(['name%d' %i, 'a%d' %i, 'b%d' %i]))

labels = ['name', 'addr1', 'addr2']
df = pd.DataFrame(s, columns=labels)

# addr1, addr2 to addr
s = []
for k in ['addr1', 'addr2']:
    s.append(df.filter(['id', 'name', k]).rename(columns={k:'addr'}))
result = pd.concat(s)

df.append намного медленнее, чем встроенный в список append. Пример заканчивается через несколько секунд.

0 голосов
/ 10 января 2019

Звонки DataFrame.append слишком часто могут быть дорогими (https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.append.html):

Итеративное добавление строк в DataFrame может быть более сложным в вычислительном отношении, чем одна конкатенация. Лучшее решение - добавить эти строки в список, а затем объединить список с исходным кадром DataFrame сразу.

Если вы можете, используйте pd.concat для более быстрой реализации.

...