Làm cách nào để ước tính DataFrame của Pandas sẽ cần bao nhiêu bộ nhớ?


125

Tôi đã tự hỏi ... Nếu tôi đang đọc, chẳng hạn như một tệp csv 400MB vào khung dữ liệu gấu trúc (sử dụng read_csv hoặc read_table), có cách nào để ước tính xem tệp này sẽ cần bao nhiêu bộ nhớ không? Chỉ đang cố gắng cảm nhận rõ hơn về khung dữ liệu và bộ nhớ ...


Bạn luôn có thể xem quy trình và việc sử dụng bộ nhớ của nó cho một tệp duy nhất. Nếu bạn đang chạy linux, hãy thử topvà sau đó Shift + Mđể sắp xếp mức sử dụng bộ nhớ của tôi.
JayQuerie.com

Tôi cảm thấy tôi nên quảng cáo vấn đề gấu trúc mở này .
Andy Hayden

3
Tôi có một khung dữ liệu lớn với 4 triệu hàng. Tôi phát hiện ra rằng tập hợp con trống của nó x=df.loc[[]]mất 0.1vài giây để được tính toán (để trích xuất không hàng) và hơn nữa, chiếm hàng trăm MB bộ nhớ, giống như khung dữ liệu ban đầu, có thể là do một số sao chép bên dưới.
osa

liên kết mới cho bài đăng cũ của nhà phát triển chính của gấu trúc
saladi 22/02

Câu trả lời:


97

df.memory_usage() sẽ trả về số tiền mà mỗi cột chiếm:

>>> df.memory_usage()

Row_ID            20906600
Household_ID      20906600
Vehicle           20906600
Calendar_Year     20906600
Model_Year        20906600
...

Để bao gồm các chỉ mục, hãy vượt qua index=True.

Vì vậy, để có được mức tiêu thụ bộ nhớ tổng thể:

>>> df.memory_usage(index=True).sum()
731731000

Ngoài ra, việc vượt qua deep=Truesẽ cho phép một báo cáo sử dụng bộ nhớ chính xác hơn, giải thích cho việc sử dụng đầy đủ các đối tượng được chứa.

Điều này là do việc sử dụng bộ nhớ không bao gồm bộ nhớ được sử dụng bởi các phần tử không phải là thành phần của mảng if deep=False(trường hợp mặc định).


1
liệu việc sử dụng bộ nhớ của tất cả các cột có thực sự ảnh hưởng đến việc sử dụng bộ nhớ không? Tôi có thể tưởng tượng có nhiều chi phí hơn.
firelynx

14
Bạn thực sự cũng muốndeep=True
smci

Tổng của df.memory_usage () không bằng sys.getsizeof (df)! Có rất nhiều chi phí. Như smci đã đề cập, Bạn cầndeep=True
vagabond

11
FYI, memory_usage()trả về mức sử dụng bộ nhớ theo byte (như bạn mong đợi).
engelen

2
Tại sao lại có sự khác biệt rất lớn giữa có / không có sâu = True?
Nguai al

83

Dưới đây là so sánh các phương pháp khác nhau - sys.getsizeof(df)đơn giản nhất.

Đối với ví dụ này, dflà một khung dữ liệu có 814 hàng, 11 cột (2 int, 9 đối tượng) - đọc từ một tệp hình dạng 427kb

sys.getsizeof (df)

>>> nhập hệ thống
>>> sys.getsizeof (df)
(cho kết quả tính bằng byte)
462456

df.memory_usage ()

>>> df.memory_usage ()
...
(liệt kê mỗi cột ở 8 byte / hàng)

>>> df.memory_usage (). sum ()
71712
(khoảng hàng * cols * 8 byte)

>>> df.memory_usage (deep = True)
(liệt kê mức sử dụng bộ nhớ đầy đủ của mỗi cột)

>>> df.memory_usage (deep = True) .sum ()
(cho kết quả tính bằng byte)
462432

df.info ()

In thông tin khung dữ liệu vào stdout. Về mặt kỹ thuật, đây là kibibyte (KiB), không phải kilobyte - như docstring nói, "Việc sử dụng bộ nhớ được hiển thị bằng đơn vị con người có thể đọc được (đại diện cơ số 2)." Vì vậy, để có được byte sẽ nhân với 1024, ví dụ: 451,6 KiB = 462,438 byte.

>>> df.info ()
...
sử dụng bộ nhớ: 70.0+ KB

>>> df.info (memory_usage = 'deep')
...
sử dụng bộ nhớ: 451,6 KB

Đoạn g mã trên đề cập đến đối tượng hoặc mô-đun nào?
zozo

@zozo woops - là một lỗi đánh máy - cố định
Brian Burns

2
Tôi sử dụng df.info(memory_usage="deep"), nó sẽ trả "392,6 MB", trong khi đó sys.getsizeof(df)df.memory_usage(index=True, deep=True).sum()cả hai trở lại xấp xỉ "411.718.016" (~ 411MB). Bạn có thể vui lòng giải thích tại sao 3 kết quả không nhất quán? cảm ơn
Catbuilts

2
@BrianBurns: df.memory_usage(deep=True).sum()trả về gần giống với df.memory_usage(index=True, deep=True).sum(). trong trường hợp của tôi, nó indexkhông chiếm nhiều bộ nhớ. Thật thú vị, tôi thấy rằng 411718016/1024/1024 = 392.6, vì vậy df.info(memory_usage="deep")có thể sử dụng 2^10để chuyển đổi byte sang MB , điều này khiến tôi bối rối. Dù sao cũng cảm ơn sự giúp đỡ của bạn: D.
Catbuilts

1
@Catbuilts Ah, điều đó giải thích nó! df.infotrả về mebibyte (2 ^ 10), không phải megabyte (10 ^ 6) - sẽ sửa đổi câu trả lời.
Brian Burns,

43

Tôi nghĩ rằng tôi sẽ đưa thêm một số dữ liệu vào cuộc thảo luận.

Tôi đã chạy một loạt các thử nghiệm về vấn đề này.

Bằng cách sử dụng resourcegói python, tôi đã sử dụng bộ nhớ trong quá trình của mình.

Và bằng cách ghi csv vào StringIObộ đệm, tôi có thể dễ dàng đo kích thước của nó theo byte.

Tôi đã chạy hai thử nghiệm, mỗi thử nghiệm tạo ra 20 khung dữ liệu có kích thước tăng dần từ 10.000 dòng đến 1.000.000 dòng. Cả hai đều có 10 cột.

Trong thử nghiệm đầu tiên, tôi chỉ sử dụng float trong tập dữ liệu của mình.

Đây là cách bộ nhớ tăng lên so với tệp csv dưới dạng một hàm của số dòng. (Kích thước tính bằng Megabyte)

Kích thước bộ nhớ và CSV tính bằng Megabyte dưới dạng hàm của số hàng có mục nhập float

Thử nghiệm thứ hai, tôi có cùng cách tiếp cận, nhưng dữ liệu trong tập dữ liệu chỉ bao gồm các chuỗi ngắn.

Kích thước bộ nhớ và CSV tính bằng Megabyte dưới dạng hàm của số hàng có mục nhập chuỗi

Có vẻ như mối quan hệ giữa kích thước của csv và kích thước của khung dữ liệu có thể khác nhau khá nhiều, nhưng kích thước trong bộ nhớ sẽ luôn lớn hơn theo hệ số 2-3 (đối với kích thước khung trong thử nghiệm này)

Tôi rất muốn hoàn thành câu trả lời này với nhiều thử nghiệm hơn, hãy bình luận nếu bạn muốn tôi thử điều gì đó đặc biệt.


Trục y của bạn là gì?
Ilya V. Schurov

1
max_rss và kích thước csv trên đĩa tính bằng megabyte
firelynx

31

Bạn phải làm điều này ngược lại.

In [4]: DataFrame(randn(1000000,20)).to_csv('test.csv')

In [5]: !ls -ltr test.csv
-rw-rw-r-- 1 users 399508276 Aug  6 16:55 test.csv

Bộ nhớ về mặt kỹ thuật là về điều này (bao gồm các chỉ mục)

In [16]: df.values.nbytes + df.index.nbytes + df.columns.nbytes
Out[16]: 168000160

Vì vậy, 168MB trong bộ nhớ với một tệp 400MB, 1 triệu hàng gồm 20 cột nổi

DataFrame(randn(1000000,20)).to_hdf('test.h5','df')

!ls -ltr test.h5
-rw-rw-r-- 1 users 168073944 Aug  6 16:57 test.h5

Gọn gàng hơn rất nhiều khi được viết dưới dạng tệp HDF5 nhị phân

In [12]: DataFrame(randn(1000000,20)).to_hdf('test.h5','df',complevel=9,complib='blosc')

In [13]: !ls -ltr test.h5
-rw-rw-r-- 1 users 154727012 Aug  6 16:58 test.h5

Dữ liệu là ngẫu nhiên, vì vậy việc nén không giúp ích quá nhiều


Đó là rất thông minh! Bất kỳ ý tưởng nào về cách đo bộ nhớ bạn cần để đọc tệp bằng cách sử dụng read_csv?
Andy Hayden

Không có ý tưởng làm thế nào để đo lường AS bạn đọc; IIRC nó có thể lên đến 2x bộ nhớ thức cần thiết để giữ dữ liệu (từ bài viết của wes), nhưng tôi nghĩ anh ấy mang nó xuống một hằng nhớ + thức
Jeff

Ah, tôi cần phải đọc lại, tôi nhớ 2x là một số lý thuyết tối thiểu thuận tiện cho một thuật toán nhất định, nếu nó thậm chí còn ít hơn nó.
Andy Hayden

Bạn có thể sử dụng iotoplike top/ htopđể xem (trong thời gian thực) hiệu suất IO.
Phillip Cloud

1
nbytessẽ bị đánh giá thấp nếu bạn có các chuỗi ví dụ trong khung dữ liệu.
osa

10

Nếu bạn biết các dtypes của mảng của mình thì bạn có thể tính trực tiếp số byte sẽ cần để lưu trữ dữ liệu của bạn + một số cho chính các đối tượng Python. Một thuộc tính hữu ích của numpymảng là nbytes. Bạn có thể lấy số byte từ các mảng trong gấu trúc DataFramebằng cách

nbytes = sum(block.values.nbytes for block in df.blocks.values())

objectmảng dtype lưu trữ 8 byte cho mỗi đối tượng (mảng dtype đối tượng lưu trữ một con trỏ đến một vùng mờ PyObject), vì vậy nếu bạn có các chuỗi trong csv của mình, bạn cần phải tính đến điều đó read_csvsẽ biến chúng thành objectmảng dtype và điều chỉnh các tính toán của bạn cho phù hợp.

BIÊN TẬP:

Xem numpytrang các loại vô hướng để biết thêm chi tiết về object dtype. Vì chỉ một tham chiếu được lưu trữ nên bạn cũng cần tính đến kích thước của đối tượng trong mảng. Như trang đó đã nói, mảng đối tượng hơi giống với listcác đối tượng Python .


Cảm ơn Phillip! Chỉ cần làm rõ - đối với một chuỗi, chúng ta sẽ cần 8 byte cho một con trỏ đến một đối tượng chuỗi, cộng với đối tượng chuỗi thực sự?
Anne

1
Vâng, đối với bất kỳ loại đối tượng bạn sẽ cần một 8 byte kích thước con trỏ + (object)
Viktor Kerkez

1
Đề xuất df.blocks.values ​​() Có vẻ như df.blocks hiện là một
mệnh lệnh

8

Có, có. Pandas sẽ lưu trữ dữ liệu của bạn trong các ndarraycấu trúc numpy 2 chiều, nhóm chúng theo kiểu dtypes. ndarrayvề cơ bản là một mảng dữ liệu C thô với một tiêu đề nhỏ. Vì vậy, bạn có thể ước tính kích thước của nó chỉ bằng cách nhân kích thước của dtypenó chứa với các kích thước của mảng.

Ví dụ: nếu bạn có 1000 hàng với 2 np.int32và 5 np.float64cột, DataFrame của bạn sẽ có một np.int32mảng 2x1000 và một np.float64mảng 5x1000 là:

4byte * 2 * 1000 + 8byte * 5 * 1000 = 48000 byte


@AndyHayden Ý bạn là chi phí xây dựng? Kích thước của một phiên bản DataFrame?
Phillip Cloud

Cảm ơn Victor! @Andy - Bạn có biết chi phí xây dựng lớn như thế nào không?
Anne

Nó không bao gồm, nhưng pandascó một triển khai rất hiệu quả read_tabletrong Cython (nó tốt hơn nhiều so với loadtxt của numpy) vì vậy tôi giả sử rằng nó phân tích cú pháp và lưu trữ dữ liệu trực tiếp vào ndarray.
Viktor Kerkez

@PhillipCloud bạn phải xây dựng nó, đó là mất trí nhớ .. Tôi nhớ hình như gấp đôi so với kích thước được đề cập ...?
Andy Hayden

6

Tôi tin rằng điều này cung cấp kích thước trong bộ nhớ cho bất kỳ đối tượng nào trong python. Nội tạng cần được kiểm tra liên quan đến gấu trúc và numpy

>>> import sys
#assuming the dataframe to be df 
>>> sys.getsizeof(df) 
59542497
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.