質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
R

R言語は、「S言語」をオープンソースとして実装なおした、統計解析向けのプログラミング言語です。 計算がとても速くグラフィックも充実しているため、数値計算に向いています。 文法的には、統計解析部分はS言語を参考にしており、データ処理部分はSchemeの影響を受けています。 世界中の専門家が開発に関わり、日々新しい手法やアルゴリズムが追加されています。

Q&A

解決済

2回答

1200閲覧

Rのfor文の高速化

kakii

総合スコア6

R

R言語は、「S言語」をオープンソースとして実装なおした、統計解析向けのプログラミング言語です。 計算がとても速くグラフィックも充実しているため、数値計算に向いています。 文法的には、統計解析部分はS言語を参考にしており、データ処理部分はSchemeの影響を受けています。 世界中の専門家が開発に関わり、日々新しい手法やアルゴリズムが追加されています。

0グッド

0クリップ

投稿2021/04/15 06:26

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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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

modieu

総合スコア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
KojiDoi

総合スコア13692

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kakii

2021/04/15 12:26

早速のご回答をありがとうございます。 私の例が悪く申し訳ないのですが下記のような場合ですと、d1とd2の結果が異なってくると思います。d1のような結果にしたいと思っておりますが、可能でしょうか? month_list <- c(1,2,3,4,5,1,1,1,1,5) weight <- c(51,55,72,57,64,NA,72,NA,NA,64)
KojiDoi

2021/04/15 14:10

すみません、NAが連続する場合のことは完全に抜けていました。確かにforループを回して上の行から値を補完していく必要があります。forをapply系に書き換えるなどの方法はあるかもしれませんが、劇的に改善するというわけにはいかないかもしれません。 ちょっと使い物にならない回答でしたね。申し訳ありません。
KojiDoi

2021/04/15 14:21

もしかすると、library(zoo)のna.locf()が使えるかもしれません。 [欠損値の処理](https://www.cyberer.net/2020/03/r-package-zoo.html#toc_headline_12) > ティックデータの場合は NA の箇所は値が変化していないことを意味しています。したがって、直近の値で補間するのが妥当です。このような場合は na.locf() を用います。locf は last observation carried forward のことで、最後の観測値を前へ持ち越す、という意味です。
kakii

2021/04/17 13:27

na.locfも含めていろいろと考えましたが、 私が実際に使用するデータではNAが連続して生じる回数が10回程度であったため、 2021/04/15 19:44に当初いただいたプログラムを何回か繰り返す方法にすることといたしました。 これによって、連続したNAが徐々に少なくなっていくイメージです。 (1回で連続するNAをすべて補完することがベストではあったのですが、思いつかなかったため) ご協力を大変ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問