2013-06-17 37 views
9

Tôi đã được làm việc theo cách của mình thông qua Rcpp hướng dẫn Dirk Eddelbuettel ở đây:Chạy biên soạn C++ với Rcpp

http://www.rinfinance.com/agenda/

Tôi đã học được làm thế nào để tiết kiệm ++ tập tin C trong một thư mục và gọi nó và chạy nó từ trong R. C++ tập tôi đang chạy được gọi là 'logabs2.ccp' và nội dung của nó là trực tiếp từ một trong slide Dirk của:

#include <Rcpp.h> 

using namespace Rcpp; 

inline double f(double x) { return ::log(::fabs(x)); } 

// [[Rcpp::export]] 
std::vector<double> logabs2(std::vector<double> x) { 
    std::transform(x.begin(), x.end(), x.begin(), f); 
    return x; 
} 

tôi chạy nó với mã R này:

library(Rcpp) 
sourceCpp("c:/users/mmiller21/simple r programs/logabs2.cpp") 
logabs2(seq(-5, 5, by=2)) 
# [1] 1.609438 1.098612 0.000000 0.000000 1.098612 1.609438 

Tôi đang chạy mã trên máy tính Windows 7 từ bên trong R GUI dường như cài đặt theo mặc định. Tôi cũng đã cài đặt phiên bản mới nhất của Rtools. Mã R ở trên dường như mất một thời gian tương đối dài để chạy. Tôi nghi ngờ hầu hết thời gian đó được dành để biên dịch mã C++ và khi mã C++ được biên dịch, nó chạy rất nhanh. Microbenchmark chắc chắn cho thấy rằng Rcpp làm giảm thời gian tính toán.

Tôi chưa bao giờ sử dụng C++ cho đến bây giờ, nhưng tôi biết rằng khi tôi biên dịch mã C, tôi nhận được tệp * .exe. Tôi đã tìm kiếm ổ cứng của mình từ một tệp có tên là logabs2.exe nhưng không thể tìm thấy một tệp. Tôi tự hỏi liệu mã C++ ở trên có thể chạy nhanh hơn nếu tệp logabs2.exe được tạo. Có thể tạo một tập tin logabs2.exe và lưu nó vào một thư mục ở đâu đó và sau đó Rcpp gọi tập tin đó bất cứ khi nào tôi muốn sử dụng nó? Tôi không biết liệu điều đó có hợp lý hay không. Nếu tôi có thể lưu trữ một hàm C++ trong tệp * .exe thì có lẽ tôi sẽ không phải biên dịch hàm mỗi khi tôi muốn sử dụng nó với Rcpp và sau đó có lẽ mã Rcpp sẽ còn nhanh hơn nữa.

Xin lỗi nếu câu hỏi này không có ý nghĩa hoặc trùng lặp. Nếu có thể lưu trữ hàm C++ dưới dạng tệp * .exe, tôi hy vọng một người nào đó sẽ chỉ cho tôi cách sửa đổi mã R của tôi ở trên để chạy nó. Cảm ơn bạn đã giúp đỡ với điều này hoặc để đặt tôi thẳng vào lý do tại sao những gì tôi đề nghị là không thể hoặc được đề nghị.

Tôi rất mong được thấy cuốn sách mới của Dirk.

+2

Bạn đã xem lệnh 'R CMD SHLIB' chưa? Với điều đó bạn chỉ có thể biên dịch hàm C++ của bạn thành một tệp dll và sau đó tải tệp đã biên dịch bằng 'dyn.load()'. Có một cái nhìn tại '? SHLIB' và'? Dyn.load' để biết chi tiết! – user1981275

+0

@ user1981275 Cảm ơn bạn đã bình luận. Cho đến nay tôi đã nhận được đến thời điểm này: C: \ Program Files \ R \ R-3.0.1 \ bin \ x64> rcmd SHLIB -oc: \ người dùng \ mmiller21 \ documents \ r \ win-library \ 3.0 \ rcpp \ include \ logabs2.dll c: \ users \ mmiller21 \ documents \ r \ win \ thư viện \ 3.0 \ rcpp \ include \ logabs2.cpp Tôi nhận được thông báo sau: make: *** Không có quy tắc để làm cho mục tiêu 'c: \ users \ mmiller21 \ documents \ r \ win-library \ 3.0 \ rcpp \ include \ logabs2.o ', cần thiết bởi' c: \ users \ mmiller21 \ documents \ r \ win \ thư viện \ 3.0 \ rcpp \ include \ logabs2.dll '. Dừng lại. Thông báo dường như nói rằng tôi đang thiếu một tệp đối tượng, quen thuộc với tôi từ công việc của tôi với C. –

+0

Tôi đang sử dụng cửa sổ lệnh DOS. Nếu vấn đề thực sự là một tập tin đối tượng bị thiếu, bạn có thể gợi ý cách tôi có thể tạo một tệp đối tượng không? Có lẽ một khi nó được tạo ra nó sẽ đi vào một danh sách cùng với logabs2.cpp ở cuối lệnh trong bình luận trước? Cảm ơn bạn bất kể. –

Trả lời

4

Bạn nói

Tôi chưa bao giờ sử dụng C++ cho đến bây giờ, nhưng tôi biết rằng khi tôi biên dịch mã C tôi nhận được một file * .exe

và đó là đúng khi và chỉ bạn tạo một tệp thực thi . Ở đây, chúng tôi xây dựng thư viện có thể load được và những thend có extensionos khác nhau tùy thuộc vào hệ điều hành: .dll cho Windoze, .so cho Linux, .dynlib cho OS X.

Vì vậy, không có gì sai ở đây, bạn chỉ cần có giả định sai lầm.

1

Nếu bạn muốn nhận được một số thực thể bạn có thể giữ, những gì bạn đang tìm kiếm là gói R. Có nhiều tài nguyên trực tuyến để tìm hiểu cách tạo chúng (ví dụ: Hadley's slides).

Chúng tôi có Rcpp.package.skeleton bạn có thể thấy hữu ích.

Vì vậy, chức năng được biên dịch một lần khi gói được cài đặt, và sau đó bạn chỉ cần sử dụng nó.

6

Cảm ơn người dùng1981275, Dirk Eddelbuettel và Romain Francois cho câu trả lời của họ. Dưới đây là cách tôi biên soạn một tệp C++ và tạo một tệp * .dll, sau đó gọi và sử dụng tệp * .dll đó bên trong R.

Bước 1. Tôi đã tạo thư mục mới có tên 'c: \ users \ mmiller21 \ myrpackages' và dán tệp 'logabs2.cpp' vào thư mục mới đó. Tệp 'logabs2.cpp' đã được tạo như được mô tả trong bài đăng gốc của tôi.

Bước 2. Bên trong thư mục mới, tôi đã tạo gói R mới có tên 'logabs2' bằng cách sử dụng tệp R tôi đã viết có tên là 'tạo gói mới.r'. Nội dung của 'gói creation.r mới' là:

setwd('c:/users/mmiller21/myrpackages/') 

library(Rcpp) 

Rcpp.package.skeleton("logabs2", example_code = FALSE, cpp_files = c("logabs2.cpp")) 

tôi thấy cú pháp trên cho Rcpp.package.skeleton trên một trong những trang web Hadley Wickham: https://github.com/hadley/devtools/wiki/Rcpp

Bước 3. Tôi đã cài đặt R gói mới "logabs2" trong R sử dụng dòng sau trong cửa sổ lệnh DOS:

C:\Program Files\R\R-3.0.1\bin\x64>R CMD INSTALL -l c:\users\mmiller21\documents\r\win-library\3.0\ c:\users\mmiller21\myrpackages\logabs2 

nơi:

vị trí của tập tin rcmd.exe là:

C:\Program Files\R\R-3.0.1\bin\x64> 

vị trí của cài đặt R gói trên máy tính của tôi là:

c:\users\mmiller21\documents\r\win-library\3.0\ 

và vị trí của R gói mới của tôi trước khi được cài đặt là:

c:\users\mmiller21\myrpackages\ 

Cú pháp được sử dụng trong cửa sổ lệnh DOS được tìm thấy bằng thử và lỗi và có thể không lý tưởng. Tại một số điểm tôi dán một bản sao của 'logabs2.cpp' trong 'C: \ Program Files \ R \ R-3.0.1 \ bin \ x64>' nhưng tôi không nghĩ rằng vấn đề.

Bước 4. Sau khi cài đặt R gói mới Tôi chạy nó sử dụng một tập tin R Tôi tên là 'gói usage.r mới' trong 'c:/users/mmiller21/myrpackages /' thư mục (mặc dù tôi không nghĩ rằng thư mục quan trọng). Nội dung của 'gói mới usage.r' là:

library(logabs2) 
logabs2(seq(-5, 5, by=2)) 

Kết quả là:

# [1] 1.609438 1.098612 0.000000 0.000000 1.098612 1.609438 

Tập tin này nạp gói Rcpp mà không có tôi yêu cầu.

Trong trường hợp này, cơ sở R nhanh hơn giả sử tôi đã thực hiện điều này một cách chính xác.

#> microbenchmark(logabs2(seq(-5, 5, by=2)), times = 100) 
#Unit: microseconds 
#      expr min  lq median  uq  max neval 
# logabs2(seq(-5, 5, by = 2)) 43.086 44.453 50.6075 69.756 190.803 100 

#> microbenchmark(log(abs(seq(-5, 5, by=2))), times=100) 
#Unit: microseconds 
#       expr min  lq median uq  max neval 
# log(abs(seq(-5, 5, by = 2))) 38.298 38.982 39.666 40.35 173.023 100 

Tuy nhiên, bằng cách sử dụng tập tin dll là nhanh hơn so với cách gọi tập tin cpp bên ngoài:

system.time(

cppFunction(" 
NumericVector logabs(NumericVector x) { 
    return log(abs(x)); 
} 
") 

) 

# user system elapsed 
# 0.06 0.08 5.85 

Mặc dù cơ sở R dường như nhanh hơn hoặc nhanh như * .dll file trong trường hợp này, tôi không có nghi ngờ rằng việc sử dụng tệp * .dll với Rcpp sẽ nhanh hơn cơ sở R trong hầu hết các trường hợp.

Đây là nỗ lực đầu tiên của tôi khi tạo gói R hoặc sử dụng Rcpp và không nghi ngờ gì nữa, tôi đã không sử dụng các phương pháp hiệu quả nhất. Ngoài ra, tôi xin lỗi vì bất kỳ lỗi chính tả nào trong bài đăng này.

EDIT

Trong một bình luận dưới đây tôi nghĩ Romain Francois đề nghị tôi thay đổi * .cpp tập tin như sau:

#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::export]] 

NumericVector logabs(NumericVector x) { 
return log(abs(x)); 
} 

và tái R gói của tôi, mà bây giờ tôi đã làm. sau đó tôi so cơ sở R chống lại gói mới của tôi bằng cách sử dụng đoạn mã sau:

library(logabs) 

logabs(seq(-5, 5, by=2)) 
log(abs(seq(-5, 5, by=2))) 

library(microbenchmark) 

microbenchmark(logabs(seq(-5, 5, by=2)), log(abs(seq(-5, 5, by=2))), times = 100000) 

cơ sở R vẫn là nhanh hơn một chút hoặc không có khác nhau:

Unit: microseconds 
         expr min  lq median  uq  max neval 
    logabs(seq(-5, 5, by = 2)) 42.401 45.137 46.505 69.073 39754.598 1e+05 
log(abs(seq(-5, 5, by = 2))) 37.614 40.350 41.718 62.234 3422.133 1e+05 

Có lẽ điều này là do cơ sở R đã được vector hóa. Tôi nghi ngờ với các chức năng phức tạp hơn, cơ sở R sẽ chậm hơn nhiều. Hoặc có lẽ tôi vẫn không sử dụng cách tiếp cận hiệu quả nhất, hoặc có lẽ tôi đã mắc lỗi ở đâu đó.

+0

Sử dụng 'std :: vector ' hoặc 'NumericVector' không giống nhau. 'lobabs2' đầu tiên phải chuyển đổi đối tượng R nó thành' std :: vector ', điều này là tốn kém khi bạn cần sao chép dữ liệu. Sau đó, ở cuối, bạn trả về 'std :: vector ', vì vậy 'Rcpp' cần biến đổi thành đối tượng R, một lần nữa điều này có nghĩa là sao chép dữ liệu. –

+0

Trong khối mã cuối cùng của bạn, bạn đang đo thời gian cần để biên dịch mã. Đây không chỉ là một sự so sánh công bằng. –

+0

@Romain Francois Cảm ơn bạn đã bình luận. Tôi không cố gắng không công bằng. Tôi chỉ đơn giản là chưa học đủ để cung cấp một câu trả lời hiệu quả hơn. Tôi chưa thể có được dyn.load và .Call để làm việc, ví dụ, sau khi tạo tập tin * .dll với Rcpp.package.sk và/hoặc cài đặt gói mới. Tôi cũng chưa thể tạo tệp * .dll bằng SHLIB. Nếu tôi đến một giải pháp hiệu quả hơn, tôi sẽ đăng nó. Mục tiêu của tôi là tìm hiểu cách tối đa hóa tiện ích của Rcpp. –