2012-02-19 38 views
14

Tôi có tệp có kích thước vừa phải (4GB CSV) trên máy tính không có đủ RAM để đọc trong (8GB trên Windows 64 bit). Trong quá khứ tôi chỉ nạp nó lên một nút cluster và đọc nó, nhưng cluster mới của tôi dường như tự ý giới hạn các tiến trình lên 4GB RAM (mặc dù phần cứng có 16GB cho mỗi máy), vì vậy tôi cần một bản sửa lỗi ngắn hạn .Chiến lược để đọc trong tệp CSV thành nhiều phần?

Có cách nào để đọc một phần tệp CSV thành R để phù hợp với giới hạn bộ nhớ có sẵn không? Bằng cách đó tôi có thể đọc trong một phần ba của tập tin tại một thời điểm, tập hợp nó xuống các hàng và cột tôi cần, và sau đó đọc trong phần ba tiếp theo?

Nhờ bình luận để chỉ ra rằng tôi có khả năng có thể đọc trong toàn bộ tập tin sử dụng một số thủ thuật bộ nhớ lớn: Quickly reading very large tables as dataframes in R

tôi có thể nghĩ ra một số cách giải quyết khác (ví dụ mở trong một trình soạn thảo văn bản tốt, lop tắt 2/3 của các quan sát, sau đó tải trong R), nhưng tôi muốn tránh chúng nếu có thể.

Vì vậy, đọc nó theo từng mảnh vẫn có vẻ là cách tốt nhất để thực hiện ngay bây giờ.

+2

Điều này đã được thảo luận chi tiết ở đây, đặc biệt câu trả lời của JD Long khá hữu ích: http://stackoverflow.com/questions/1727772/quickly-reading-very-large-tables-as-dataframes-in-r –

+0

gói ff có khung dữ liệu – mdsumner

+0

Xin lỗi, điều đó trả lời câu hỏi đầu tiên. Rõ ràng SO tìm kiếm-fu của tôi cần mài giũa, như tôi đã tìm kiếm nhưng không thể tìm thấy nó. Nó bỏ cái thứ hai chưa được trả lời: cách đọc trong một tệp .CSV thành nhiều phần. –

Trả lời

8

Bạn có thể đọc nó vào cơ sở dữ liệu bằng RSQLite, và sau đó sử dụng câu lệnh sql để lấy một phần.

Nếu bạn chỉ cần một phần duy nhất thì read.csv.sql trong gói sqldf sẽ đọc dữ liệu vào cơ sở dữ liệu sqlite. Nó tạo ra cơ sở dữ liệu cho bạn và dữ liệu không đi qua R nên các giới hạn của R sẽ không áp dụng. Sau khi đọc nó vào cơ sở dữ liệu, nó đọc đầu ra của một câu lệnh sql được chỉ định vào R và sau đó phá hủy cơ sở dữ liệu. Tùy thuộc vào tốc độ làm việc với dữ liệu của bạn, bạn có thể chỉ cần lặp lại toàn bộ quá trình cho từng phần nếu bạn có nhiều phần.

Vì chỉ có một dòng mã của nó để thực hiện toàn bộ một phần cho một phần của nó nên không cần phải thử. DF <- read.csv.sql("myfile.csv", sql=..., ...other args...). Xem ?read.csv.sql?sqldf và cũng là sqldf home page.

+0

Rất hay. Tuy nhiên có vẻ như một chút không hiệu quả mặc dù để đọc trong toàn bộ tập tin và đổ phần lớn của nó. Nó cho thấy rằng tôi có thể chỉ cần đặt nó xuống trạng thái mà tôi muốn trong SQL mặc dù, mà có khả năng giải quyết vấn đề của tôi. –

+1

Nếu bạn chỉ cần đặt nó xuống một tập hợp các hàng cụ thể thì bạn chỉ có thể sử dụng 'read.table (..., skip = ..., nrows = ...)' –

+0

Tôi đã quên mất điều đó. Wow, thực sự có một câu hỏi thất bại trong ngày. Nhưng tôi đã học được hai điều mới từ điều này ('ff' gói và' sqldf' cả hai đều có một tùy chọn bộ lọc), do đó, có lẽ giá trị nó. –

20

Tôi biết rằng đây là một chuỗi rất cũ. Tuy nhiên tôi đã đi qua nó gần đây bởi vì tôi đã có một vấn đề tương tự. Sau khi xem qua chủ đề này, tôi nhận thấy một giải pháp dễ thấy cho vấn đề này không được đề cập. Sử dụng kết nối!

1) Mở một kết nối đến tập tin của bạn

con = file("file.csv", "r") 

2) Đọc trong khối mã với read.csv

read.csv(con, nrows="CHUNK SIZE",...) 

Side lưu ý: colClasses định này sẽ tăng tốc mọi thứ lên. Đảm bảo xác định cột không mong muốn là NULL.

3) Làm những gì bạn cần làm

4) Lặp lại.

5) Đóng kết nối

close(con) 

Ưu điểm của phương pháp này là các kết nối. Nếu bạn bỏ qua bước này, nó có thể sẽ làm chậm mọi thứ xuống một chút. Bằng cách mở một kết nối theo cách thủ công, về cơ bản bạn mở tập dữ liệu và không đóng nó cho đến khi bạn gọi hàm đóng. Điều này có nghĩa là khi bạn lặp qua tập dữ liệu, bạn sẽ không bao giờ mất vị trí của mình. Hãy tưởng tượng rằng bạn có tập dữ liệu với 1e7 hàng. Cũng hãy tưởng tượng rằng bạn muốn tải một đoạn của 1e5 hàng tại một thời điểm.Vì chúng tôi mở kết nối, chúng tôi có được các hàng 1e5 đầu tiên bằng cách chạy read.csv(con, nrow=1e5,...), sau đó để lấy đoạn thứ hai, chúng tôi cũng chạy read.csv(con, nrow=1e5,...), v.v ...

Nếu chúng tôi không sử dụng kết nối chúng tôi sẽ nhận chunk theo cùng một cách, read.csv("file.csv", nrow=1e5,...), tuy nhiên đối với đoạn tiếp theo, chúng tôi sẽ cần phải read.csv("file.csv", skip = 1e5, nrow=2e5,...). Rõ ràng điều này là không hiệu quả. Chúng ta phải tìm lại hàng 1e5 + 1, mặc dù thực tế là chúng ta chỉ đọc trong hàng 1e5.

Cuối cùng, data.table::fread thật tuyệt. Nhưng bạn không thể vượt qua nó kết nối. Cách tiếp cận này không hiệu quả.

Tôi hy vọng điều này sẽ giúp ai đó.

CẬP NHẬT

dân giữ upvoting bài này vì vậy tôi nghĩ tôi sẽ bổ sung thêm một suy nghĩ ngắn gọn. readr::read_csv mới, như read.csv, có thể được thông qua kết nối. Tuy nhiên, nó là advertised nhanh hơn khoảng 10 lần.

+2

fread data.table đã lên kế hoạch hỗ trợ cho kết nối trong bản phát hành ổn định tiếp theo, chi tiết hơn trong [data.table # 561] (https://github.com/Rdatatable/data.table/issues/561) – jangorecki

+2

Lưu ý rằng 'đọc * 'Các chức năng của gói' iotools' có thể được cấp một kết nối. – lmo

Các vấn đề liên quan