2012-01-30 24 views
8

Đọc ~ 5x10^6 giá trị số vào R từ một tệp văn bản tương đối chậm trên máy của tôi (một vài giây và tôi đọc một số tệp như vậy), ngay cả với scan(..., what="numeric", nmax=5000) hoặc các thủ thuật tương tự. Có thể đáng để thử một trình bao bọc Rcpp cho loại tác vụ này (ví dụ: Armadillo có một vài tiện ích để đọc tệp văn bản) không? Hoặc tôi có thể lãng phí thời gian của tôi cho ít hoặc không đạt được hiệu suất vì chi phí giao diện dự kiến? Tôi không chắc chắn những gì hiện đang hạn chế tốc độ (hiệu suất máy nội tại, hoặc người nào khác?) Đó là một nhiệm vụ mà tôi lặp lại nhiều lần trong ngày, thông thường, và định dạng tập tin luôn giống nhau, 1000 cột, khoảng 5000 hàng.nhanh hơn quét() với Rcpp?

Đây là tệp mẫu để phát, nếu cần.

nr <- 5000 
nc <- 1000 

m <- matrix(round(rnorm(nr*nc),3),nr=nr) 

cat(m[1, -1], "\n", file = "test.txt") # first line is shorter 
write.table(m[-1, ], file = "test.txt", append=TRUE, 
      row.names = FALSE, col.names = FALSE) 

Cập nhật: Tôi cố gắng read.csv.sql và cũng load("test.txt", arma::raw_ascii) bằng Armadillo và cả hai đều chậm hơn so với các giải pháp scan.

+3

Hãy thử 'read.csv.sql' trong sqldf và xem có nhanh hơn không. Chỉ một dòng mã của nó. http://sqldf.googlecode.com –

+0

Tôi đã thử 'system.time (b <- read.csv.sql (" test.txt ", header = FALSE, sep =" "))' và nó chậm hơn 'hệ thống .time (a <- scan ("test.txt", what = "numeric")) '. Ngoài ra, tôi cho rằng việc lưu trữ dữ liệu vào một ma trận sẽ hiệu quả hơn vào một 'data.frame' – baptiste

Trả lời

8

Tôi đặc biệt khuyên bạn nên kiểm tra fread trong phiên bản mới nhất của data.table. Phiên bản trên CRAN (1.8.6) chưa có fread (tại thời điểm bài đăng này), do đó bạn sẽ có thể tải xuống nếu bạn cài đặt từ nguồn mới nhất tại R-forge. Xem here.

+0

đó thực sự là nhanh hơn nhiều, cảm ơn! – baptiste

5

Xin lưu ý rằng tôi không phải là chuyên gia R nhưng có thể khái niệm cũng áp dụng ở đây: thường đọc nội dung nhị phân nhanh hơn nhiều so với việc đọc tệp văn bản. Nếu tệp nguồn của bạn không thay đổi thường xuyên (ví dụ: bạn đang chạy các phiên bản khác nhau của tập lệnh/chương trình trên cùng một dữ liệu), hãy thử đọc chúng qua quét() một lần và lưu chúng ở định dạng nhị phân (hướng dẫn có chương về xuất tệp nhị phân). Từ đó bạn có thể sửa đổi chương trình của bạn để đọc đầu vào nhị phân.

@Rcpp: scan() & bạn bè có thể gọi triển khai gốc (như fscanf()) để viết các chức năng đọc tệp của riêng bạn qua Rcpp có thể không mang lại hiệu suất lớn. Bạn vẫn có thể thử mặc dù (và tối ưu hóa cho dữ liệu cụ thể của bạn).

+0

re Rcpp, vâng, đó là sự lo lắng của tôi: thực hiện nó chỉ để thấy rằng nó thực hiện giống như' scan() '. Tôi đã hy vọng một ai đó có thể đã tìm ra được điều đó. – baptiste

+0

Tôi hy vọng nó sẽ nhanh hơn rất nhiều, nhưng tất nhiên là ít chung chung hơn. –

3

Có, bạn gần như chắc chắn có thể tạo nội dung nào đó nhanh hơn read.csv/scan. Tuy nhiên, để đọc tệp hiệu suất cao, có một số thủ thuật hiện có đã cho phép bạn đi nhanh hơn nhiều, vì vậy bất cứ điều gì bạn làm sẽ cạnh tranh với chúng.

Như Mathias đã nói, nếu tệp của bạn không thay đổi thường xuyên, bạn có thể lưu chúng bằng cách gọi save, sau đó khôi phục chúng bằng load. (Hãy chắc chắn sử dụng ascii = FALSE, vì đọc các tệp nhị phân sẽ nhanh hơn.)

Thứ hai, như Gabor đã đề cập, bạn thường có thể tăng hiệu suất đáng kể bằng cách đọc tệp của mình vào cơ sở dữ liệu và sau đó từ cơ sở dữ liệu đó sang R.

Thứ ba, bạn có thể sử dụng gói HadoopStreaming để sử dụng khả năng đọc tệp của Hadoop.

Để biết thêm suy nghĩ về các kỹ thuật này, hãy xem Quickly reading very large tables as dataframes in R.

+0

cảm ơn. Tôi nghĩ rằng tôi đã sử dụng tất cả các lời khuyên từ thread SO đó, và không, lưu dữ liệu dưới dạng '.rda' hoặc khác không thực sự là một tùy chọn vì đó là lần nhập đầu tiên làm phiền tôi. Tôi sẽ kiểm tra 'sqldf', mà tôi đã xem xét một thời gian ngắn nhưng cú pháp làm tôi bối rối. – baptiste

4

Salut Baptiste,

dữ liệu Input/Output là một chủ đề rất lớn, lớn đến nỗi R đi kèm với công manual on data input/output.

Chức năng cơ bản của R có thể chậm vì chúng rất chung chung. Nếu bạn biết định dạng của mình, bạn có thể dễ dàng tự viết cho mình một bộ chuyển đổi nhập nhanh hơn. Nếu bạn biết kích thước của bạn quá, nó thậm chí còn dễ dàng hơn khi bạn chỉ cần một cấp phát bộ nhớ.

Chỉnh sửa: Là lần đầu tiên gần đúng, tôi sẽ viết một lớp lót C++.Mở một tệp, đọc một dòng, chia nhỏ nó thành mã thông báo, gán cho một số vector<vector<double> > hoặc một cái gì đó tương tự. Ngay cả khi bạn sử dụng push_back() trên các phần tử vectơ riêng lẻ, bạn phải cạnh tranh với scan(), các liên kết.

Tôi đã từng có một lớp nhỏ gọn csv reader trong C++ dựa trên mã của chính Brian Kernighan. Khá phổ biến (đối với tệp csv), khá mạnh mẽ.

Sau đó, bạn có thể nén hiệu suất như bạn thấy phù hợp.

Chỉnh sửa tiếp theo: Điều này SO question có một số gợi ý cho trường hợp đọc csv và tham chiếu đến sách Kernighan và Plauger.

+0

tôi không biết kích thước chính xác (tốt, một số công cụ unix có thể tìm ra), nhưng 5000 là một ước tính tốt trên thô – baptiste