2017-02-02 3 views
2

Je cherche à utiliser la fonction replace de manière efficace dans python3. Le code que j'ai a atteint la tâche, mais il est beaucoup trop lent, car je travaille avec un grand ensemble de données. Ainsi, ma priorité est l'efficacité plutôt que l'élégance à chaque fois qu'il y a un compromis. Voici un jouet de ce que je voudrais faire:En utilisant remplacer efficacement dans les 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) 

Ce qui donne

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

que je veux, mais il prend beaucoup trop de temps. Quel serait le moyen le plus rapide? Editer: c'est une question plus précise et mieux ciblée que celle de this, pour laquelle la solution est similaire.

+0

Reproduction possible de [Pandas remplacer/dictionnaire lenteur] (http://stackoverflow.com/questions/41985566/pandas-replace-dictionary-slowness) – root

Répondre

3

utilisation map pour effectuer une recherche:

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

pour éviter la situation où il n'y a pas de clé valide, vous pouvez passer na_action='ignore'

Vous pouvez également utiliser df['1st'].replace(idxDict) mais pour vous répondre à la question sur l'efficacité:

horaires

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 

Donc, en utilisant map est plus 3x plus rapide ici

sur un ensemble de données plus vaste:

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 

Pour 30K ligne df, map est ~ 4x plus vite il adapte mieux que replace ou boucle

+0

Fonctionne parfaitement, mais est-ce le moyen le plus rapide? – splinter

+0

il devrait être plus rapide que 'apply' ou itératif, je pense que' map' est une boucle cythonisée. – EdChum

+0

'df ['1st']. Map (idxDict.get)' est en fait plus rapide que le simple passage du dictionnaire lui-même. – root

0

Alors que map est en effet plus rapide, replace a été mis à jour dans la version 19.2 (details here) pour améliorer sa vitesse, ce qui réduit considérablement la différence:

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 

De plus, j'ai modifié le code EdChum pour carte d'inclure update, qui, bien que plus lents, empêche les valeurs non incluses dans une carte incomplète d'être changé à Nans.