Chuyển đổi Django QuerySet thành gấu trúc DataFrame


90

Tôi sẽ chuyển đổi Django QuerySet thành gấu trúc DataFramenhư sau:

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

Nó hoạt động, nhưng có cách nào hiệu quả hơn không?


Xin chào @FrancoMariluis, xin lỗi vì điều này lạc đề: bạn đang sử dụng gấu trúc vào các dự án django. Bạn hiển thị đồ họa bằng cách sử dụng "Vẽ đồ họa với matplotlib" thông qua các ứng dụng web django. Là một giải pháp hợp lệ cho bạn? Cảm ơn.
dani herrera

Hi, cho thấy đồ họa trong Django Tôi đang sử dụng django-chartit, hoạt động tốt, nhưng tôi đang nghĩ về việc sử dụng matplotlib, trong đó sẽ cho tôi linh hoạt hơn
Franco Mariluis

Trông khá đơn giản và nó hoạt động. Bất kỳ mối quan tâm cụ thể?
Dmitry Shevchenko

Có gì sai với cách bạn có nó bây giờ? Bạn có một mối quan tâm đặc biệt?
Burhan Khalid

Đây là cách tiếp cận đầu tiên (và duy nhất!) Của tôi, nhưng vì tôi còn khá mới với gấu trúc, tôi muốn xem có cách nào khác không, nhưng đây có vẻ là một cách tốt.
Franco Mariluis

Câu trả lời:


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

Trên đây là cách tôi làm điều tương tự. Bổ sung hữu ích nhất là chỉ định các trường bạn quan tâm. Nếu đó chỉ là một tập hợp con của các trường có sẵn mà bạn quan tâm, thì điều này sẽ giúp tăng hiệu suất mà tôi tưởng tượng.


37
Sử dụng 'list ()' dường như không được dùng nữa (Tôi đang sử dụng gấu trúc 0.12). Việc sử dụng DataFrame.from_records()hoạt động tốt hơn, tức là df = pd.DataFrame.from_records(BlogPost.objects.all().values()).
gregoltsov

2
Sẽ rõ ràng hơn nếu điều này sử dụng các tên từ câu hỏi OP. Ví dụ, được BlogPostcho là giống như của mình SomeModel?
Hack-R

Xin chào, có cách nào để loại trừ cột bạn không cần trong khung dữ liệu không?
Willower

19

Django Pandas giải quyết vấn đề này khá gọn gàng: https://github.com/chrisdev/django-pandas/

Từ 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)

10
Django Pandas đối phó với tập dữ liệu lớn như thế nào? github.com/chrisdev/django-pandas/blob/master/django_pandas/… Dòng này làm tôi sợ, vì tôi nghĩ nó có nghĩa là toàn bộ tập dữ liệu sẽ được tải vào bộ nhớ cùng một lúc.
Adam Barnes

@Ada Để tạo DataFrame bằng cách sử dụng các tên trường được chỉ định:df = read_frame(qs, fieldnames=['age', 'wage', 'full_name'])
Gathide

Đối với những người trong số các bạn trong tương lai kỳ diệu này, những người đang tự hỏi xem tôi sẽ ở đâu, đây là một liên kết lâu dài hơn đến nguồn tại thời điểm: github.com/chrisdev/django-pandas/blob/…
Adam Barnes

9

Chuyển đổi bộ truy vấn trên danh sách giá trị () sẽ tiết kiệm bộ nhớ hơn trên giá trị () trực tiếp. Vì phương thức giá trị () trả về một tập hợp truy vấn gồm danh sách các cặp dict (khóa: giá trị), nên giá trị_list () chỉ trả về danh sách các tuple (dữ liệu thuần túy). Nó sẽ tiết kiệm khoảng 50% bộ nhớ, chỉ cần thiết lập thông tin cột khi bạn gọi pd.DataFrame ().

Phương pháp 1:
    queryset = models.xxx.objects.values ​​("A", "B", "C", "D")
    df = pd.DataFrame (list (queryset)) ## ngốn nhiều bộ nhớ
    #df = pd.DataFrame.from_records (queryset) ## hoạt động nhưng không có thay đổi nhiều về mức sử dụng bộ nhớ

Phương pháp 2:
    queryset = models.xxx.objects.values_list ("A", "B", "C", "D")
    df = pd.DataFrame (list (queryset), column = ["A", "B", "C", "D"]) ## điều này sẽ tiết kiệm 50% bộ nhớ
    #df = pd.DataFrame.from_records (bộ câu hỏi, cột = ["A", "B", "C", "D"]) ## Nó không hoạt động. Đã gặp sự cố với kiểu dữ liệu là bộ truy vấn không phải danh sách.

Tôi đã thử nghiệm điều này trên dự án của mình với dữ liệu> 1 triệu hàng, bộ nhớ cao điểm được giảm từ 2G xuống 1G.


2

Từ quan điểm của Django (tôi không quen thuộc pandas) thì điều này ổn. Mối quan tâm duy nhất của tôi là nếu bạn có một số lượng rất lớn các bản ghi, bạn có thể gặp vấn đề về bộ nhớ. Nếu trường hợp này xảy ra, một cái gì đó dọc theo dòng của trình lặp bộ truy vấn hiệu quả bộ nhớ này sẽ là cần thiết. (Đoạn mã được viết có thể yêu cầu một số viết lại để cho phép bạn sử dụng thông minh .values()).


Ý tưởng sử dụng .from_records()và không sử dụng của @ GregoryGoltsov list()sẽ loại bỏ mối quan tâm về hiệu quả bộ nhớ.
hobs

1
Mối quan tâm về hiệu quả bộ nhớ nằm ở phía Django. .values()trả về một ValuesQuerySetkết quả lưu trong bộ nhớ cache, vì vậy đối với một tập dữ liệu đủ lớn, nó sẽ khá tốn bộ nhớ.
David Eyk

1
À vâng. Bạn sẽ phải lập chỉ mục vào bộ truy vấn sử dụng .from_recordsmà không có khả năng hiểu danh sách để loại bỏ cả hai ổ nhớ. vd pd.DataFrame.from_records(qs[i].__dict__ for i in range(qs.count())). Nhưng bạn bị bỏ lại với cái "_state"cột khó chịu đó khi bạn hoàn thành. qs.values()[i]nhanh hơn và sạch hơn nhiều, nhưng tôi nghĩ nó được lưu vào bộ nhớ cache.
hobs

1

Bạn có thể sử dụng 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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.