日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++语言get:_用C++给R语言加速:Rcpp简单用法

發布時間:2023/12/15 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++语言get:_用C++给R语言加速:Rcpp简单用法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:黃天元,復旦大學博士在讀,熱愛數據科學與開源工具(R),致力于利用數據科學迅速積累行業經驗優勢和科學知識發現,涉獵內容包括但不限于信息計量、機器學習、數據可視化、應用統計建模、知識圖譜等,著有《R語言高效數據處理指南》(《R語言數據高效處理指南》(黃天元)【摘要 書評 試讀】- 京東圖書)。知乎專欄:R語言數據挖掘。郵箱:huang.tian-yuan@qq.com.歡迎合作交流。

最近要做一個小任務,它的描述非常簡單,就是識別向量的變化。比如一個整數序列是“4,4,4,5,5,6,6,5,5,5,4,4”,那么我們要根據數字的連續關系來分組,輸出應該是“1,1,1,2,2,3,3,4,4,4,5,5”。這個函數用R寫起來非常簡單,稍加思考草擬如下:

get_id = function(x){z = vector()y = NULLfor (i in seq_along(x)) {if(i == 1) y = 1else if(x[i] != x[i-1]) y = y + 1z = c(z,y)}z }

不妨做個小測試:

get_id = function(x){z = vector()y = NULLfor (i in seq_along(x)) {if(i == 1) y = 1else if(x[i] != x[i-1]) y = y + 1z = c(z,y)}z } c(rep(33L,3),rep(44L,4),rep(33L,3)) #> [1] 33 33 33 44 44 44 44 33 33 33 get_id(c(rep(33L,3),rep(44L,4),rep(33L,3))) #> [1] 1 1 1 2 2 2 2 3 3 3

得到的結果絕對是準確的,而且按照這些代碼,基本可以識別不同的數據類型,只要這些數據能夠用“==”來判斷是否相同(可能用setequal函數的健壯性更好)。

但是當數據量很大的時候,這樣寫是否足夠快,就很重要了。這意味著看你要等一小時、一天還是一個月。想起自己小時候還學過C++,就希望嘗試用Rcpp來加速,擬了代碼如下:

library(Rcpp)# 函數名稱為get_id_c cppFunction('IntegerVector get_id_c(IntegerVector x){int n = x.size();IntegerVector out(n);for (int i = 0; i < n; i++) {if(i == 1) out[i] = 1;else if(x[i] == x[i-1]) out[i] = out[i-1];else out[i] = out[i-1] + 1;}return out; }')

需要聲明的是,C++需要定義數據類型,因為任務是正整數,所以函數就接受一個整數向量,輸出一個整數向量。多年不用C++,寫這么一段代碼居然調試過程就出了3次錯,慚愧。但是對性能的提升效果非常顯著,我們先做一些簡單嘗試。先嘗試1萬個整數:

library(pacman) p_load(tidyfst) sys_time_print({res1 = get_id(c(rep(33L,1e4),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e4),rep(44L,4),rep(33L,3))) })setequal(res1,res2)

0.14s和0.00s的區別,可能體會不夠深。那么來10萬個整數試試:

sys_time_print({res1 = get_id(c(rep(33L,1e5),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e5),rep(44L,4),rep(33L,3))) })setequal(res1,res2)

13s vs 0s,有點不能忍了。那么,我們來100萬個整數再來試試:

# 不要嘗試這個 sys_time_print({res1 = get_id(c(rep(33L,1e6),rep(44L,4),rep(33L,3))) })# 可以嘗試這個 sys_time_print({res2 = get_id_c(c(rep(33L,1e6),rep(44L,4),rep(33L,3))) })setequal(res1,res2)

好的,關于這段代碼:

sys_time_print({res1 = get_id(c(rep(33L,1e6),rep(44L,4),rep(33L,3))) })

可以不要嘗試了,因為直接卡死了。但是如果用Rcpp構造的函數,那么就放心試吧,我們還遠遠沒有探知其算力上限。可以觀察一下結果:

我們可以看到,1億個整數,也就是0.69秒;10億是7.15秒。雖然想嘗試百億,但是我的計算機內存已經不夠了。

總結一下,永遠不敢說R的速度不夠快,只是自己代碼寫得爛而已(盡管完成了實現,其實get_id這個函數優化的空間是很多的),方法總比問題多。不多說了,去溫習C++,學習Rcpp去了。后面如果有閑暇,來做一個Rcpp的學習系列。放一個核心資料鏈接:

Seamless R and C++ Integration?rcpp.org

根據評論區提示,重新寫了R的代碼再來比較。代碼如下:

library(pacman) p_load(Rcpp,tidyfst)get_id = function(x){z = vector()for (i in seq_along(x)) {if(i == 1) z[i] = 1else if(x[i] != x[i-1]) z[i] = z[i-1] + 1else z[i] = z[i-1]}z }cppFunction('IntegerVector get_id_c(IntegerVector x){int n = x.size();IntegerVector out(n);for (int i = 0; i < n; i++) {if(i == 1) out[i] = 1;else if(x[i] == x[i-1]) out[i] = out[i-1];else out[i] = out[i-1] + 1;}return out; }')sys_time_print({res1 = get_id(c(rep(33L,1e4),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e4),rep(44L,4),rep(33L,3))) })setequal(res1,res2)sys_time_print({res1 = get_id(c(rep(33L,1e5),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e5),rep(44L,4),rep(33L,3))) })setequal(res1,res2)sys_time_print({res1 = get_id(c(rep(33L,1e6),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e6),rep(44L,4),rep(33L,3))) })setequal(res1,res2)sys_time_print({res1 = get_id(c(rep(33L,1e7),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e7),rep(44L,4),rep(33L,3))) })setequal(res1,res2)sys_time_print({res1 = get_id(c(rep(33L,1e8),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e8),rep(44L,4),rep(33L,3))) })setequal(res1,res2)sys_time_print({res1 = get_id(c(rep(33L,1e9),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e9),rep(44L,4),rep(33L,3))) })setequal(res1,res2)

1萬:

10萬:

100萬:

1000萬:

1億:

結論:還是Rcpp香。


三更:R代碼提前設置向量長度,再比較。

library(pacman) p_load(Rcpp,tidyfst)get_id = function(x){z = integer(length(x))for (i in seq_along(x)) {if(i == 1) z[i] = 1else if(x[i] != x[i-1]) z[i] = z[i-1] + 1else z[i] = z[i-1]}z }cppFunction('IntegerVector get_id_c(IntegerVector x){int n = x.size();IntegerVector out(n);for (int i = 0; i < n; i++) {if(i == 1) out[i] = 1;else if(x[i] == x[i-1]) out[i] = out[i-1];else out[i] = out[i-1] + 1;}return out; }')sys_time_print({res1 = get_id(c(rep(33L,1e4),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e4),rep(44L,4),rep(33L,3))) })setequal(res1,res2)sys_time_print({res1 = get_id(c(rep(33L,1e5),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e5),rep(44L,4),rep(33L,3))) })setequal(res1,res2)sys_time_print({res1 = get_id(c(rep(33L,1e6),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e6),rep(44L,4),rep(33L,3))) })setequal(res1,res2)sys_time_print({res1 = get_id(c(rep(33L,1e7),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e7),rep(44L,4),rep(33L,3))) })setequal(res1,res2)sys_time_print({res1 = get_id(c(rep(33L,1e8),rep(44L,4),rep(33L,3))) })sys_time_print({res2 = get_id_c(c(rep(33L,1e8),rep(44L,4),rep(33L,3))) })setequal(res1,res2)


四更:對于這個任務來講,data.table的rleid函數是最快的。R語言中的終極魔咒,能找到現成的千萬不要自己寫,總有巨佬在前頭。不過直到10億個整數才有難以忍受的差距。

1億

10億

總結

以上是生活随笔為你收集整理的c++语言get:_用C++给R语言加速:Rcpp简单用法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。