Zamierzam przekonwertować zestaw Django QuerySet na pandy DataFrame
w następujący sposób:
qs = SomeModel.objects.select_related().filter(date__year=2012)
q = qs.values('date', 'OtherField')
df = pd.DataFrame.from_records(q)
Działa, ale czy istnieje bardziej efektywny sposób?
Odpowiedzi:
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')))
Powyższe pokazuje, jak robię to samo. Najbardziej użytecznym dodatkiem jest określenie, które pola Cię interesują. Jeśli jest to tylko podzbiór dostępnych pól, którymi jesteś zainteresowany, to dałoby to wzrost wydajności, jak sobie wyobrażam.
źródło
DataFrame.from_records()
działa lepiej, tjdf = pd.DataFrame.from_records(BlogPost.objects.all().values())
.BlogPost
ma być taki sam jak jegoSomeModel
?Django Pandas rozwiązuje to dość dobrze: https://github.com/chrisdev/django-pandas/
Z 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)
źródło
df = read_frame(qs, fieldnames=['age', 'wage', 'full_name'])
Konwersja zestawu zapytań na values_list () będzie bardziej wydajna w pamięci niż bezpośrednio na wartości (). Ponieważ metoda values () zwraca zestaw zapytań zawierający listę dict (pary klucz: wartość), lista_wartości () zwraca tylko listę krotek (czyste dane). Zaoszczędzi to około 50% pamięci, wystarczy ustawić informacje o kolumnie podczas wywoływania pd.DataFrame ().
Przetestowałem to w moim projekcie z danymi> 1 miliona wierszy, pamięć szczytowa została zmniejszona z 2G do 1G.
źródło
Z perspektywy Django (nie jestem zaznajomiony
pandas
) to jest w porządku. Moim jedynym zmartwieniem jest to, że jeśli masz bardzo dużą liczbę rekordów, możesz napotkać problemy z pamięcią. Gdyby tak było, konieczne byłoby coś na wzór tego iteratora zestawu zapytań wydajnego pod względem pamięci . (Napisany fragment może wymagać przepisania, aby umożliwić inteligentne użycie.values()
).źródło
.from_records()
i nie używaćlist()
, wyeliminuje problem z wydajnością pamięci..values()
zwraca wartość,ValuesQuerySet
która buforuje wyniki, więc dla wystarczająco dużego zbioru danych będzie wymagała dużej ilości pamięci..from_records
bez rozumienia listy, aby wyeliminować obie świnie pamięci. nppd.DataFrame.from_records(qs[i].__dict__ for i in range(qs.count()))
. Ale kiedy skończysz, zostajesz z tą irytującą"_state"
kolumną.qs.values()[i]
jest znacznie szybszy i czystszy, ale myślę, że buforuje.Możesz użyć 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()
źródło