精華區beta R_Language 關於我們 聯絡資訊
如題 最近想手刻實踐 cross validtion的算法 上網查了一下別人的範例code 如下 x <- runif(100)*10 #Random values between 0 and 10 y <- x+rnorm(100)*.1 #y~x+error dataset <- data.frame(x,y) #Create data frame dataset<- dataset[sample(nrow(dataset)),] dataset #here is the trick folds <- cut(seq(1,nrow(dataset)),breaks=5,labels=FALSE) folds sample(nrow(dataset)) for(i in 1:5){ #Segement your data by fold using the which() function #這裡就是我想問的 testIndexes <- which(folds==i,arr.ind=TRUE) #這裡就是我想問的 testData <- dataset[testIndexes, ] trainData <- dataset[-testIndexes, ] #Use the test and train data partitions however you desire... #必須要在這個步驟去套入model 然後計算MSE } 他在切traing 和Testing時 使用了 fold的技巧 但是這整段有沒有可能 不使用for 迴圈 而改用apply家族去實現 因為真的太喜歡使用apply的簡潔了 還希望版友回答 偷偷問另外一個問題 我有一個function s 去計算 x*y s<- function(x,y){ x*y } s( c(2,3) , c(4,5) ) 這裡我會得到 8 15 但其實我想得到的是所有的可能性 8,10,12,15 請問我要如何在保有 input是 c(2,3) , c(4,5) 下 得到我要的結果呢 更甚至在 s ( c(2,3),c(4,5,6,7,8) ) 狀況下也可以得到遍歷的結果 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 219.91.75.186 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/R_Language/M.1585076880.A.0D5.html ※ 編輯: empireisme (219.91.75.186 臺灣), 03/25/2020 03:44:33
andrew43: 最後的問題用outer 03/25 07:39
locka: 推outer沒想到還有這招 03/25 07:55
empireisme: ty 03/25 13:25
jezi1878: 第二個問題很簡單吧,用兩個for迴圈就可以達成 03/26 10:10
jezi1878: https://i.imgur.com/9Nno130.png 03/26 10:10
empireisme: 第二個例子用for真的很簡單呢! 03/26 11:13
locka: outer( c(2:3), c(4:8) ) 原生好東西,不用嗎XD 03/26 11:22
> -------------------------------------------------------------------------- < 作者: locka (locka) 看板: R_Language 標題: Re: [問題]不使用for改使用apply寫法的可能性 時間: Wed Mar 25 07:52:19 2020 (同是apply家族愛好者先shout out一下XD) 以前看過版主C大跟其他前輩版友的討論,結論是 apply 效率並沒有比較好 (印象中好像背後都還是用for迴圈?!) 不過我覺得向量化(vectorized)是R語言裡面很重要的一個特性 也是functional programming跟其他程式語言不一樣的地方 我自己也喜歡做for轉apply的練習 === 分隔線 === 以下的寫法只是隨便寫的(甚至可以說骨子裡還是for的邏輯...) 請其他版友分享更好的寫法!! 1. cross validation: 1.a 還是用到folds sapply(1:5,function(i){ testIndexes <- which(folds==i,arr.ind=T) # 做你想做的事情 # ex: 找測試集的最大值跟訓練集的最小值 max_intest <- max(dataset[testIndexes,]) min_intrain <- min(dataset[-testIndexes,]) #回傳結果 c(max_intest,min_intrain) }) 其實這個跟for的寫法根本換湯不換藥XD 1.b 使用split (不要用cut跟folds) 原po原本的方法是先用sample()抽樣打亂原始data的順序後再用cut()指定組別 提供sapply + split的做法: sapply(split(dataset,1:5),function(x){ test <- x # test dataset train <- dataset[-as.numeric(row.names(x)),] # train dataset # 做你想做的 c(max(test),max(train)) }) 這個做法直接把dataset分成5份然後將該dataframe傳進sapply裡 不過須注意這作法取樣的順序跟cut不一樣 cut是111..222...333...444..555(各20次) split是12345...12345...12345...(共20次) 不過因為一開始已經用sample打亂過順序了,所以個人覺得後面cut或split應該沒差 (有錯請指正>"<) 2. 偷偷問的小問題 x <- c(2:3) y <- c(4:8) sapply(x,function(i){ i*y }) 其實我後來很常用 sapply(x,function(){ .... }) 這樣的形式寫,因為可以省略掉for裡面預先指定次數(i)的模式,寫起來也更有彈性 不過要注意function()裡面不要太多變數,不然效率應該會很差 (但是如何要評估效率我就不會惹...XD) 許願: 希望可以釣到版上其他大大 ex: celestialgod, andrew43 兩個偶像 >///< ※ 引述《empireisme (empireisme)》之銘言: : 如題 : 最近想手刻實踐 cross validtion的算法 : 上網查了一下別人的範例code : 如下 : x <- runif(100)*10 #Random values between 0 and 10 : y <- x+rnorm(100)*.1 #y~x+error : dataset <- data.frame(x,y) #Create data frame : dataset<- dataset[sample(nrow(dataset)),] : dataset : #here is the trick : folds <- cut(seq(1,nrow(dataset)),breaks=5,labels=FALSE) : folds : sample(nrow(dataset)) : for(i in 1:5){ : #Segement your data by fold using the which() function : #這裡就是我想問的 : testIndexes <- which(folds==i,arr.ind=TRUE) : #這裡就是我想問的 : testData <- dataset[testIndexes, ] : trainData <- dataset[-testIndexes, ] : #Use the test and train data partitions however you desire... : #必須要在這個步驟去套入model 然後計算MSE : } : 他在切traing 和Testing時 使用了 fold的技巧 : 但是這整段有沒有可能 不使用for 迴圈 而改用apply家族去實現 : 因為真的太喜歡使用apply的簡潔了 : 還希望版友回答 : 偷偷問另外一個問題 : 我有一個function s 去計算 x*y : s<- function(x,y){ x*y } : s( c(2,3) , c(4,5) ) : 這裡我會得到 8 15 : 但其實我想得到的是所有的可能性 : 8,10,12,15 : 請問我要如何在保有 input是 c(2,3) , c(4,5) 下 得到我要的結果呢 : 更甚至在 s ( c(2,3),c(4,5,6,7,8) ) 狀況下也可以得到遍歷的結果 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 36.224.210.149 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/R_Language/M.1585093941.A.3E6.html
locka: 之前的討論可以參考這篇 #1ScvIY4l 03/25 08:07
andrew43: 用apply系列在分支後的運算若有例外發生比for會小麻煩 03/25 10:23
andrew43: 一點,也比使用for難抓蟲。之前做10-fold CV的小經驗。 03/25 10:25
obarisk: 可以看一下 purrr ,有例外處理的方法。不過,沒有很推 03/25 11:31
empireisme: 太神拉 03/25 13:25
VIATOR: 謝謝分享,不過這個情況實在看不出來apply有比loop好 @@ 03/26 08:53
VIATOR: apply的優點在於比較簡潔,但CV用apply根本沒比較簡潔 03/26 08:57
locka: 從來沒有人說apply比較好啊XD 而且也要端看好的定義是什麼 03/26 09:38
locka: ,例如說第一種方法其實跟loop一樣,而第二種方法不需要預 03/26 09:38
locka: 先設定loop幾次,我覺得這點就很有用啦~不過我同意CV用appl 03/26 09:38
locka: y寫沒有比較簡潔,挑習慣用的就好~ 03/26 09:38
VIATOR: 我只是在討論,如果有冒犯到請多多包涵 03/26 13:36
locka: V大客氣了~沒事沒事!請多討論XD 03/26 13:41
> -------------------------------------------------------------------------- < 作者: celestialgod (天) 看板: R_Language 標題: Re: [問題]不使用for改使用apply寫法的可能性 時間: Thu Mar 26 09:31:12 2020 ※ 引述《locka (locka)》之銘言: : (同是apply家族愛好者先shout out一下XD) : 以前看過版主C大跟其他前輩版友的討論,結論是 apply 效率並沒有比較好 : (印象中好像背後都還是用for迴圈?!) : 不過我覺得向量化(vectorized)是R語言裡面很重要的一個特性 : 也是functional programming跟其他程式語言不一樣的地方 : 我自己也喜歡做for轉apply的練習 : === 分隔線 === : 以下的寫法只是隨便寫的(甚至可以說骨子裡還是for的邏輯...) : 請其他版友分享更好的寫法!! : 1. cross validation: : 1.a 還是用到folds : sapply(1:5,function(i){ : testIndexes <- which(folds==i,arr.ind=T) : # 做你想做的事情 : # ex: 找測試集的最大值跟訓練集的最小值 : max_intest <- max(dataset[testIndexes,]) : min_intrain <- min(dataset[-testIndexes,]) : #回傳結果 : c(max_intest,min_intrain) : }) : 其實這個跟for的寫法根本換湯不換藥XD : 1.b 使用split (不要用cut跟folds) : 原po原本的方法是先用sample()抽樣打亂原始data的順序後再用cut()指定組別 : 提供sapply + split的做法: : sapply(split(dataset,1:5),function(x){ : test <- x # test dataset : train <- dataset[-as.numeric(row.names(x)),] # train dataset : # 做你想做的 : c(max(test),max(train)) : }) : 這個做法直接把dataset分成5份然後將該dataframe傳進sapply裡 : 不過須注意這作法取樣的順序跟cut不一樣 : cut是111..222...333...444..555(各20次) : split是12345...12345...12345...(共20次) : 不過因為一開始已經用sample打亂過順序了,所以個人覺得後面cut或split應該沒差 : (有錯請指正>"<) library(pipeR) library(data.table) N <- 100000L x <- runif(N) * 10 y <- x+rnorm(N) * 0.1 num_folds <- 10L split_idx <- seq_len(N) %>>% cut(breaks=num_folds, labels = FALSE) %>>% sample dataset <- data.table(x, y, split_idx, key = "split_idx") library(microbenchmark) microbenchmark(apply_func = { models <- seq_len(num_folds)%>>% lapply( function(i){ lm(y ~ x, dataset[split_idx != i]) }) mse_folds <- seq_len(num_folds) %>>% sapply(function(i){ mean((predict(models[[i]], dataset[split_idx == i]) - dataset[split_idx == i]$y)^2) }) }, for_loop = { models <- vector("list", num_folds) mse_folds <- vector("numeric", num_folds) for (i in seq_len(num_folds)) { models[[i]] <- lm(y ~ x, dataset[split_idx != i]) mse_folds[i] <- mean((predict(models[[i]], dataset[split_idx == i]) - dataset[split_idx == i]$y)^2) } }, times = 20L ) # Unit: milliseconds # expr min lq mean median uq max neval # apply_func 192.4187 199.8315 236.0988 209.2901 284.0653 365.0350 20 # for_loop 198.8673 206.2947 230.8822 210.7969 260.0005 301.9913 20 基本上沒差多少,開心用什麼就用什麼,重點還是forloop前的變數要allocate apply寫法有很多種,有人是不存model,那就不用拆兩段 有人直接一次return list(model, mse),這樣也不用拆兩段 我是覺得apply或是for-loop看coder開心就好XD 請參考 https://www.ptt.cc/man/R_Language/D5C7/M.1437921117.A.AC4.html : 2. 偷偷問的小問題 : x <- c(2:3) : y <- c(4:8) : sapply(x,function(i){ : i*y : }) : 其實我後來很常用 : sapply(x,function(){ : .... : }) 可以用microbenchmark去看效能,我猜其實沒差 這個例子outer最快 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.163.170.73 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/R_Language/M.1585186274.A.9D9.html ※ 編輯: celestialgod (118.163.170.73 臺灣), 03/26/2020 09:34:53
locka: 謝謝大大!沒想到還真的被釣出來了(欸 03/26 13:36
locka: 可能我的使用情境來說都還不到效能瓶頸,所以以前不太需要 03/26 13:36
locka: 注意效能問題,但還是很感謝C大分享! 03/26 13:36
> -------------------------------------------------------------------------- < 作者: empireisme (empireisme) 看板: R_Language 標題: Re: [問題]不使用for改使用apply寫法的可能性 時間: Thu Mar 26 11:28:27 2020 require(magrittr) data(iris) set.seed(1) data <- iris[sample(nrow(iris)) ,] # 打散資料 Xtrain <- data[1:100,1:4] Xtest <- data[101:150,1:4] M <- nrow(Xtrain) N <- nrow(Xtest) distmatrix <- matrix(0,nrow = M,ncol = N) for(i in 1:M){ for(j in 1:N){ distmatrix[i,j]<- sum((Xtrain[i,]-Xtest[j,])^2) %>% sqrt() } } 最近在implement knn 的 distancematrix 想在厚臉皮的問問看 這種常見的操作要怎麼 轉成非迴圈寫法 我用迴圈寫塞的好慢喔 我自己只想到這樣 就卡住了 (matrix(rep(Xtest[1,],nrow(Xtrain)),ncol=ncol(Xtrain),byrow = T)-Xtrain)^2 %>% apply(X=. ,1,sum)%>%sqrt -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 219.91.75.186 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/R_Language/M.1585193311.A.644.html
locka: 避免把 apply 搭配 %>% pipeline 運算子 因為他會把前半部 03/26 11:38
locka: 的向量結果做完才會一個一個丟pipeline 這樣一定超慢(有錯 03/26 11:38
locka: 請指正) 03/26 11:38
VIATOR: expand.grid和apply一起用可以取代nested loop 03/26 13:28
params <- expand.grid(M=seq(M), N=seq(N)) distmatrix2 <- matrix(mapply(function(i,j) sqrt(sum((Xtrain[i,]-Xtest[j,])^2)), params$M, params$N), nrow = M, ncol = N) 有點看不懂 mapply這段 有人可以解釋一下他是怎麼運作的嗎 # EQUIVALENT TO OP's distance identical(distmatrix, distmatrix2) 老外的解法 ※ 編輯: empireisme (219.91.75.186 臺灣), 03/26/2020 14:34:27 ※ 編輯: empireisme (219.91.75.186 臺灣), 03/26/2020 14:46:28 ※ 編輯: empireisme (219.91.75.186 臺灣), 03/26/2020 14:58:34
andrew43: function(i,j)裡的i和j就是params$M和params$N 03/26 23:10
andrew43: 每做一次function都是拿M和N各一個元素 03/26 23:13
andrew43: 就此例而言,distmatrix[i, j] <- 改成 03/27 10:01
andrew43: rbind(Xtrain[i, ], Xtest[j, ]) %>% dist 會快不少。 03/27 10:01
andrew43: 或是只有一次dist硬幹 https://i.imgur.com/feLrQO1.jpg 03/27 10:28
andrew43: 小改正 https://i.imgur.com/YkTAJF4.jpg 03/27 10:31
empireisme: 謝a大,但是用dist函數不就代表不能自己定義距離的意 03/27 18:40
empireisme: 思? 03/27 18:40
andrew43: 對,但有不少距離定義在R中是由C寫成的。你看看?dist 03/27 18:43
andrew43: 中的method有沒有你想用的,其它package也有提供 03/27 18:43
andrew43: 例如生態學家常用的vegan::vegdist() 03/27 18:44
Gjerry: 我想你的寫法會比較慢可能不是用 apply 就能解決。一個一 03/28 03:02
Gjerry: 個算值然後填入矩陣,在R裡面比較沒有效率。可以考慮用矩 03/28 03:02
Gjerry: 陣運算,一次計算完整個 row 再填入矩陣,會會很多。 03/28 03:02
empireisme: 矩陣運算我就是有點卡住 03/28 19:30
andrew43: 針對矩陣運算,例如,不要一列對一列算,而是改成一矩 03/28 20:56
andrew43: 陣對一矩陣算。技巧是你需要額外先造出一堆以列重複的 03/28 20:56
andrew43: 矩陣使得二個矩陣大小相等而可以直接相減,於是迴圈只 03/28 20:56
andrew43: 剩一層。效果如何待測試。若有興趣歡迎繼續發文討論。 03/28 20:56
empireisme: 其實我有做到那邊,在本文的最後一段 03/29 00:42
empireisme: 但是那時候想說還是有一層迴圈就沒繼續做了 03/29 00:42
andrew43: 一樣的,你可以創造出兩個非常多重複列但重複方式不同 03/29 01:22
andrew43: 的大矩陣以達成所以的對應情況,於是完全不用迴圈了。 03/29 01:22
andrew43: 技巧上可用rep產生不同的重複列號索引來生成二個大矩陣 03/29 01:27
andrew43: 。 03/29 01:27
empireisme: ok 03/30 13:57
Gjerry: 也許可以這樣寫,在我電腦上其實用 for 的function比較快 03/30 14:55
Gjerry: https://imgur.com/5UZT7m3.jpg 03/30 14:55
andrew43: 抱歉前一大段手邊沒電腦,現在補上 03/30 16:51
andrew43: https://ideone.com/zlHh25 03/30 16:51
empireisme: 大神們感恩! 03/30 20:53