LoginSignup
0
1

More than 5 years have passed since last update.

mapplyで二重ループを回避してみた

Posted at

Rのapply系の中でも異彩を放っているmapplyの使い方の例を書いてみました。以下の図のような、
1. 50m×50mの中に2000個の点が散らばっている。
2. それぞれの点について、半径5m以内にいる他の点の数を数える。
という例で考えてみます。

data.png

データの準備
library(dplyr)
set.seed(4)
n <- 2000
gx <- runif(n, min=0, max=50)
gy <- runif(n, min=0, max=50)
samp_dat <- data_frame(ID = paste("ID", 1:n, sep = "_"), gx, gy) 

このデータから下のような結果がほしい。

ID 周りの数
ID_1 65
ID_2 37
ID_3 43
... ...
ID_2000 79

普通にループを使う

  • ループ1:対象の点と回りの点の距離を比べる。
  • ループ2:ループ1を全部の点に行う。
ループのみ
countR <- function(gx, gy, r){
 n_length <- length(gx)
 res <- numeric(n_length)
 for (i in 1:n_length){
  temp <- numeric(n_length)
   for (j in 1:n_length){
        if ((gx[i]-gx[j])^2 + (gy[i]-gy[j])^2 <= r^2) temp[j] <- 1
      }
      res[i] <- sum(temp)
      temp <- numeric(n_length)
    }
  res - 1
}

> system.time(res <- countR(samp_dat$gx, samp_dat$gy, r = 5))
   user  system elapsed
  6.989   0.027   7.015
> str(res)
 num [1:2000] 65 37 43 65 57 59 58 52 52 65 ...

mapplyを使う

  • 1つ目のループをベクトル化。
  • 2つ目のループにmapplyを使う。
mapply
r <- 5
countR2 <- function(n){
    temp <- (gx[n] - gx)^2 + (gy[n] - gy)^2 # gx[n]-gxでベクトル化
    temp[temp <= r^2] %>% length - 1
}

> system.time(res2 <- mapply(countR2, n = 1:n))
   user  system elapsed
  0.170   0.012   0.181

> str(res2)
 num [1:2000] 65 37 43 65 57 59 58 52 52 65 ...

短く書けたし、40倍くらい速くなりました。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1