2013-09-06 8 views
13

TL; DR Se i campi caricati in un DataFrame di Pandas contengono documenti JSON, come possono essere utilizzati in un modo simile a Pandas?Come accedere agli oggetti JSON incorporati in un DataFrame di Pandas?

Attualmente sto direttamente di dumping JSON/risultati del dizionario da una libreria Twitter (twython) in una collezione Mongo (chiamati utenti qui).

from twython import Twython 
from pymongo import MongoClient 

tw = Twython(...<auth>...) 

# Using mongo as object storage 
client = MongoClient() 
db = client.twitter 
user_coll = db.users 

user_batch = ... # collection of user ids 
user_dict_batch = tw.lookup_user(user_id=user_batch) 

for user_dict in user_dict_batch: 
    if(user_coll.find_one({"id":user_dict['id']}) == None): 
     user_coll.insert(user_dict) 

Dopo aver popolato questo database ho letto i documenti in Panda:

# Pull straight from mongo to pandas 
cursor = user_coll.find() 
df = pandas.DataFrame(list(cursor)) 

che funziona come magia:

Pandas is magic

mi piacerebbe essere in grado di manipolare il ' stato 'campo Stile panda (accesso diretto agli attributi). C'è un modo?

status field

EDIT: Qualcosa di simile a df [ 'stato: testo']. Lo stato ha campi come "testo", "creato_at". Un'opzione potrebbe essere appiattire/normalizzare questo campo json come this pull request a cui Wes McKinney stava lavorando.

+0

Puoi dare un esempio di ciò che vuoi veramente fare? Hai mostrato la colonna 'df ['status']', ma cosa vuoi fare con essa? – BrenBarn

+0

FWIW C'è un PR in questo senso: https://github.com/pydata/pandas/pull/4007 –

+0

Ci sono record annidati negli elementi di 'df.status'? –

risposta

20

Una soluzione è solo quello di rompere con il costruttore della serie:

In [1]: df = pd.DataFrame([[1, {'a': 2}], [2, {'a': 1, 'b': 3}]]) 

In [2]: df 
Out[2]: 
    0     1 
0 1   {u'a': 2} 
1 2 {u'a': 1, u'b': 3} 

In [3]: df[1].apply(pd.Series) 
Out[3]: 
    a b 
0 2 NaN 
1 1 3 

In alcuni casi si vorrà concat questo al dataframe al posto della fila dict:

In [4]: dict_col = df.pop(1) # here 1 is the column name 

In [5]: pd.concat([df, dict_col.apply(pd.Series)], axis=1) 
Out[5]: 
    0 a b 
0 1 2 NaN 
1 2 1 3 

Se si approfondisce, è possibile farlo alcune volte ...

+0

Rad. Questo ha funzionato bene, purché non ci fossero voci nulle. –

+0

Necessario anche per unire gli stati, aggiungendo un suffisso in modo che il nome delle collisioni abbia nomi decenti. DF2 = df [df.status.notnull()] stati = df2.status.apply (pandas.Series) DF2 = df2.merge (stati, left_index = True, right_index = True, suffissi = ("", "_status")) –

+0

dang, è fastidioso che tu abbia un caso speciale NaN, un'altra soluzione per quella parte è fillna ({}) prima. –

Problemi correlati