Самый быстрый способ сравнить строку и предыдущую строку в кадре данных pandas с миллионами строк

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

Например, это упрощенная версия моей проблемы:

User Time Col1 newcol1 newcol2 newcol3 newcol4 0 1 6 [cat, dog, goat] 0 0 0 0 1 1 6 [cat, sheep] 0 0 0 0 2 1 12 [sheep, goat] 0 0 0 0 3 2 3 [cat, lion] 0 0 0 0 4 2 5 [fish, goat, lemur] 0 0 0 0 5 3 9 [cat, dog] 0 0 0 0 6 4 4 [dog, goat] 0 0 0 0 7 4 11 [cat] 0 0 0 0 

На данный момент у меня есть функция, которая перебирает и вычисляет значения для « newcol1 » и « newcol2 » в зависимости от того, изменился ли « User » с предыдущей строки, а также отличается ли разница в значениях « Time » больше 1. Он также смотрит на первое значение в массивах, хранящихся в « Col1 » и « Col2 », и обновляет « newcol3 » и « newcol4 », если эти значения изменились с предыдущей строки.

Вот псевдокод для того, что я делаю в настоящее время (поскольку я упростил проблему, которую я не тестировал, но это очень похоже на то, что я на самом деле делаю в ноутбуке ipython):

  def myJFunc(df): ... #initialize jnum counter ... jnum = 0; ... #loop through each row of dataframe (not including the first/zeroeth) ... for i in range(1,len(df)): ... #has user changed? ... if df.User.loc[i] == df.User.loc[i-1]: ... #has time increased by more than 1 (hour)? ... if abs(df.Time.loc[i]-df.Time.loc[i-1])>1: ... #update new columns ... df['newcol2'].loc[i-1] = 1; ... df['newcol1'].loc[i] = 1; ... #increase jnum ... jnum += 1; ... #has content changed? ... if df.Col1.loc[i][0] != df.Col1.loc[i-1][0]: ... #record this change ... df['newcol4'].loc[i-1] = [df.Col1.loc[i-1][0], df.Col2.loc[i][0]]; ... #different user? ... elif df.User.loc[i] != df.User.loc[i-1]: ... #update new columns ... df['newcol1'].loc[i] = 1; ... df['newcol2'].loc[i-1] = 1; ... #store jnum elsewhere (code not included here) and reset jnum ... jnum = 1; 

Теперь мне нужно применить эту функцию к нескольким миллионам строк, и это невозможно медленно, поэтому я пытаюсь найти лучший способ ускорить ее. Я слышал, что Cython может увеличить скорость функций, но у меня нет опыта с ним (и я новичок в pandas и python). Возможно ли передать две строки данных в качестве аргументов функции, а затем использовать Cython для ее ускорения или было бы необходимо создать новые столбцы с значениями « diff » в них, чтобы функция только считывала и записывала в один строка кадра данных за раз, чтобы извлечь выгоду из использования Cython? Любые другие быстрые трюки будут очень благодарны!

(Что касается использования .loc, я сравнивал .loc, .iloc и .ix, и этот был немного быстрее, так что это единственная причина, по которой я использую это в настоящее время)

(Кроме того, мой столбец User в действительности является unicode not int, что может быть проблематичным для скорейшего сравнения)

2 Solutions collect form web for “Самый быстрый способ сравнить строку и предыдущую строку в кадре данных pandas с миллионами строк”

Я думал так же, как Энди, только с groupby добавил, и я думаю, что это дополняет ответ Энди. Добавление groupby просто приведет к положению NaN в первой строке всякий раз, когда вы выполняете diff или shift . (Обратите внимание, что это не попытка точного ответа, просто для того, чтобы набросать некоторые основные методы.)

 df['time_diff'] = df.groupby('User')['Time'].diff() df['Col1_0'] = df['Col1'].apply( lambda x: x[0] ) df['Col1_0_prev'] = df.groupby('User')['Col1_0'].shift() User Time Col1 time_diff Col1_0 Col1_0_prev 0 1 6 [cat, dog, goat] NaN cat NaN 1 1 6 [cat, sheep] 0 cat cat 2 1 12 [sheep, goat] 6 sheep cat 3 2 3 [cat, lion] NaN cat NaN 4 2 5 [fish, goat, lemur] 2 fish cat 5 3 9 [cat, dog] NaN cat NaN 6 4 4 [dog, goat] NaN dog NaN 7 4 11 [cat] 7 cat dog 

В качестве дополнения к вопросу Энди о хранении объектов обратите внимание, что я сделал здесь, чтобы извлечь первый элемент столбца списка (и добавить также сдвинутую версию). Выполняя это так, вам нужно только сделать дорогостоящую экстракцию один раз и после этого может придерживаться стандартных методов pandas.

Используйте pandas (конструкции) и векторизовать свой код, то есть не используйте для циклов, вместо этого используйте функции pandas / numpy.

'newcol1' и 'newcol2' в зависимости от того, изменился ли «Пользователь» с предыдущей строки, а также разница в значениях «Время» больше 1.

Рассчитайте их отдельно:

 df['newcol1'] = df['User'].shift() == df['User'] df.ix[0, 'newcol1'] = True # possibly tweak the first row?? df['newcol1'] = (df['Time'].shift() - df['Time']).abs() > 1 

Мне непонятна цель Col1, но общие объекты python в столбцах плохо масштабируются (вы не можете использовать быстрый путь, а содержимое разбросано по памяти). Большую часть времени вы можете уйти от использования чего-то еще …


Cython является самым последним вариантом и не нужен в 99% случаев использования, но см. Раздел повышения производительности документации для советов.

  • Что происходит в функции журнала numpy? Есть ли способы улучшить производительность?
  • Python: почему * и ** быстрее, чем / и sqrt ()?
  • Скорость обертывания
  • Numpy с комбинаторными генераторами: как ускорить комбинации?
  • Смутно с ответом о лучшем / худшем случае для функции Python
  • как ускорить вычисление векторного перекрестного продукта
  • Улучшить pandas (PyTables?) Производительность записи таблицы HDF5
  • Администратор Django меняет форму загрузки довольно медленно
  • Python - лучший язык программирования в мире.