Đúng cách ™ để tạo một DataFrame
TLDR; (chỉ cần đọc văn bản in đậm)
Hầu hết các câu trả lời ở đây sẽ cho bạn biết cách tạo một DataFrame trống và điền nó, nhưng không ai sẽ nói với bạn rằng đó là một việc xấu phải làm.
Đây là lời khuyên của tôi: Đợi cho đến khi bạn chắc chắn rằng bạn có tất cả dữ liệu bạn cần để làm việc. Sử dụng danh sách để thu thập dữ liệu của bạn, sau đó khởi tạo DataFrame khi bạn sẵn sàng.
data = []
for a, b, c in some_function_that_yields_data():
data.append([a, b, c])
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
Việc thêm vào danh sách và tạo DataFrame trong một lần luôn rẻ hơn so với việc tạo một DataFrame trống (hoặc một trong các NaN) và nối lại nó nhiều lần. Danh sách cũng chiếm ít bộ nhớ hơn và là một cấu trúc dữ liệu nhẹ hơn nhiều để làm việc với , chắp thêm và xóa (nếu cần).
Ưu điểm khác của phương pháp này dtypes
là tự động được suy ra (thay vì gánobject
cho tất cả chúng).
Ưu điểm cuối cùng là a RangeIndex
được tạo tự động cho dữ liệu của bạn , do đó, một điều ít phải lo lắng hơn (hãy xem người nghèo append
và loc
phương pháp bên dưới, bạn sẽ thấy các yếu tố trong cả hai yêu cầu xử lý chỉ mục một cách thích hợp).
Những điều bạn KHÔNG nên làm
append
hoặc concat
bên trong một vòng lặp
Đây là sai lầm lớn nhất tôi từng thấy từ những người mới bắt đầu:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck
# or similarly,
# df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)
Bộ nhớ được phân bổ lại cho mọi append
hoặc concat
hoạt động bạn có. Kết hợp điều này với một vòng lặp và bạn có một hoạt động phức tạp bậc hai . Từ df.append
trang tài liệu :
Lặp đi lặp lại các hàng vào DataFrame có thể được tính toán chuyên sâu hơn so với một liên kết đơn. Một giải pháp tốt hơn là nối các hàng đó vào một danh sách và sau đó nối danh sách với DataFrame gốc cùng một lúc.
Một lỗi khác liên quan đến df.append
là người dùng có xu hướng quên append không phải là một chức năng tại chỗ , do đó, kết quả phải được gán lại. Bạn cũng phải lo lắng về các dtypes:
df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)
df.dtypes
A object # yuck!
B float64
C object
dtype: object
Đối phó với các cột đối tượng không bao giờ là một điều tốt, bởi vì gấu trúc không thể vector hóa các hoạt động trên các cột đó. Bạn sẽ cần phải làm điều này để sửa nó:
df.infer_objects().dtypes
A int64
B float64
C object
dtype: object
loc
bên trong một vòng lặp
Tôi cũng đã thấy loc
được sử dụng để chắp thêm vào DataFrame được tạo trống:
df = pd.DataFrame(columns=['A', 'B', 'C'])
for a, b, c in some_function_that_yields_data():
df.loc[len(df)] = [a, b, c]
Như trước đây, bạn chưa phân bổ trước số lượng bộ nhớ bạn cần mỗi lần, vì vậy bộ nhớ được tăng trưởng lại mỗi khi bạn tạo một hàng mới . Nó cũng tệ nhưappend
, và thậm chí còn xấu xí hơn.
Khung dữ liệu trống của NaN
Và sau đó, sẽ tạo ra một DataFrame của NaN và tất cả các cảnh báo liên quan.
df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
A B C
0 NaN NaN NaN
1 NaN NaN NaN
2 NaN NaN NaN
3 NaN NaN NaN
4 NaN NaN NaN
Nó tạo ra một DataFrame của các cột đối tượng, giống như các cột khác.
df.dtypes
A object # you DON'T want this
B object
C object
dtype: object
Áp dụng vẫn có tất cả các vấn đề như các phương pháp trên.
for i, (a, b, c) in enumerate(some_function_that_yields_data()):
df.iloc[i] = [a, b, c]
Bằng chứng là trong pudding
Định thời gian cho các phương thức này là cách nhanh nhất để xem chúng khác nhau bao nhiêu về bộ nhớ và tiện ích của chúng.
Mã điểm chuẩn để tham khảo.