Какой самый быстрый способ векторизации обновления 2 параметров .loc? - PullRequest
0 голосов
/ 31 января 2019

Допустим, у меня есть следующий фрейм данных:

import pandas as pd
df = pd.DataFrame({'n': [1, 2, 3], 'm': [4, 4, 7]})
df.loc[df['m']==4,'n']=1

Выполнение этой функции .loc на относительно небольшом наборе данных (~ 50 000 выборок int32) занимает 11 мс.Есть ли способ, которым я могу ускорить это?Я надеюсь, что та же самая операция будет сокращена до 10-100 мкс.

Обновление

Я отредактировал приведенный выше пример, чтобы он был немного более кратким.

Послетестирование предложенных методов было самым быстрым:

df['n'].values[df['m'].values == 4] = 1

После применения его к набору данных из ~ 50 000 образцов это решение работало в 244 раза быстрее, чем исходный код.

Ответы [ 4 ]

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

Есть много подходов.Вы можете рассмотреть возможность изменения базового массива NumPy.Однако это не документированный или официально рекомендованный метод.

# Python 3.6.5, Pandas 0.19.2, NumPy 1.11.4
np.random.seed(0)
df = pd.DataFrame({'n': np.random.randint(0, 10, 10**5),
                   'm': np.random.randint(0, 10, 10**5)})

%timeit df.loc[df['m'] == 4, 'n'] = 1                              # 1.3 ms
%timeit df['n'].values[df['m'].values == 4] = 1                    # 436 µs
%timeit df['n'] = np.where(df['m'].values == 4, 1, df['n'])        # 751 µs
%timeit df.iloc[df['m'].values == 4, df.columns.get_loc('n')] = 1  # 880 µs
%timeit df.loc[df['m'].values == 4, 'n'] = 1                       # 1.12 ms
%timeit df['n'] = df['n'].mask(df['m'].values == 4, 1)             # 1.34 ms
0 голосов
/ 31 января 2019

Вы можете взглянуть на np.where()

df.numbers=np.where(df['more_numbers']==4,1,df.numbers)
0 голосов
/ 31 января 2019

Вы можете использовать np.where для более эффективного решения:

df = pd.DataFrame({'numbers': np.random.choice(range(5), 100_000), 
                   'more_numbers': np.random.choice(range(5), 100_000)})

%timeit df.loc[df.more_numbers==4,'numbers']=1
7.09 ms ± 658 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit np.where(df.more_numbers == 4, 1, df.numbers)
547 µs ± 20.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Так что вместо этого вы можете сделать:

df.numbers = np.where(df.more_numbers == 4, 1, df.numbers)
0 голосов
/ 31 января 2019

Так что просто сделайте с values

%timeit df.values[df['more_numbers']==4,0]=1
10000 loops, best of 3: 127 µs per loop
%timeit df.loc[df['more_numbers']==4,'numbers']=1
1000 loops, best of 3: 692 µs per loop
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...