Производительность панд: loc против использования .head (x) в первых x строках с использованием отсортированных данных - PullRequest
0 голосов
/ 22 мая 2018

Предположим, у нас есть фрейм данных из 100 000 строк и 3 столбцов, структурированный так:

  | visitorId | timestamp | url |
1 | 1         | 11        |  A  |
2 | 1         | 12        |  B  |
3 | 2         | 21        |  A  |
4 | 3         | 31        |  A  |
5 | 3         | 32        |  C  |
.
.
n | z         | Z1        |  A  |

Этот фрейм данных всегда сортируется и хранится в переменной с именем sortedData.Сначала мы извлекаем все уникальные идентификаторы посетителей в список с именем visitors и создаем переменную пути для хранения всех URL-адресов, которые посетил этот посетитель.

visitors = sortedData.visitorId.unique()
    visitors = visitors.tolist()
    paths = []
    visitor_length = len(visitors)

Теперь я сделал для каждого посетителя цикл, чтобы найти и сохранить пройденный путь каждого посетителя, его временную метку и идентификатор и использовать его в качестве входных данных для вторичного алгоритма (не имеет значения).Я сделал это двумя способами:

A:

for visitor in visitors:
    dataResult = sortedData.loc[sortedData['visitorId'] == visitor]
    timestamps = dataResult.timestamp.tolist()
    path = dataResult.pageUrl.tolist()

    paths.append((visitor, timestamps, path))
    sortedData = sortedData.iloc[len(dataResult):]

При этом используется встроенная функция pandas loc, чтобы найти строки с совпадающими visitorId и извлечь метки времени.и пути в списки, и, наконец, добавить их вместе.Затем он удаляет первые x строк (равных длине результата запроса, то есть числу совпадений), чтобы не пропустить их в будущем при выполнении аналогичных совпадений.

Процесс повторяетсядля каждого уникального visitor в списке visitors.

По времени я обнаружил, что для завершения понадобилось около 6.31 секунд.В моем случае это был файл размером 11,7 МБ, 100 000 строк.На 1,2 ГБ файле это масштабируется до 14 часов.Таким образом, я пробовал способ B, надеясь на ускорение.

Способ B использует логику, согласно которой данные всегда сортируются, так как такой посетитель 1 в visitors всегда будет первым посетителем в sortedData, посетитель2-й и т. Д. Таким образом, я мог бы использовать функцию pandas value_counts() для подсчета вхождений x текущего посетителя и просто извлечь данные из первых x строк, используя head(x), так как они всегда будут совпадать.Таким образом, не нужно будет каждый раз перебирать и просматривать весь фрейм данных.Затем, как и раньше, я удаляю эти строки из кадра данных и повторяю цикл для следующего visitor.

B:

for visitor in visitors:
    x = sortedData.visitorId.value_counts()[visitor]
    timestamps = sortedData.timestamp.head(x).tolist()
    path = sortedData.pageUrl.head(x).tolist()

    paths.append((visitor, timestamps, path))
    sortedData = sortedData.iloc[x:]

К моему удивлению, это сделало его почти вдвое медленнымПри времени выполнения 10.89 секунд по сравнению с 6.31 от A.

Сроки loc и value_counts() оказалось, что последние были быстрее, однако при использовании в цикле верно обратное,

Учитывая, что в B мы знаем позиции посетителей, и нам нужно только перебрать первые x строк в кадре данных, а в A нам нужно каждый раз искать весь кадр данных, что вызывает эту разницу в производительности.?

В предыдущей оптимизации, которую я выполнял, с удалением уже пройденных строк, скорость была значительной, удваиваясь каждый раз, когда размер фрейма данных уменьшается вдвое, по сравнению с оставлением его целым.Это заставило меня заподозрить, что он каждый раз перебирает весь фрейм данных по пути A, за исключением случаев, когда я что-то упускаю?

Я использую MacBook Pro 2014, Python 3.6.4 (Anaconda), работающий на PyCharm 2018.

1 Ответ

0 голосов
/ 22 мая 2018

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

Взгляните на groupby , который можно использовать в вашей ситуации, если я правильно понимаю ваш вопрос.

Чтобы иметь код, похожий на тот, который у вас есть сейчас, вы можете начать так:

grouped = sortedData.groupby('visitorId')

for visitorId, group in grouped:
    print(vistorId)
    # your code here
    custom_url_algorithm(group)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...