Есть ли способ векторизовать этот метод pandas apply, чтобы код работал быстрее? - PullRequest
0 голосов
/ 16 июня 2020

В настоящее время для выполнения ~ 220 тыс. Строк требуется 40-50 минут

shop    timestamp   flag
10061   1577525275  NaN
10061   1577534732  NaN
10061   1577741715  NaN
10061   1577741800  NaN
10084   1577405286  NaN
def foo(row):
    criteria = (pd.isnull(df2.flag)) & (df.shop==row.shop) & (abs(df.timestamp-row.timestamp) <= 3600)
    df2.loc[criteria, 'flag'] = 1
df2 = df.copy()
df2.apply(foo, axis=1)

Я делаю для каждой строки в df2, я проверяю main df, чтобы узнать, есть ли в том же магазине, какие еще строки имеют метку времени в течение часа, и установить флаг 1. Есть ли способ использовать numpy векторов, чтобы сделать этот запуск намного быстрее?

Ожидаемый результат :

shop    timestamp   flag
10061   1577525275  NaN
10061   1577534732  NaN
10061   1577741715  1
10061   1577741800  1
10084   1577405286  NaN

Ответы [ 2 ]

1 голос
/ 16 июня 2020

Для более быстрого выполнения вашей задачи определите следующую функцию:

def newFlag(grp):
    tt = grp.timestamp
    ind = np.nonzero(np.triu(np.absolute(tt[np.newaxis, :] - tt[:, np.newaxis]) <= 3600, 1))
    tbl = grp.flag.values
    tbl[np.concatenate(ind)] = 1
    return pd.Series(np.where(np.isnan(grp.flag), tbl, grp.flag), index=grp.index)

Затем примените ее, сохранив результат в столбце flag :

df['flag'] = df.groupby('shop').apply(newFlag).reset_index(level=0, drop=True)

Скорость этого решения основана на группировке по магазин , поэтому вам не нужно сравнивать строки, относящиеся к разным магазинам.

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

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

0 голосов
/ 16 июня 2020

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

print(df)
    shop   timestamp
0  10061  1577525275
1  10061  1577534732
2  10061  1577741715
3  10061  1577741800
4  10084  1577405286


def have_similar(df):
    df = df.sort_values('timestamp')
    df = df.assign(
        flag = (df.timestamp - df.timestamp.shift(1) < 3600) |
               (df.timestamp.shift(-1) - df.timestamp < 3600)
    )
    return df

result = df.groupby('shop').apply(have_similar).reset_index(drop=True)


print(result)
    shop   timestamp   flag
0  10061  1577525275  False
1  10061  1577534732  False
2  10061  1577741715   True
3  10061  1577741800   True
4  10084  1577405286  False
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...