¿Cuál es la forma más eficiente de crear un diccionario de dos columnas de marco de datos de pandas?

136

¿Cuál es la forma más eficiente de organizar el siguiente marco de datos de pandas?

datos =

Position    Letter
1           a
2           b
3           c
4           d
5           e

en un diccionario como alphabet[1 : 'a', 2 : 'b', 3 : 'c', 4 : 'd', 5 : 'e']?

usuario1083734
fuente

Respuestas:

182
In [9]: pd.Series(df.Letter.values,index=df.Position).to_dict()
Out[9]: {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'}

Comparador de velocidad (usando el método de Wouter)

In [6]: df = pd.DataFrame(randint(0,10,10000).reshape(5000,2),columns=list('AB'))

In [7]: %timeit dict(zip(df.A,df.B))
1000 loops, best of 3: 1.27 ms per loop

In [8]: %timeit pd.Series(df.A.values,index=df.B).to_dict()
1000 loops, best of 3: 987 us per loop
Jeff
fuente
20
Sin crear primero una Serie ... dict (zip (df.Position, df.Letter))
Wouter Overmeire
1
FYI ..... mi método está muy cerca del capó en cuanto a lo que está haciendo Wouter, la diferencia es que se implementa usando izip, en lugar de zip; generador hace la diferencia, supongo
Jeff
1
@WouterOvermeire esto funciona perfectamente en mi aplicación, gracias por tu contribución
user1083734
3
@Jeff dict (zip ...) el más rápido
Wouter Overmeire
3
En un DataFrame con shape = (100,2), el método de Wouter con dict (zip ...) fue 3 veces más rápido que el de Jeff - Utilicé% timeit
Quetzalcoatl
79

Encontré una forma más rápida de resolver el problema, al menos en conjuntos de datos de gran realismo utilizando: df.set_index(KEY).to_dict()[VALUE]

Prueba en 50,000 filas:

df = pd.DataFrame(np.random.randint(32, 120, 100000).reshape(50000,2),columns=list('AB'))
df['A'] = df['A'].apply(chr)

%timeit dict(zip(df.A,df.B))
%timeit pd.Series(df.A.values,index=df.B).to_dict()
%timeit df.set_index('A').to_dict()['B']

Salida:

100 loops, best of 3: 7.04 ms per loop  # WouterOvermeire
100 loops, best of 3: 9.83 ms per loop  # Jeff
100 loops, best of 3: 4.28 ms per loop  # Kikohs (me)
Kirell
fuente
18
¡Siempre desplácese hacia abajo para obtener posibles respuestas más rápidas!
Nour Wolf el
5

En Python 3.6, la forma más rápida sigue siendo la WouterOvermeire. La propuesta de Kikohs es más lenta que las otras dos opciones.

import timeit

setup = '''
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randint(32, 120, 100000).reshape(50000,2),columns=list('AB'))
df['A'] = df['A'].apply(chr)
'''

timeit.Timer('dict(zip(df.A,df.B))', setup=setup).repeat(7,500)
timeit.Timer('pd.Series(df.A.values,index=df.B).to_dict()', setup=setup).repeat(7,500)
timeit.Timer('df.set_index("A").to_dict()["B"]', setup=setup).repeat(7,500)

Resultados:

1.1214002349999777 s  # WouterOvermeire
1.1922008498571748 s  # Jeff
1.7034366211428602 s  # Kikohs
pakobill
fuente
4

TL; DR

>>> import pandas as pd
>>> df = pd.DataFrame({'Position':[1,2,3,4,5], 'Letter':['a', 'b', 'c', 'd', 'e']})
>>> dict(sorted(df.values.tolist())) # Sort of sorted... 
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
>>> from collections import OrderedDict
>>> OrderedDict(df.values.tolist())
OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)])

En largo

Explicando la solución: dict(sorted(df.values.tolist()))

Dado:

df = pd.DataFrame({'Position':[1,2,3,4,5], 'Letter':['a', 'b', 'c', 'd', 'e']})

[fuera]:

 Letter Position
0   a   1
1   b   2
2   c   3
3   d   4
4   e   5

Tratar:

# Get the values out to a 2-D numpy array, 
df.values

[fuera]:

array([['a', 1],
       ['b', 2],
       ['c', 3],
       ['d', 4],
       ['e', 5]], dtype=object)

Entonces opcionalmente:

# Dump it into a list so that you can sort it using `sorted()`
sorted(df.values.tolist()) # Sort by key

O:

# Sort by value:
from operator import itemgetter
sorted(df.values.tolist(), key=itemgetter(1))

[fuera]:

[['a', 1], ['b', 2], ['c', 3], ['d', 4], ['e', 5]]

Por último, convierta la lista de la lista de 2 elementos en un dict.

dict(sorted(df.values.tolist())) 

[fuera]:

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

Relacionado

En respuesta al comentario de @sbradbio:

Si hay varios valores para una clave específica y desea conservarlos todos, no es la forma más eficiente sino la más intuitiva:

from collections import defaultdict
import pandas as pd

multivalue_dict = defaultdict(list)

df = pd.DataFrame({'Position':[1,2,4,4,4], 'Letter':['a', 'b', 'd', 'e', 'f']})

for idx,row in df.iterrows():
    multivalue_dict[row['Position']].append(row['Letter'])

[fuera]:

>>> print(multivalue_dict)
defaultdict(list, {1: ['a'], 2: ['b'], 4: ['d', 'e', 'f']})
alvas
fuente
¿Hay alguna manera de agregar más de una columna como valor{'key': [value1, value2]}
Sbradbio
1
Compruebe la respuesta adjunta
alvas
Creo que value1 y value2 son dos columnas separadas. ¿Podría crear un diccionario con {'id': ['long', 'lat]}? largo y lat están en columnas separadas.
kms