将Django QuerySet转换为pandas DataFrame


90

我将DataFrame如下将Django QuerySet转换为pandas :

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

它有效,但是有没有更有效的方法?


嗨@FrancoMariluis,您好,对这个话题感到抱歉:您是否正在将django项目中使用熊猫。您可以通过Django Web应用程序使用“使用matplotlib进行绘图”显示图形。是一个有效的解决方案吗?谢谢。
丹妮·埃雷拉

嗨,为了在Django中显示图形,我使用的是django-chartit,它可以正常工作,但是我在考虑使用matplotlib,它将为我提供更大的灵活性
Franco Mariluis,2012年

看起来非常简单,并且可以正常工作。还有什么特别的问题吗?
德米特里·舍甫琴科

您现在的购买方式有什么问题?您是否有特别的关注?
Burhan Khalid

这是我的第一种(也是唯一的一种!)方法,但是由于我对熊猫还很陌生,所以我想看看是否还有另一种方法,但这似乎是一种不错的方法。
Franco Mariluis

Answers:


87
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')))

以上是我做同一件事的方式。最有用的添加是指定您感兴趣的字段。如果它只是您感兴趣的可用字段的子集,那么我想这将提高性能。


37
使用'list()'似乎已被弃用(我使用的是熊猫0.12)。使用DataFrame.from_records()效果更好,即df = pd.DataFrame.from_records(BlogPost.objects.all().values())
gregoltsov

2
如果这使用了OP问题中的名称,将会更加清楚。例如,BlogPost应该与他相同SomeModel吗?
Hack-R

嗨,有没有一种方法可以排除数据框中不需要的列?
Willower

19

Django Pandas相当巧妙地解决了这个问题:https : //github.com/chrisdev/django-pandas/

从自述文件:

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)

10
Django Pandas如何处理大型数据集? github.com/chrisdev/django-pandas/blob/master/django_pandas/…行使我感到恐惧,因为我认为这意味着整个数据集将被立即加载到内存中。
亚当·巴恩斯

@Ada使用指定的字段名称创建DataFrame:df = read_frame(qs, fieldnames=['age', 'wage', 'full_name'])
Gathide,

对于这个奇妙的未来谁想知道问心无愧我关于那些你,这里有一个更永久链接的来源的时候: github.com/chrisdev/django-pandas/blob/...
亚当巴恩斯

8

在values_list()上转换queryset比直接在values()上转换内存效率更高。由于方法values()返回字典列表(键:值对)的查询集,所以values_list()仅返回元组列表(纯数据)。它将节省大约50%的内存,只需要在调用pd.DataFrame()时设置列信息即可。

方法1:
    queryset = models.xxx.objects.values(“ A”,“ B”,“ C”,“ D”)
    df = pd.DataFrame(list(queryset))##消耗大量内存
    #df = pd.DataFrame.from_records(queryset)##可以使用,但是内存使用率没有太大变化

方法2:
    queryset = models.xxx.objects.values_list(“ A”,“ B”,“ C”,“ D”)
    df = pd.DataFrame(list(queryset),columns = [“ A”,“ B”,“ C”,“ D”])##这样可以节省50%的内存
    #df = pd.DataFrame.from_records(queryset,columns = [“ A”,“ B”,“ C”,“ D”])##它不起作用。数据类型损坏的是查询集而不是列表。

我在大于100万行数据的项目中对此进行了测试,峰值内存从2G减少到1G。


2

从Django的角度(我不熟悉pandas),这很好。我唯一关心的是,如果您有大量的记录,则可能会遇到内存问题。如果是这种情况,则必须使用这种高效内存的查询集迭代器。(如前所述,该代码段可能需要重新编写,以便您聪明地使用.values())。


@GregoryGoltsov使用.from_records()和不使用的想法list()将消除对内存效率的担忧。
滚刀

1
内存效率问题在Django方面。.values()返回一个ValuesQuerySet缓存结果的,因此对于足够大的数据集,它将占用大量内存。
David Eyk 2014年

1
嗯是的 您必须索引查询集,并且在.from_records没有列表理解的情况下使用,以消除这两个内存消耗。例如 pd.DataFrame.from_records(qs[i].__dict__ for i in range(qs.count()))。但是,完成后,您会剩下那烦人的"_state"专栏。qs.values()[i]更快,更干净,但是我认为它可以缓存。
滚刀2014年

1

您也许可以使用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()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.