Rに関する質問です。
実行したい内容は"Weightという名称の列について、①Monthが上の行と等しく、かつ、②NAの場合に上の行と同じ数値にする"というものです。
データの列や行がさらに膨大となった場合に、かなり時間がかかってしまい困っております。
これを高速化する方法はあるでしょうか。
month_list <- c(1,2,3,4,5,1,1,1,4,5)
weight <- c(51,55,72,57,64,NA,72,NA,57,64)
Data <- data.frame(Month=month_list, Weight=weight)
for(i in 2:ncol(Data)){
for(j in 2:nrow(Data)){
if ((Data[j,"Month"] == Data[j-1,"Month"]) && (is.na(Data[j,i]))) {
Data[j,i] <- Data[j-1,i]
}
}
}
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
R
1for(j in 2:nrow(Data)){ 2 if (Data[j,"Month"] == Data[j-1,"Month"]){ 3 for(i in 2:ncol(Data)){ 4 if(is.na(Data[j,i])) { 5 Data[j,i] <- Data[j-1,i] 6 } 7 } 8 } 9}
とか
投稿2021/04/15 18:19
総合スコア282
0
ベストアンサー
4/15 23:10追記。以下は、要件を満たしていませんでした。何かの参考にはなるかもしれませんのでこのまま晒しておきます。
こういうときは中間データを格納する一時的な列を利用するとわかりやすく、ベリファイやデバッグが楽です。流れがわかりやすいと無駄を省いて高速化するのも容易になります。
というわけで、中間データを利用することによってforを使わないで処理するバージョンを試作してみました。これらを関数とし、プロファイラで実行時間をチェックします。
R
1month_list <- c(1,2,3,4,5,1,1,1,4,5) 2weight <- c(51,55,72,57,64,NA,72,NA,57,64) 3 4# データを重複させて大きなデータセットを作る 5repcnt <- 1000 6month_list <- rep(month_list, repcnt) 7weight <- rep(weight, repcnt) 8 9# テスト用データ最終型 10d0 <- data.frame(m=month_list, w=weight) 11 12# オリジナルの処理を関数化 13f1 <- function(d){ 14 for(i in 2:ncol(d)){ 15 for(j in 2:nrow(d)){ 16 if ((d[j,"m"] == d[j-1,"m"]) && (is.na(d[j,i]))) { 17 d[j,i] <- d[j-1,i] 18 } 19 } 20 } 21 return(d) 22} 23 24# 同じことをforを使わずにやってみる 25f2 <- function(d){ 26# 作業用に一時的に列を追加 27 d$m2 <- c(NA, month_list[1:length(month_list)-1]) 28 d$w2 <- c(NA, weight[1:length(month_list)-1]) 29 30# 一気にデータ書き換え 31 d[d$m==d$m2 & is.na(d$w), "w"] <- d[d$m==d$m2 & is.na(d$w), "w2"] 32 33# 作業用の列を削除 34 d$m2 <- NULL 35 d$w2 <- NULL 36 37 return(d) 38} 39 40# プロファイラを使い、関数単位で実行時間の計測と比較を実行 41Rprof(tmp<-tempfile(), interval=0.01) 42d1 <- f1(d0) 43d2 <- f2(d0) 44Rprof(NULL) 45summaryRprof(tmp) 46 47
結果をざっと見ると以下のとおりで、私の環境では所要時間が0.43秒→0.01秒に改善されました。
テストスクリプトのrepcnt
を色々変えてみると、オリジナル版ではデータが大きくなればなるほど所要時間が増えるのに対し、改良版ではほとんど左右されないことがわかります。
$ R -q --vanilla < test.r | egrep '"f[12]"|total.time' self.time self.pct total.time total.pct "f1" 0.01 2.27 0.43 97.73 total.time total.pct self.time self.pct "f1" 0.43 97.73 0.01 2.27 "f2" 0.01 2.27 0.00 0.00
投稿2021/04/15 10:44
編集2021/04/15 14:12総合スコア13692
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/04/15 14:10
2021/04/15 14:21
2021/04/17 13:27
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。