2012-07-28 34 views
45

Ho intenzione di convertire un Django QuerySet ad un panda DataFrame come segue:Conversione Django QuerySet al panda dataframe

qs = SomeModel.objects.select_related().filter(date__year=2012) 
q = qs.values('date', 'OtherField') 
df = pd.DataFrame.from_records(q) 

Funziona, ma c'è un modo più efficiente?

+0

Hi @FrancoMariluis, mi dispiace per questo fuori di argomento: sono stai usando i panda nei progetti di Django. Puoi mostrare la grafica usando "Plotting with matplotlib" tramite le applicazioni web di django. È una soluzione valida per te? Grazie. – danihp

+0

Ciao, per mostrare la grafica in Django sto usando django-chartit, che funziona bene, ma sto pensando di usare matplotlib, che mi darebbe più flessibilità –

+0

sembra un buon modo. –

risposta

2

Dal punto di vista di Django (non ho familiarità con pandas) questo va bene. La mia unica preoccupazione è che se si dispone di un numero molto elevato di record, è possibile che si verifichino problemi di memoria. Se questo fosse il caso, sarebbe necessario qualcosa sulla falsariga di questo memory efficient queryset iterator. (Il frammento come scritto potrebbe richiedere una riscrittura per consentire l'uso intelligente di .values()).

+0

L'idea di GregoryGoltsov di usare '.from_records()' e non usare 'list()' eliminerà il problema dell'efficienza della memoria. – hobs

+1

Il problema dell'efficienza della memoria si trova sul lato Django. ['.values ​​()'] (https://docs.djangoproject.com/en/1.7/ref/models/querysets/#django.db.models.query.QuerySet.values) restituisce un 'ValuesQuerySet' che memorizza nella cache i risultati quindi, per un set di dati abbastanza grande, sarà abbastanza ricco di memoria. –

+0

Ah sì. Dovresti indicizzare nel queryset * e * usare '.from_records' senza la comprensione delle liste per eliminare entrambi i maiali della memoria. per esempio. 'pd.DataFrame.from_records (qs [i] .__ dict__ per i in range (qs.count()))'. Ma hai finito con quella fastidiosa colonna "_state" 'quando hai finito. 'qs.values ​​() [i]' è molto più veloce e più pulito, ma penso che crei cache. – hobs

40
import pandas as pd 
import datetime 
from myapp.models import BlogPost 

df = pd.DataFrame(list(BlogPost.objects.all().values())) 
df = pd.DataFrame(list(BlogPost.objects.filter(date__gte=datetime.datetime(2012, 5, 1)).values())) 

# limit which fields 
df = pd.DataFrame(list(BlogPost.objects.all().values('author', 'date', 'slug'))) 

Quanto sopra è come faccio la stessa cosa. L'aggiunta più utile è specificare i campi a cui sei interessato. Se è solo un sottoinsieme dei campi disponibili a cui sei interessato, ciò darebbe un miglioramento delle prestazioni che immagino.

+16

L'uso di 'list()' sembra essere stato deprecato (sono su panda 0.12). L'uso di 'DataFrame.from_records()' funziona meglio, ad esempio 'df = pd.DataFrame.from_records (BlogPost.objects.all(). Values ​​())'. – gregoltsov

+0

Sarebbe più chiaro se questo usasse i nomi dalla domanda OP. Ad esempio, "BlogPost" dovrebbe essere uguale al suo "SomeModel"? –

0

È forse possibile utilizzare model_to_dict

import datetime 
from django.forms import model_to_dict 
pallobjs = [ model_to_dict(pallobj) for pallobj in PalletsManag.objects.filter(estado='APTO_PARA_VENTA')] 
df = pd.DataFrame(pallobjs) 
df.head() 
9

Django Pandas risolve questo piuttosto ordinatamente: https://github.com/chrisdev/django-pandas/

Dal README:

class MyModel(models.Model): 
    full_name = models.CharField(max_length=25) 
    age = models.IntegerField() 
    department = models.CharField(max_length=3) 
    wage = models.FloatField() 

from django_pandas.io import read_frame 
qs = MyModel.objects.all() 
df = read_frame(qs) 
+2

In che modo i panda Django gestiscono dataset di grandi dimensioni? https://github.com/chrisdev/django-pandas/blob/master/django_pandas/io.py#L107 Questa riga mi spaventa, perché penso che significhi che l'intero set di dati verrà caricato in memoria in una sola volta. –