2017-02-02 48 views
2

Я ищу эффективную функцию replace в python3. Код, который у меня есть, - это выполнение задачи, но слишком медленный, поскольку я работаю с большим набором данных. Таким образом, мой приоритет - эффективность над элегантностью всякий раз, когда есть компромисс. Вот это игрушка, что я хотел бы сделать:Эффективное использование в pandas

import pandas as pd 
df = pd.DataFrame([[1,2],[3,4],[5,6]], columns = ['1st', '2nd']) 

     1st 2nd 
    0 1 2 
    1 3 4 
    2 5 6 


idxDict= dict() 
idxDict[1] = 'a' 
idxDict[3] = 'b' 
idxDict[5] = 'c' 

for k,v in idxDict.items(): 
    df ['1st'] = df ['1st'].replace(k, v) 

Что дает

 1st 2nd 
    0 a 2 
    1 b 4 
    2 c 6 

, как я хочу, но это занимает слишком много времени. Какой был бы самый быстрый способ?

Редактировать: это более целенаправленный и чистый вопрос, чем this тот, для которого решение похоже.

+0

Возможный дубликат [Pandas replace/dictionary slowown] (http://stackoverflow.com/questions/41985566/pandas-replace-dictionary-slowness) – root

ответ

3

использование map для выполнения поиска:

In [46]: 
df['1st'] = df['1st'].map(idxDict) 
df 
Out[46]: 
    1st 2nd 
0 a 2 
1 b 4 
2 c 6 

, чтобы избежать ситуации, когда нет никакого действительного ключа вы можете передать na_action='ignore'

Вы также можете использовать df['1st'].replace(idxDict), но ответить вам вопрос об эффективности:

тайминги

In [69]: 
%timeit df['1st'].replace(idxDict) 
%timeit df['1st'].map(idxDict) 

1000 loops, best of 3: 1.57 ms per loop 
1000 loops, best of 3: 1.08 ms per loop 

In [70]:  
%%timeit 
for k,v in idxDict.items(): 
    df ['1st'] = df ['1st'].replace(k, v) 

100 loops, best of 3: 3.25 ms per loop 

Таким образом, использование map является более 3x быстрее здесь

на большом наборе данных:

In [3]: 
df = pd.concat([df]*10000, ignore_index=True) 
df.shape 

Out[3]: 
(30000, 2) 

In [4]:  
%timeit df['1st'].replace(idxDict) 
%timeit df['1st'].map(idxDict) 

100 loops, best of 3: 18 ms per loop 
100 loops, best of 3: 4.31 ms per loop 

In [5]:  
%%timeit 
for k,v in idxDict.items(): 
    df ['1st'] = df ['1st'].replace(k, v) 

100 loops, best of 3: 18.2 ms per loop 

Для 30K строк Д.Ф., map составляет ~ 4 раза быстрее, так что масштабируется лучше, чем replace или перекручивание

+0

Работает отлично, но это самый быстрый способ? – splinter

+0

он должен быть быстрее, чем 'apply' или iterating, я думаю, что' map' является цитонизированным циклом. – EdChum

+0

'df ['1st']. Map (idxDict.get)' на самом деле быстрее, чем просто прохождение самого словаря. – root

0

В то время как map действительно быстрее, replace был обновлен в версии 19.2 (details here), чтобы улучшить его скорость, делая разницу значительно меньше:

In [1]: 
import pandas as pd 


df = pd.DataFrame([[1,2],[3,4],[5,6]], columns = ['1st', '2nd']) 
df = pd.concat([df]*10000, ignore_index=True) 
df.shape 

Out [1]: 
(30000, 2) 

In [2]: 
idxDict = {1:'a', 3:"b", 5:"c"} 
%timeit df['1st'].replace(idxDict, inplace=True) 
%timeit df['1st'].update(df['1st'].map(idxDict)) 

Out [2]: 
100 loops, best of 3: 12.8 ms per loop 
100 loops, best of 3: 7.95 ms per loop 

Кроме того, я изменил код EdChum для карты включить update, что, в то время как медленнее, предотвращающие значений не включен в неполной карте от изменений в NaNs.