การแปลง Django QuerySet เป็น Panda DataFrame


93

ฉันจะแปลง Django QuerySet เป็นแพนด้าDataFrameดังนี้:

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

ได้ผล แต่มีวิธีที่มีประสิทธิภาพมากกว่านี้หรือไม่?


สวัสดี @FrancoMariluis ขออภัยเกี่ยวกับเรื่องนี้: คุณใช้แพนด้าในโครงการ django หรือไม่ คุณแสดงกราฟิกโดยใช้ "การพล็อตด้วย matplotlib" ผ่านเว็บแอปพลิเคชัน django เป็นทางออกที่ถูกต้องสำหรับคุณหรือไม่? ขอบคุณ.
dani herrera

สวัสดีสำหรับการแสดงกราฟิกใน Django ฉันใช้ django-chartit ซึ่งใช้งานได้ดี แต่ฉันกำลังคิดเกี่ยวกับการใช้ matplotlib ซึ่งจะทำให้ฉันมีความยืดหยุ่นมากขึ้น
Franco Mariluis

ดูตรงไปตรงมาและใช้งานได้จริง มีข้อกังวลเป็นพิเศษหรือไม่?
Dmitry Shevchenko

มีอะไรผิดปกติกับคุณตอนนี้? คุณมีความกังวลเป็นพิเศษหรือไม่?
Burhan Khalid

นี่เป็นแนวทางแรก (และครั้งเดียว!) ของฉัน แต่เนื่องจากฉันค่อนข้างใหม่กับแพนด้าฉันจึงอยากดูว่ามีวิธีอื่นหรือไม่ แต่ดูเหมือนว่าจะเป็นวิธีที่ดี
Franco Mariluis

คำตอบ:


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

ข้างต้นเป็นวิธีที่ฉันทำสิ่งเดียวกัน การเพิ่มที่มีประโยชน์ที่สุดคือการระบุสาขาที่คุณสนใจหากเป็นเพียงส่วนย่อยของฟิลด์ที่มีอยู่ที่คุณสนใจสิ่งนี้จะช่วยเพิ่มประสิทธิภาพอย่างที่ฉันคิด


38
การใช้ 'list ()' ดูเหมือนจะเลิกใช้แล้ว (ฉันใช้แพนด้า 0.12) การใช้งานที่ดีกว่าคือDataFrame.from_records() df = pd.DataFrame.from_records(BlogPost.objects.all().values())
gregoltsov

2
จะชัดเจนยิ่งขึ้นหากใช้ชื่อจากคำถาม OP ตัวอย่างเช่นBlogPostควรจะเหมือนกับของเขาSomeModelหรือไม่?
Hack-R

สวัสดีมีวิธีการยกเว้นคอลัมน์ที่คุณไม่ต้องการใน dataframe หรือไม่?
Willower

19

Django Pandas แก้ปัญหานี้ได้ค่อนข้างเรียบร้อย: https://github.com/chrisdev/django-pandas/

จาก 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)

11
Django Pandas จัดการกับชุดข้อมูลขนาดใหญ่อย่างไร github.com/chrisdev/django-pandas/blob/master/django_pandas/… บรรทัดนี้ทำให้ฉันกลัวเพราะฉันคิดว่ามันหมายความว่าชุดข้อมูลทั้งหมดจะถูกโหลดลงในหน่วยความจำในครั้งเดียว
Adam Barnes

@Ada ในการสร้าง DataFrame โดยใช้ชื่อฟิลด์ที่ระบุ:df = read_frame(qs, fieldnames=['age', 'wage', 'full_name'])
Gathide

สำหรับพวกคุณในอนาคตอันน่าอัศจรรย์นี้ที่กำลังสงสัยกับสิ่งที่ฉันกำลังดำเนินอยู่ต่อไปนี้เป็นลิงก์ถาวรมากขึ้นไปยังแหล่งที่มาในเวลานั้น: github.com/chrisdev/django-pandas/blob/…
Adam Barnes

10

การแปลง queryset บน values_list () จะทำให้หน่วยความจำมีประสิทธิภาพมากกว่าค่า () โดยตรง เนื่องจาก method values ​​() ส่งคืนชุดรายการของ dict (คู่คีย์: ค่า) 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), column = ["A", "B", "C", "D"]) ## ซึ่งจะช่วยประหยัดหน่วยความจำ 50%
    #df = pd.DataFrame.from_records (queryset, column = ["A", "B", "C", "D"]) ## ไม่ทำงาน Crashed with datatype is queryset not list.

ฉันทดสอบสิ่งนี้ในโครงการของฉันด้วยข้อมูล> 1 ล้านแถวหน่วยความจำสูงสุดจะลดลงจาก 2G เป็น 1G


2

จากมุมมองของ Django (ฉันไม่คุ้นเคยpandas) ก็ใช้ได้ สิ่งเดียวที่ฉันกังวลคือถ้าคุณมีบันทึกจำนวนมากคุณอาจประสบปัญหาเกี่ยวกับหน่วยความจำ หากเป็นกรณีนี้จำเป็นต้องมีบางสิ่งบางอย่างตามบรรทัดของตัววนซ้ำแบบสอบถามที่มีประสิทธิภาพของหน่วยความจำนี้ (ตัวอย่างข้อมูลตามที่เขียนอาจต้องมีการเขียนใหม่เพื่อให้สามารถใช้งานได้อย่างชาญฉลาด.values())


ความคิดของ @ GregoryGoltsov ที่จะใช้.from_records()และไม่ใช้list()จะช่วยขจัดปัญหาด้านประสิทธิภาพของหน่วยความจำ
เตาปรุงอาหาร

1
ความกังวลเกี่ยวกับประสิทธิภาพของหน่วยความจำอยู่ที่ด้าน Django .values()ส่งคืนผลลัพธ์ValuesQuerySetที่แคชไว้ดังนั้นสำหรับชุดข้อมูลที่มีขนาดใหญ่เพียงพอจะต้องใช้หน่วยความจำค่อนข้างมาก
David Eyk

1
อ่าใช่ คุณต้องจัดทำดัชนีลงในแบบสอบถามและใช้.from_recordsโดยไม่มีความเข้าใจในรายการเพื่อกำจัดหมูหน่วยความจำทั้งสอง เช่น pd.DataFrame.from_records(qs[i].__dict__ for i in range(qs.count())). แต่คุณจะเหลือ"_state"คอลัมน์ที่น่ารำคาญเมื่อคุณทำเสร็จแล้ว qs.values()[i]เร็วและสะอาดกว่ามาก แต่ฉันคิดว่ามันแคช
เตา

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()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.