Dữ liệu lớn Dòng dữ liệu làm việc bằng cách sử dụng gấu trúc


981

Tôi đã cố gắng tìm ra câu trả lời cho câu hỏi này trong nhiều tháng khi học gấu trúc. Tôi sử dụng SAS cho công việc hàng ngày của mình và thật tuyệt vời cho sự hỗ trợ vượt trội. Tuy nhiên, SAS là khủng khiếp như một phần mềm vì nhiều lý do khác.

Một ngày nào đó tôi hy vọng sẽ thay thế việc sử dụng SAS của tôi bằng python và gấu trúc, nhưng hiện tại tôi thiếu một quy trình làm việc bên ngoài cho các bộ dữ liệu lớn. Tôi không nói về "dữ liệu lớn" đòi hỏi một mạng phân tán, mà là các tệp quá lớn để phù hợp với bộ nhớ nhưng đủ nhỏ để vừa với ổ cứng.

HDFStoreSuy nghĩ đầu tiên của tôi là sử dụng để giữ các bộ dữ liệu lớn trên đĩa và chỉ kéo các phần tôi cần vào dataframes để phân tích. Những người khác đã đề cập MongoDB như là một thay thế dễ sử dụng hơn. Câu hỏi của tôi là:

Một số quy trình thực hành tốt nhất để hoàn thành những điều sau đây là gì:

  1. Đang tải các tệp phẳng vào cấu trúc cơ sở dữ liệu trên đĩa cố định
  2. Truy vấn cơ sở dữ liệu đó để lấy dữ liệu để đưa vào cấu trúc dữ liệu của gấu trúc
  3. Cập nhật cơ sở dữ liệu sau khi thao tác các mảnh trong gấu trúc

Các ví dụ trong thế giới thực sẽ được đánh giá cao, đặc biệt là từ bất kỳ ai sử dụng gấu trúc trên "dữ liệu lớn".

Chỉnh sửa - một ví dụ về cách tôi muốn làm việc này:

  1. Lặp lại nhập một tệp phẳng lớn và lưu trữ nó trong một cấu trúc cơ sở dữ liệu cố định trên đĩa. Những tập tin này thường quá lớn để phù hợp với bộ nhớ.
  2. Để sử dụng Pandas, tôi muốn đọc các tập hợp con của dữ liệu này (thường chỉ là một vài cột tại một thời điểm) có thể phù hợp với bộ nhớ.
  3. Tôi sẽ tạo các cột mới bằng cách thực hiện các hoạt động khác nhau trên các cột đã chọn.
  4. Sau đó tôi sẽ phải nối các cột mới này vào cấu trúc cơ sở dữ liệu.

Tôi đang cố gắng tìm một cách thực hành tốt nhất để thực hiện các bước này. Đọc các liên kết về gấu trúc và pytables có vẻ như việc nối thêm một cột mới có thể là một vấn đề.

Chỉnh sửa - Trả lời cụ thể các câu hỏi của Jeff:

  1. Tôi đang xây dựng mô hình rủi ro tín dụng tiêu dùng. Các loại dữ liệu bao gồm đặc điểm điện thoại, SSN và địa chỉ; giá trị tài sản; thông tin xúc phạm như hồ sơ tội phạm, phá sản, v.v ... Các bộ dữ liệu tôi sử dụng hàng ngày có trung bình gần 1.000 đến 2.000 trường dữ liệu hỗn hợp: biến liên tục, danh nghĩa và thứ tự của cả dữ liệu số và ký tự. Tôi hiếm khi nối các hàng, nhưng tôi thực hiện nhiều thao tác tạo cột mới.
  2. Các hoạt động tiêu biểu liên quan đến việc kết hợp một số cột sử dụng logic có điều kiện thành một cột ghép mới. Ví dụ , if var1 > 2 then newvar = 'A' elif var2 = 4 then newvar = 'B'. Kết quả của các hoạt động này là một cột mới cho mỗi bản ghi trong tập dữ liệu của tôi.
  3. Cuối cùng, tôi muốn nối các cột mới này vào cấu trúc dữ liệu trên đĩa. Tôi sẽ lặp lại bước 2, khám phá dữ liệu với chéo bảng và thống kê mô tả cố gắng tìm các mối quan hệ trực quan thú vị để mô hình hóa.
  4. Một tệp dự án điển hình thường là khoảng 1GB. Các tệp được sắp xếp theo cách như vậy trong đó một hàng bao gồm một bản ghi dữ liệu người tiêu dùng. Mỗi hàng có cùng số cột cho mỗi bản ghi. Điều này sẽ luôn luôn là trường hợp.
  5. Thật hiếm khi tôi tập hợp các hàng khi tạo một cột mới. Tuy nhiên, nó khá phổ biến đối với tôi để tập hợp con trên các hàng khi tạo báo cáo hoặc tạo số liệu thống kê mô tả. Ví dụ: tôi có thể muốn tạo một tần suất đơn giản cho một ngành nghề kinh doanh cụ thể, ví dụ như thẻ tín dụng Bán lẻ. Để làm điều này, tôi sẽ chỉ chọn những bản ghi trong đó dòng doanh nghiệp = bán lẻ ngoài bất kỳ cột nào tôi muốn báo cáo. Tuy nhiên, khi tạo các cột mới, tôi sẽ kéo tất cả các hàng dữ liệu và chỉ các cột tôi cần cho các hoạt động.
  6. Quá trình mô hình hóa yêu cầu tôi phân tích mọi cột, tìm kiếm các mối quan hệ thú vị với một số biến kết quả và tạo các cột ghép mới mô tả các mối quan hệ đó. Các cột mà tôi khám phá thường được thực hiện trong các bộ nhỏ. Ví dụ: tôi sẽ tập trung vào một nhóm gồm 20 cột nói về việc xử lý các giá trị tài sản và quan sát cách chúng liên quan đến mặc định cho khoản vay. Khi những cột đó được khám phá và các cột mới được tạo, sau đó tôi chuyển sang một nhóm cột khác, nói giáo dục đại học và lặp lại quy trình. Những gì tôi đang làm là tạo ra các biến số ứng viên giải thích mối quan hệ giữa dữ liệu của tôi và một số kết quả. Vào cuối quá trình này, tôi áp dụng một số kỹ thuật học tập tạo ra một phương trình từ các cột ghép đó.

Rất hiếm khi tôi thêm hàng vào tập dữ liệu. Tôi gần như sẽ luôn tạo các cột mới (các biến hoặc tính năng trong thống kê / cách học máy).


1
Là kích thước lõi tỷ lệ / kích thước đầy đủ 1%, 10%? Có vấn đề gì không - nếu bạn có thể nén cols thành int8 hoặc lọc ra các hàng ồn ào, điều đó có làm thay đổi vòng lặp tính toán của bạn từ giờ nói sang phút không? (Đồng thời thêm thẻ dữ liệu lớn.)
denis 18/03/13

1
Lưu trữ float32 thay vì float64 và int8 nếu có thể, nên tầm thường (không biết công cụ / chức năng nào thực hiện float64 trong nội bộ)
denis

bạn có thể chia nhiệm vụ của bạn thành nhiều phần của công việc?
Andrew Scott Evans

1
một giải pháp hay năm 2019 để thực hiện gấu trúc như thao tác trên dữ liệu "trung bình" không phù hợp với bộ nhớ là dask
lunguini

Có những lựa chọn thay thế cho python + gấu trúc mà bạn có thể muốn xem xét khi bạn mới bắt đầu. Hãy xem xét thực tế rằng Python là một ngôn ngữ lập trình có mục đích chung (không phải là DSL để phân tích và phân tích dữ liệu) và gấu trúc là một thư viện được giải quyết trên đó. Tôi sẽ xem xét nhìn vào R hoặc kdb.
Henry Henrinson

Câu trả lời:


621

Tôi thường xuyên sử dụng hàng chục gigabyte dữ liệu chỉ trong thời gian này, ví dụ như tôi có các bảng trên đĩa mà tôi đọc qua các truy vấn, tạo dữ liệu và nối lại.

Thật đáng để đọc các tài liệumuộn trong chủ đề này cho một số gợi ý về cách lưu trữ dữ liệu của bạn.

Các chi tiết sẽ ảnh hưởng đến cách bạn lưu trữ dữ liệu của mình, như:
Cung cấp càng nhiều chi tiết càng tốt; và tôi có thể giúp bạn phát triển một cấu trúc.

  1. Kích thước của dữ liệu, # hàng, cột, loại cột; bạn đang nối các hàng, hay chỉ các cột?
  2. Những hoạt động điển hình sẽ như thế nào. Ví dụ: thực hiện một truy vấn trên các cột để chọn một loạt các hàng và các cột cụ thể, sau đó thực hiện một thao tác (trong bộ nhớ), tạo các cột mới, lưu các cột này.
    (Đưa ra một ví dụ về đồ chơi có thể cho phép chúng tôi đưa ra các khuyến nghị cụ thể hơn.)
  3. Sau khi xử lý, bạn sẽ làm gì? Là bước 2 ad hoc, hoặc lặp lại?
  4. Nhập tệp phẳng: có bao nhiêu, tổng kích thước thô trong Gb. Làm thế nào được tổ chức ví dụ như bằng hồ sơ? Có phải mỗi trường chứa các trường khác nhau hoặc chúng có một số bản ghi cho mỗi tệp với tất cả các trường trong mỗi tệp không?
  5. Bạn có bao giờ chọn các tập hợp con của các hàng (bản ghi) dựa trên các tiêu chí (ví dụ: chọn các hàng có trường A> 5) không? và sau đó làm một cái gì đó, hoặc bạn chỉ chọn các trường A, B, C với tất cả các bản ghi (và sau đó làm một cái gì đó)?
  6. Bạn có 'làm việc trên' tất cả các cột của mình (theo nhóm) không, hoặc có một tỷ lệ tốt mà bạn chỉ có thể sử dụng cho các báo cáo (ví dụ: bạn muốn giữ dữ liệu xung quanh, nhưng không cần phải khám phá cột đó cho đến khi thời gian kết quả cuối cùng)?

Giải pháp

Đảm bảo bạn có gấu trúc ít nhất0.10.1 được cài đặt.

Đọc các tệp lặp chunk-by-chunknhiều truy vấn bảng .

Vì pytables được tối ưu hóa để hoạt động theo hàng (đó là những gì bạn truy vấn), chúng tôi sẽ tạo một bảng cho từng nhóm trường. Bằng cách này, thật dễ dàng để chọn một nhóm nhỏ các trường (sẽ hoạt động với một bảng lớn, nhưng sẽ hiệu quả hơn khi làm theo cách này ... Tôi nghĩ rằng tôi có thể khắc phục giới hạn này trong tương lai ... đây là dù sao trực quan hơn):
(Sau đây là mã giả.)

import numpy as np
import pandas as pd

# create a store
store = pd.HDFStore('mystore.h5')

# this is the key to your storage:
#    this maps your fields to a specific group, and defines 
#    what you want to have as data_columns.
#    you might want to create a nice class wrapping this
#    (as you will want to have this map and its inversion)  
group_map = dict(
    A = dict(fields = ['field_1','field_2',.....], dc = ['field_1',....,'field_5']),
    B = dict(fields = ['field_10',......        ], dc = ['field_10']),
    .....
    REPORTING_ONLY = dict(fields = ['field_1000','field_1001',...], dc = []),

)

group_map_inverted = dict()
for g, v in group_map.items():
    group_map_inverted.update(dict([ (f,g) for f in v['fields'] ]))

Đọc trong tệp và tạo bộ lưu trữ (về cơ bản là làm gì append_to_multiple):

for f in files:
   # read in the file, additional options may be necessary here
   # the chunksize is not strictly necessary, you may be able to slurp each 
   # file into memory in which case just eliminate this part of the loop 
   # (you can also change chunksize if necessary)
   for chunk in pd.read_table(f, chunksize=50000):
       # we are going to append to each table by group
       # we are not going to create indexes at this time
       # but we *ARE* going to create (some) data_columns

       # figure out the field groupings
       for g, v in group_map.items():
             # create the frame for this group
             frame = chunk.reindex(columns = v['fields'], copy = False)    

             # append it
             store.append(g, frame, index=False, data_columns = v['dc'])

Bây giờ bạn có tất cả các bảng trong tệp (thực sự bạn có thể lưu trữ chúng trong các tệp riêng nếu bạn muốn, bạn sẽ phải thêm tên tệp vào group_map, nhưng có lẽ điều này không cần thiết).

Đây là cách bạn lấy cột và tạo cột mới:

frame = store.select(group_that_I_want)
# you can optionally specify:
# columns = a list of the columns IN THAT GROUP (if you wanted to
#     select only say 3 out of the 20 columns in this sub-table)
# and a where clause if you want a subset of the rows

# do calculations on this frame
new_frame = cool_function_on_frame(frame)

# to 'add columns', create a new group (you probably want to
# limit the columns in this new_group to be only NEW ones
# (e.g. so you don't overlap from the other tables)
# add this info to the group_map
store.append(new_group, new_frame.reindex(columns = new_columns_created, copy = False), data_columns = new_columns_created)

Khi bạn đã sẵn sàng cho post_ Xử lý:

# This may be a bit tricky; and depends what you are actually doing.
# I may need to modify this function to be a bit more general:
report_data = store.select_as_multiple([groups_1,groups_2,.....], where =['field_1>0', 'field_1000=foo'], selector = group_1)

Về data_columns, bạn thực sự không cần xác định BẤT K data data_columns nào; chúng cho phép bạn chọn các hàng dựa trên cột. Ví dụ:

store.select(group, where = ['field_1000=foo', 'field_1001>0'])

Chúng có thể thú vị nhất với bạn trong giai đoạn tạo báo cáo cuối cùng (về cơ bản một cột dữ liệu được tách biệt khỏi các cột khác, điều này có thể ảnh hưởng đến hiệu quả phần nào nếu bạn xác định nhiều).

Bạn cũng có thể muốn:

  • tạo một hàm lấy danh sách các trường, tra cứu các nhóm trong nhóm_map, sau đó chọn các trường này và nối các kết quả để bạn có được khung kết quả (đây thực chất là những gì select_as_multipl làm). Bằng cách này, cấu trúc sẽ khá minh bạch với bạn.
  • lập chỉ mục trên các cột dữ liệu nhất định (làm cho việc đặt hàng nhanh hơn nhiều).
  • cho phép nén.

Hãy cho tôi biết khi bạn có câu hỏi!


5
Cảm ơn các liên kết. Liên kết thứ hai làm tôi hơi lo lắng rằng tôi không thể nối các cột mới vào các bảng trong HDFStore? Đúng không? Ngoài ra, tôi đã thêm một ví dụ về cách tôi sẽ sử dụng thiết lập này.
Zelazny7

4
Cấu trúc thực tế trong hdf là tùy thuộc vào bạn. Pytables được định hướng theo hàng, với các cột cố định tại thời điểm tạo. Bạn không thể nối các cột sau khi bảng được tạo. Tuy nhiên, bạn có thể tạo một bảng mới được lập chỉ mục giống như bảng hiện có của bạn. (xem các ví dụ select_as_multipl trong tài liệu). Bằng cách này bạn có thể tạo các đối tượng có kích thước tùy ý trong khi có các truy vấn khá hiệu quả. Cách bạn sử dụng dữ liệu là chìa khóa để tổ chức nó trên đĩa. Gửi cho tôi một e-mail ngoài danh sách với mã giả của một ví dụ cụ thể hơn.
Jeff

1
Tôi đã cập nhật câu hỏi của tôi để trả lời các điểm chi tiết của bạn. Tôi sẽ làm việc trên một ví dụ để gửi cho bạn ngoài danh sách. Cảm ơn!
Zelazny7

12
@Jeff, với Pandas đang ở 0.17.x bây giờ các vấn đề được nêu ở trên đã được giải quyết trong Pandas?
ctrl-alt-xóa

5
@Jeff muốn thêm một bản cập nhật nhanh về câu trả lời của bạn để quảng bá dask?
Boud

137

Tôi nghĩ rằng các câu trả lời ở trên đang thiếu một cách tiếp cận đơn giản mà tôi thấy rất hữu ích.

Khi tôi có một tệp quá lớn để tải trong bộ nhớ, tôi chia tệp thành nhiều tệp nhỏ hơn (theo hàng hoặc cols)

Ví dụ: Trong trường hợp dữ liệu giao dịch có giá trị 30 ngày với kích thước ~ 30 GB, tôi chia nó thành một tệp mỗi ngày có kích thước ~ 1GB. Sau đó tôi xử lý từng tệp riêng biệt và tổng hợp kết quả ở cuối

Một trong những ưu điểm lớn nhất là nó cho phép xử lý song song các tệp (nhiều luồng hoặc tiến trình)

Ưu điểm khác là thao tác tệp (như thêm / xóa ngày trong ví dụ) có thể được thực hiện bằng các lệnh shell thông thường, điều này không thể thực hiện được ở các định dạng tệp nâng cao / phức tạp hơn

Cách tiếp cận này không bao gồm tất cả các kịch bản, nhưng rất hữu ích trong nhiều trường hợp


39
Đã đồng ý. Với tất cả sự cường điệu, thật dễ dàng để quên rằng các công cụ dòng lệnh có thể nhanh hơn 235 lần so với cụm Hadoop
zelusp

83

Bây giờ, hai năm sau câu hỏi, một con gấu trúc 'ngoài luồng' tương đương: dask . Thật xuất sắc! Mặc dù nó không hỗ trợ tất cả các chức năng của gấu trúc, nhưng bạn có thể thực sự đi xa với nó.


6
và để có một ví dụ hoàn chỉnh với dask, chỉ cần xem tại đây stackoverflow.com/questions/37979167/
mẹo

Tùy thuộc vào dữ liệu của bạn, có ý nghĩa để xem xét vào pystore . Nó dựa vào dask.
gies0r

66

Nếu bộ dữ liệu của bạn nằm trong khoảng từ 1 đến 20 GB, bạn sẽ nhận được một máy trạm có 48 GB RAM. Sau đó, Pandas có thể giữ toàn bộ dữ liệu trong RAM. Tôi biết đó không phải là câu trả lời mà bạn đang tìm kiếm ở đây, nhưng thực hiện tính toán khoa học trên máy tính xách tay có 4GB RAM là không hợp lý.


7
"Thực hiện tính toán khoa học trên máy tính xách tay có 4GB RAM là không hợp lý" Xác định hợp lý. Tôi nghĩ UNIVAC sẽ có một cái nhìn khác. arstechnica.com/tech-policy/2011/09/ hy
viêm grisa

2
Đã đồng ý! cố gắng tiếp tục làm việc trong bộ nhớ ngay cả khi chi phí $$ lên phía trước. Nếu công việc của bạn dẫn đến lợi nhuận tài chính, thì theo thời gian, bạn sẽ thu hồi chi phí thông qua hiệu quả tăng lên của bạn.
ansonw

2
Thực hiện tính toán khoa học trên máy trạm với 48GB RAM là không hợp lý.
Yaroslav Nikitenko

4
@YaroslavNikitenko Một r4.2xlund với 61GB / RAM là $ 0,55 / giờ. Bạn đang làm loại máy tính khoa học nào không có giá trị? Nghe có vẻ bất thường, nếu không muốn nói là không hợp lý.
rjurney

4
@rjurney xin lỗi, có lẽ tôi nên xóa bình luận của mình. Đánh giá của bạn về máy tính khoa học "không hợp lý" có vẻ rất chủ quan. Tôi làm các tính toán khoa học của mình trong nhiều năm trên máy tính xách tay, và điều đó dường như là đủ với tôi, vì hầu hết thời gian tôi viết mã. Các thuật toán của tôi khó khăn hơn nhiều từ quan điểm lập trình so với quan điểm tính toán. Ngoài ra, tôi khá chắc chắn rằng để viết các thuật toán có thể mở rộng, người ta không nên dựa vào các giới hạn phần cứng hiện tại. Nhận xét của bạn về điện toán của người khác nghe có vẻ hơi khó chịu (ngoài tính chủ quan), bạn có phiền khi xóa vài từ này không?
Yaroslav Nikitenko

58

Tôi biết đây là một chủ đề cũ nhưng tôi nghĩ rằng thư viện Blaze đáng để kiểm tra. Nó được xây dựng cho các loại tình huống.

Từ các tài liệu:

Blaze mở rộng khả năng sử dụng NumPy và Pandas cho điện toán phân tán và ngoài lõi. Blaze cung cấp một giao diện tương tự như NumPy ND-Array hoặc Pandas DataFrame nhưng ánh xạ các giao diện quen thuộc này lên một loạt các công cụ tính toán khác như Postgres hoặc Spark.

Chỉnh sửa: Nhân tiện , nó được hỗ trợ bởi ContinuumIO và Travis Oliphant, tác giả của NumPy.


Một thư viện khác có thể đáng xem là GraphLab Tạo: Nó có cấu trúc giống như DataFrame không bị giới hạn bởi dung lượng bộ nhớ. blog.dato.com/ từ
không thấm nước

52

Đây là trường hợp cho pymongo. Tôi cũng đã tạo nguyên mẫu bằng cách sử dụng máy chủ sql, sqlite, HDF, ORM (SQLAlchemy) trong python. Pymongo đầu tiên và quan trọng nhất là một DB dựa trên tài liệu, vì vậy mỗi người sẽ là một tài liệu ( dictthuộc tính). Nhiều người tạo thành một bộ sưu tập và bạn có thể có nhiều bộ sưu tập (người, thị trường chứng khoán, thu nhập).

pd.dateframe -> pymongo Lưu ý: Tôi sử dụng chunksizein read_csvđể giữ nó ở mức 5 đến 10k hồ sơ (pymongo làm rơi ổ cắm nếu lớn hơn)

aCollection.insert((a[1].to_dict() for a in df.iterrows()))

truy vấn: gt = lớn hơn ...

pd.DataFrame(list(mongoCollection.find({'anAttribute':{'$gt':2887000, '$lt':2889000}})))

.find()trả về một trình vòng lặp để tôi thường sử dụng ichunkedđể cắt thành các trình vòng lặp nhỏ hơn.

Làm thế nào về một tham gia vì tôi thường nhận được 10 nguồn dữ liệu để dán cùng nhau:

aJoinDF = pandas.DataFrame(list(mongoCollection.find({'anAttribute':{'$in':Att_Keys}})))

sau đó (trong trường hợp của tôi đôi khi tôi phải kích hoạt aJoinDFtrước khi "có thể hợp nhất".)

df = pandas.merge(df, aJoinDF, on=aKey, how='left')

Và sau đó bạn có thể viết thông tin mới vào bộ sưu tập chính của mình thông qua phương pháp cập nhật bên dưới. (bộ sưu tập logic so với các nguồn dữ liệu vật lý).

collection.update({primarykey:foo},{key:change})

Trên tra cứu nhỏ hơn, chỉ cần không chuẩn hóa. Ví dụ: bạn có mã trong tài liệu và bạn chỉ cần thêm văn bản mã trường và thực hiện dicttra cứu khi bạn tạo tài liệu.

Bây giờ bạn có một bộ dữ liệu đẹp dựa trên một người, bạn có thể giải phóng logic của mình trên từng trường hợp và tạo thêm thuộc tính. Cuối cùng, bạn có thể đọc vào gấu trúc các chỉ số chính tối đa 3 đến bộ nhớ của bạn và thực hiện khám phá dữ liệu pivots / agg /. Điều này hoạt động với tôi cho 3 triệu bản ghi với số / văn bản lớn / danh mục / mã / số float / ...

Bạn cũng có thể sử dụng hai phương thức được tích hợp trong MongoDB (MapReduce và khung tổng hợp). Xem ở đây để biết thêm thông tin về khung tổng hợp , vì nó có vẻ dễ hơn MapReduce và có vẻ thuận tiện cho công việc tổng hợp nhanh. Lưu ý rằng tôi không cần xác định các lĩnh vực hoặc quan hệ của mình và tôi có thể thêm các mục vào tài liệu. Ở trạng thái hiện tại của bộ công cụ numpy, gấu trúc, python thay đổi nhanh chóng, MongoDB giúp tôi vừa đi làm :)


Xin chào, tôi cũng đang chơi xung quanh với ví dụ của bạn và tôi gặp phải lỗi này khi cố gắng chèn vào cơ sở dữ liệu : In [96]: test.insert((a[1].to_dict() for a in df.iterrows())) --------------- InvalidDocument: Cannot encode object: 0. Bất cứ ý tưởng những gì có thể là sai? Khung dữ liệu của tôi bao gồm tất cả các kiểu chữ int64 và rất đơn giản.
Zelazny7

2
Vâng, tôi đã làm tương tự cho một phạm vi DF đơn giản và int64 từ numpy dường như làm phiền pymongo. Tất cả dữ liệu tôi đã chơi với các chuyển đổi từ CSV (so với giả tạo thông qua phạm vi ()) và có các loại dài và do đó không có vấn đề. Trong numpy bạn có thể chuyển đổi nhưng tôi thấy điều đó là gây khó chịu. Tôi phải thừa nhận 10,1 mặt hàng cho HDF trông thú vị.
brian_the_bungler

43

Tôi phát hiện ra điều này hơi muộn, nhưng tôi làm việc với một vấn đề tương tự (mô hình trả trước thế chấp). Giải pháp của tôi là bỏ qua lớp HDFStore của gấu trúc và sử dụng các pytables thẳng. Tôi lưu mỗi cột dưới dạng một mảng HDF5 riêng lẻ trong tệp cuối cùng của mình.

Quy trình làm việc cơ bản của tôi là trước tiên lấy tệp CSV từ cơ sở dữ liệu. Tôi gzip nó, vì vậy nó không lớn như vậy. Sau đó, tôi chuyển đổi nó thành tệp HDF5 theo hàng, bằng cách lặp qua nó trong python, chuyển đổi từng hàng thành một loại dữ liệu thực và ghi nó thành tệp HDF5. Việc này mất vài chục phút, nhưng nó không sử dụng bất kỳ bộ nhớ nào, vì nó chỉ hoạt động theo từng hàng. Sau đó, tôi "chuyển đổi" tệp HDF5 theo hàng thành tệp HDF5 hướng cột.

Bảng chuyển đổi trông giống như:

def transpose_table(h_in, table_path, h_out, group_name="data", group_path="/"):
    # Get a reference to the input data.
    tb = h_in.getNode(table_path)
    # Create the output group to hold the columns.
    grp = h_out.createGroup(group_path, group_name, filters=tables.Filters(complevel=1))
    for col_name in tb.colnames:
        logger.debug("Processing %s", col_name)
        # Get the data.
        col_data = tb.col(col_name)
        # Create the output array.
        arr = h_out.createCArray(grp,
                                 col_name,
                                 tables.Atom.from_dtype(col_data.dtype),
                                 col_data.shape)
        # Store the data.
        arr[:] = col_data
    h_out.flush()

Đọc lại sau đó trông giống như:

def read_hdf5(hdf5_path, group_path="/data", columns=None):
    """Read a transposed data set from a HDF5 file."""
    if isinstance(hdf5_path, tables.file.File):
        hf = hdf5_path
    else:
        hf = tables.openFile(hdf5_path)

    grp = hf.getNode(group_path)
    if columns is None:
        data = [(child.name, child[:]) for child in grp]
    else:
        data = [(child.name, child[:]) for child in grp if child.name in columns]

    # Convert any float32 columns to float64 for processing.
    for i in range(len(data)):
        name, vec = data[i]
        if vec.dtype == np.float32:
            data[i] = (name, vec.astype(np.float64))

    if not isinstance(hdf5_path, tables.file.File):
        hf.close()
    return pd.DataFrame.from_items(data)

Bây giờ, tôi thường chạy cái này trên một máy có rất nhiều bộ nhớ, vì vậy tôi có thể không đủ cẩn thận với việc sử dụng bộ nhớ của mình. Ví dụ, theo mặc định, hoạt động tải đọc toàn bộ tập dữ liệu.

Điều này thường hiệu quả với tôi, nhưng nó hơi rắc rối và tôi không thể sử dụng phép thuật pytables lạ mắt.

Chỉnh sửa: Ưu điểm thực sự của phương pháp này, so với mặc định các mảng của bản ghi, là sau đó tôi có thể tải dữ liệu vào R bằng h5r, không thể xử lý các bảng. Hoặc, ít nhất, tôi đã không thể khiến nó tải các bảng không đồng nhất.


bạn có phiền khi chia sẻ với tôi một số mã của bạn không? Tôi quan tâm đến cách bạn tải dữ liệu từ một số định dạng văn bản phẳng mà không biết các loại dữ liệu trước khi đẩy sang pytables. Ngoài ra, có vẻ như bạn chỉ làm việc với dữ liệu của một loại. Đúng không?
Zelazny7

1
Trước hết, tôi giả sử tôi biết các loại cột trước khi tải, thay vì cố gắng đoán từ dữ liệu. Tôi lưu tệp JSON "data spec" với tên và kiểu cột và sử dụng tệp đó khi xử lý dữ liệu. (Tệp thường là một số đầu ra BCP khủng khiếp mà không có bất kỳ nhãn nào.) Các loại dữ liệu tôi sử dụng là chuỗi, số float, số nguyên hoặc ngày hàng tháng. Tôi biến các chuỗi thành int bằng cách lưu bảng liệt kê và chuyển đổi ngày thành int (tháng trước năm 2000), vì vậy tôi chỉ còn lại ints và nổi trong dữ liệu của mình, cộng với liệt kê. Bây giờ tôi lưu các float như float64, nhưng tôi đã thử nghiệm với float32.
Johann Hibschman

1
nếu bạn có thời gian, vui lòng thử cái này cho compat bên ngoài với R: pandas.pydata.org/pandas-docs/dev/ trộm , và nếu bạn gặp khó khăn, có lẽ chúng ta có thể điều chỉnh nó
Jeff

Tôi sẽ thử, nếu tôi có thể. rhdf5 là một nỗi đau, vì nó là một gói chất dẫn sinh học, thay vì chỉ trên CRAN như h5r. Tôi rất hài lòng với đội ngũ kiến ​​trúc kỹ thuật của chúng tôi và đã có một số vấn đề với rhdf5 lần trước tôi đã yêu cầu nó. Trong mọi trường hợp, có vẻ như là một sai lầm khi đi theo hướng hàng thay vì hướng theo cột với cửa hàng OLAP, nhưng bây giờ tôi đang lan man.
Johann Hibschman

38

Một mẹo tôi thấy hữu ích cho các trường hợp sử dụng dữ liệu lớn là giảm âm lượng dữ liệu bằng cách giảm độ chính xác float xuống 32 bit. Nó không được áp dụng trong mọi trường hợp, nhưng trong nhiều ứng dụng, độ chính xác 64 bit là quá mức cần thiết và tiết kiệm bộ nhớ 2x là xứng đáng. Để làm cho một điểm rõ ràng thậm chí còn rõ ràng hơn:

>>> df = pd.DataFrame(np.random.randn(int(1e8), 5))
>>> df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float64(5)
memory usage: 3.7 GB

>>> df.astype(np.float32).info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000000 entries, 0 to 99999999
Data columns (total 5 columns):
...
dtypes: float32(5)
memory usage: 1.9 GB

26

Theo ghi nhận của những người khác, sau một số năm, một con gấu trúc 'ngoài luồng' đã xuất hiện: dask . Mặc dù dask không phải là sự thay thế thả gấu trúc và tất cả các chức năng của nó, nó nổi bật vì nhiều lý do:

Dask là một thư viện điện toán song song linh hoạt cho điện toán phân tích, được tối ưu hóa để lập lịch tác vụ động cho khối lượng công việc tính toán tương tác của các bộ sưu tập của Big Big Data như các mảng song song, datafram và liệt kê các giao diện phổ biến như NumPy, Pandas hoặc Python iterators để lớn hơn- hơn bộ nhớ hoặc môi trường phân tán và quy mô từ máy tính xách tay đến cụm.

Dask nhấn mạnh những đức tính sau:

  • Quen thuộc: Cung cấp các đối tượng mảng NumPy và Pandas DataFrame song song
  • Linh hoạt: Cung cấp giao diện lập lịch tác vụ cho khối lượng công việc tùy chỉnh hơn và tích hợp với các dự án khác.
  • Bản địa: Cho phép tính toán phân tán trong Pure Python với quyền truy cập vào ngăn xếp PyData.
  • Nhanh: Hoạt động với chi phí thấp, độ trễ thấp và tuần tự hóa tối thiểu cần thiết cho các thuật toán số nhanh
  • Cân lên: Chạy một cách kiên cường trên các cụm có 1000 lõi. Cân xuống: Không quan trọng để thiết lập và chạy trên máy tính xách tay trong một quy trình duy nhất
  • Responsive: Được thiết kế với tính toán tương tác, nó cung cấp phản hồi và chẩn đoán nhanh chóng để hỗ trợ con người

và để thêm một mẫu mã đơn giản:

import dask.dataframe as dd
df = dd.read_csv('2015-*-*.csv')
df.groupby(df.user_id).value.mean().compute()

thay thế một số mã gấu trúc như thế này:

import pandas as pd
df = pd.read_csv('2015-01-01.csv')
df.groupby(df.user_id).value.mean()

và, đặc biệt đáng chú ý, cung cấp thông qua concurrent.futuresgiao diện một cơ sở hạ tầng chung để gửi các tác vụ tùy chỉnh:

from dask.distributed import Client
client = Client('scheduler:port')

futures = []
for fn in filenames:
    future = client.submit(load, fn)
    futures.append(future)

summary = client.submit(summarize, futures)
summary.result()

Tôi đã thêm câu trả lời này vì bài đăng của @Private xuất hiện thường xuyên trên danh sách gợi ý xóa nội dung và độ dài.
wp78de

17

Điều đáng nói ở đây là Ray ,
đó là một khung tính toán phân tán, có triển khai riêng cho gấu trúc theo cách phân tán.

Chỉ cần thay thế nhập khẩu gấu trúc và mã sẽ hoạt động như sau:

# import pandas as pd
import ray.dataframe as pd

#use pd as usual

có thể đọc thêm chi tiết tại đây:

https://awn.cs.ber siêu.edu / blog / pasas-on-ray /


16

Thêm một biến thể

Nhiều thao tác được thực hiện trong gấu trúc cũng có thể được thực hiện dưới dạng truy vấn db (sql, mongo)

Sử dụng RDBMS hoặc mongodb cho phép bạn thực hiện một số tập hợp trong Truy vấn DB (được tối ưu hóa cho dữ liệu lớn và sử dụng bộ đệm và chỉ mục một cách hiệu quả)

Sau đó, bạn có thể thực hiện xử lý bài bằng cách sử dụng gấu trúc.

Ưu điểm của phương pháp này là bạn có được tối ưu hóa DB để làm việc với dữ liệu lớn, trong khi vẫn xác định logic theo cú pháp khai báo mức cao - và không phải xử lý các chi tiết quyết định phải làm gì trong bộ nhớ và phải làm gì cốt lõi.

Và mặc dù ngôn ngữ truy vấn và gấu trúc là khác nhau, nhưng thường không phức tạp để dịch một phần logic từ cái này sang cái khác.


11

Hãy xem xét Ruffus nếu bạn đi theo con đường đơn giản là tạo một đường ống dữ liệu được chia thành nhiều tệp nhỏ hơn.


9

Gần đây tôi đã gặp một vấn đề tương tự. Tôi thấy chỉ đơn giản là đọc dữ liệu trong các đoạn và nối thêm nó khi tôi viết nó thành các đoạn cho cùng một csv hoạt động tốt. Vấn đề của tôi là thêm một cột ngày dựa trên thông tin trong một bảng khác, sử dụng giá trị của các cột nhất định như sau. Điều này có thể giúp những người bối rối bởi dask và hdf5 nhưng quen thuộc hơn với gấu trúc như tôi.

def addDateColumn():
"""Adds time to the daily rainfall data. Reads the csv as chunks of 100k 
   rows at a time and outputs them, appending as needed, to a single csv. 
   Uses the column of the raster names to get the date.
"""
    df = pd.read_csv(pathlist[1]+"CHIRPS_tanz.csv", iterator=True, 
                     chunksize=100000) #read csv file as 100k chunks

    '''Do some stuff'''

    count = 1 #for indexing item in time list 
    for chunk in df: #for each 100k rows
        newtime = [] #empty list to append repeating times for different rows
        toiterate = chunk[chunk.columns[2]] #ID of raster nums to base time
        while count <= toiterate.max():
            for i in toiterate: 
                if i ==count:
                    newtime.append(newyears[count])
            count+=1
        print "Finished", str(chunknum), "chunks"
        chunk["time"] = newtime #create new column in dataframe based on time
        outname = "CHIRPS_tanz_time2.csv"
        #append each output to same csv, using no header
        chunk.to_csv(pathlist[2]+outname, mode='a', header=None, index=None)

8

Tôi muốn chỉ ra gói Vaex.

Vaex là một thư viện python dành cho các DataFrames lười biếng (tương tự như Pandas), để trực quan hóa và khám phá các bộ dữ liệu dạng bảng lớn. Nó có thể tính toán các số liệu thống kê như trung bình, tổng, đếm, độ lệch chuẩn, v.v., trên lưới N chiều lên tới một tỷ (10 9 ) đối tượng / hàng mỗi giây. Hình dung được thực hiện bằng cách sử dụng biểu đồ, biểu đồ mật độ và kết xuất khối lượng 3d, cho phép khám phá tương tác dữ liệu lớn. Vaex sử dụng ánh xạ bộ nhớ, chính sách sao chép bộ nhớ bằng 0 và tính toán lười biếng để có hiệu suất tốt nhất (không lãng phí bộ nhớ).

Hãy xem tài liệu: https://vaex.readthedocs.io/en/latest/ API rất gần với API của gấu trúc.


0

Tại sao gấu trúc? Bạn đã thử Python chuẩn chưa?

Việc sử dụng python thư viện tiêu chuẩn. Pandas có thể cập nhật thường xuyên, ngay cả với phiên bản ổn định gần đây.

Sử dụng thư viện python tiêu chuẩn, mã của bạn sẽ luôn chạy.

Một cách để làm điều đó là có một ý tưởng về cách bạn muốn lưu trữ dữ liệu của mình và những câu hỏi bạn muốn giải quyết liên quan đến dữ liệu. Sau đó, vẽ một lược đồ về cách bạn có thể sắp xếp dữ liệu của mình (nghĩ các bảng) sẽ giúp bạn truy vấn dữ liệu, không nhất thiết phải chuẩn hóa.

Bạn có thể sử dụng tốt:

  • danh sách các từ điển để lưu trữ dữ liệu trong bộ nhớ, một từ điển là một hàng,
  • trình tạo để xử lý hàng dữ liệu sau hàng để không làm tràn RAM của bạn,
  • liệt kê sự hiểu biết để truy vấn dữ liệu của bạn,
  • sử dụng Counter, DefaultDict, ...
  • lưu trữ dữ liệu của bạn trên ổ cứng bằng bất kỳ giải pháp lưu trữ nào bạn đã chọn, json có thể là một trong số đó.

Ram và HDD ngày càng rẻ hơn theo thời gian và python 3 tiêu chuẩn có sẵn rộng rãi và ổn định.


-1

Hiện tại tôi đang làm việc "thích" bạn, chỉ ở quy mô thấp hơn, đó là lý do tại sao tôi không có PoC cho đề xuất của mình.

Tuy nhiên, tôi dường như tìm thấy thành công trong việc sử dụng pickle làm hệ thống lưu trữ và thực hiện gia công các chức năng khác nhau vào các tệp - thực thi các tệp này từ tệp lệnh / chính của tôi; Ví dụ: tôi sử dụng một Chuẩn bị để sử dụng để chuyển đổi các loại đối tượng, phân chia một tập dữ liệu thành tập dữ liệu kiểm tra, xác thực và dự đoán.

Làm thế nào để bộ nhớ đệm của bạn với dưa chua hoạt động? Tôi sử dụng các chuỗi để truy cập các tệp pickle được tạo động, tùy thuộc vào tham số và tập dữ liệu nào được truyền (với điều đó tôi cố gắng nắm bắt và xác định xem chương trình đã chạy chưa, sử dụng .shape cho tập dữ liệu, dict cho thông số). Tôn trọng các biện pháp này, tôi nhận được một Chuỗi để cố gắng tìm và đọc tệp .pickle và nếu có thể, hãy bỏ qua thời gian xử lý để chuyển sang thực thi mà tôi đang làm việc ngay bây giờ.

Tuy nhiên, khi sử dụng cơ sở dữ liệu tôi gặp phải các vấn đề tương tự, đó là lý do tại sao tôi tìm thấy niềm vui khi sử dụng giải pháp này, tuy nhiên - có nhiều hạn chế chắc chắn - ví dụ như lưu trữ các bộ dưa chua khổng lồ do dư thừa. Việc cập nhật bảng từ trước đến sau khi chuyển đổi có thể được thực hiện bằng cách lập chỉ mục thích hợp - thông tin xác thực sẽ mở ra một cuốn sách khác (Tôi đã thử hợp nhất dữ liệu cho thuê được thu thập thông tin và ngừng sử dụng cơ sở dữ liệu sau 2 giờ về cơ bản - vì tôi muốn quay lại sau mọi quá trình biến đổi)

Tôi hy vọng 2 xu của tôi sẽ giúp bạn theo một cách nào đó.

Lời chào hỏi.

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.