Tengo un dataFrame como este:
id asn orgs 0 3320 {'Deutsche Telekom AG': 2288} 1 47886 {'Joyent': 16, 'Equinix (Netherlands) BV': 7} 2 47601 {'fusion services': 1024, 'GCE Global Maritime':16859} 3 33438 {'Highwinds Network Group': 893}
Me gustaría ordenar la columna ‘orgs’ que es en realidad un diccionario y luego extraer el par (k, v) con los valores más altos en dos columnas diferentes. Me gusta esto:
id asn org value 0 3320 'Deutsche Telekom AG' 2288 1 47886 'Joyent' 16 2 47601 'GCE Global Maritime' 16859 3 33438 'Highwinds Network Group' 893
Actualmente estoy ejecutando este código pero no se ordena correctamente, y luego no estoy seguro de cómo extraer el par con el valor más alto.
df.orgs.apply(lambda x : sorted(x.items(),key=operator.itemgetter(1),reverse=True))
que me dio una lista como esta:
id asn orgs 0 3320 [('Deutsche Telekom AG', 2288)] 1 47886 [('Joyent', 16),( 'Equinix (Netherlands) BV', 7)] 2 47601 [('GCE Global Maritime',16859),('fusion services', 1024)] 3 33438 [('Highwinds Network Group', 893)]
Ahora, ¿cómo puedo poner la clave y el valor más alto en dos columnas separadas? ¿Alguien puede ayudar?
Otro enfoque define una función que solo llama min
en el dict y devuelve una serie para que pueda asignar a múltiples columnas (cuerpo de la función tomado de la respuesta de @Alex Martelli ):
In [17]: def func(x): k = min(x, key=x.get) return pd.Series([k, x[k]]) df[['orgs', 'value']] = df['orgs'].apply(func) df Out[17]: asn id orgs value 0 3320 0 Deutsche Telekom AG 2288 1 47886 1 Equinix (Netherlands) BV 7 2 47601 2 fusion services 1024 3 33438 3 Highwinds Network Group 893
EDITAR
Si sus datos tienen datos vacíos, puede probar el len
:
In [34]: df = pd.DataFrame({'id':[0,1,2,3,4], 'asn':[3320,47886,47601,33438,56], 'orgs':[{'Deutsche Telekom AG': 2288}, {'Joyent': 16, 'Equinix (Netherlands) BV': 7}, {'fusion services': 1024, 'GCE Global Maritime':16859}, {'Highwinds Network Group': 893},{}]}) df Out[34]: asn id orgs 0 3320 0 {'Deutsche Telekom AG': 2288} 1 47886 1 {'Equinix (Netherlands) BV': 7, 'Joyent': 16} 2 47601 2 {'GCE Global Maritime': 16859, 'fusion service... 3 33438 3 {'Highwinds Network Group': 893} 4 56 4 {} In [36]: def func(x): if len(x) > 0: k = min(x, key=x.get) return pd.Series([k, x[k]]) return pd.Series([np.NaN, np.NaN]) df[['orgs', 'value']] = df['orgs'].apply(func) df Out[36]: asn id orgs value 0 3320 0 Deutsche Telekom AG 2288 1 47886 1 Equinix (Netherlands) BV 7 2 47601 2 fusion services 1024 3 33438 3 Highwinds Network Group 893 4 56 4 NaN NaN
Esto debería funcionar:
In [1]: import pandas as pd In [2]: import operator In [3]: df = pd.DataFrame({ 'id' : [0,1,2,3], ...: 'asn' : [3320, 47886, 47601, 33438], ...: 'orgs' : [{'Deutsche Telekom AG': 2288}, {'Joyent': 16, 'Equinix (Netherlands) BV': 7}, {'fusion services': 1024, 'GCE Global Maritime':16859}, {'Highwinds Network Group': 893}] ...: }) In [4]: df.orgs, df['value'] = zip(*df.orgs.apply(lambda x : sorted(x.items(),key=operator.itemgetter(1),reverse=True)[0])) In [5]: df Out[5]: asn id orgs value 0 3320 0 Deutsche Telekom AG 2288 1 47886 1 Joyent 16 2 47601 2 GCE Global Maritime 16859 3 33438 3 Highwinds Network Group 893
Utilicé zip(*
y los df.orgs
a df.orgs
y df.value
.
Para diccionarios vacíos:
In [3]: df = pd.DataFrame({ 'id' : [0,1,2,3], ...: 'asn' : [3320, 47886, 47601, 33438], ...: 'orgs' : [{'Deutsche Telekom AG': 2288}, {'Joyent': 16, 'Equinix (Netherlands) BV': 7}, {'fusion services': 1024, 'GCE Global Maritime':16859}, {}] ...: }) In [4]: df.orgs.apply(lambda x : sorted(x.items(),key=operator.itemgetter(1),reverse=True)[0] if len(x) else ('','')) Out[4]: 0 (Deutsche Telekom AG, 2288) 1 (Joyent, 16) 2 (GCE Global Maritime, 16859) 3 (, ) Name: orgs, dtype: object In [5]: df.orgs, df['value'] = zip(*df.orgs.apply(lambda x : sorted(x.items(),key=operator.itemgetter(1),reverse=True)[0] if len(x) else ('',''))) In [6]: df Out[6]: asn id orgs value 0 3320 0 Deutsche Telekom AG 2288 1 47886 1 Joyent 16 2 47601 2 GCE Global Maritime 16859 3 33438 3