Избегание цикла for при использовании apply в каждой строке кадра данных - PullRequest
0 голосов
/ 08 мая 2018

Я пишу сценарий, который определяет интервал между векторами чисел.например, 0,3 попадает в первый интервал 0,5, 0,8, 1. Упрощенный пример кода ниже:

df <- data.frame(p1 = runif(10)/2, p2 = rep(-1,10), p3 = rep(1, 10));
df$p2 <- df$p1 + runif(10)/2;
r <- runif(10);

c(1,2,3)[apply(abs(outer(as.numeric(df[1,]), r, '-')),2, which.min)];

Это хорошо работает, когда каждое значение в r применяется к одному и тому же вектору - в этом случае как.numeric (DF [1,]).Однако теперь мне нужно применить каждое значение в r к соответствующей уникальной строке в наборе данных df.В данный момент я делаю это в цикле, который кажется неэффективным, но я не смог найти эффективную альтернативу циклической обработке каждой строки:

a <- array(dim=10);
for(x in 1:10){
    a[x] <- c(1,2,3)[apply(abs(outer(as.numeric(df[x,]), r[x], '-')),2, which.min)];
}

Существует ли более эффективная альтернатива, чем цикл?

Спасибо, Джеймс

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

Спасибо за предложения. Я использовал dplyr и придумал следующее. Кажется, это быстрее, чем мой оригинал, но все еще страдает, когда размер набора данных увеличивается:

 library(dplyr);

 # Dummy data-set
 nRows <- 1000
 df <- data.frame(p1 = runif(nRows )/2, p2 = rep(-1,nRows ), p3 = rep(1, nRows ), r = runif(nRows))
 df$p2 <- df$p1 + runif(nRows )/2

df %>% dplyr::rowwise() %>%
       dplyr::mutate_at(vars(starts_with("r")), funs(bin = 1+findInterval(., c(p1,p2,p3))))

- Джеймс

0 голосов
/ 08 мая 2018

Как упоминал @Gregor, лучше использовать findInterval. Вы можете использовать mutate_xxx функции из пакета dplyr, чтобы применить findInterval ко всем столбцам

library(tidyverse)

set.seed(1111)
df <- data.frame(p1 = runif(10)/2, p2 = rep(-1,10), p3 = rep(1, 10));
df$p2 <- df$p1 + runif(10)/2;

# define intervals
intv1 <- c(0.3, 0.5, 0.8, 1) 

# columns start with `p`
df %>% 
  mutate_at(vars(starts_with("p")), funs(bin = findInterval(., intv1)))
#>            p1        p2 p3 p1_bin p2_bin p3_bin
#> 1  0.23275132 0.2335964  1      0      0      4
#> 2  0.20646243 0.5809412  1      0      2      4
#> 3  0.45350161 0.8289807  1      1      3      4
#> 4  0.06855271 0.3852559  1      0      1      4
#> 5  0.36940842 0.8034923  1      1      3      4
#> 6  0.48816350 0.5678450  1      1      2      4
#> 7  0.43997997 0.8983940  1      1      3      4
#> 8  0.05839214 0.3368955  1      0      1      4
#> 9  0.27314439 0.7233537  1      0      2      4
#> 10 0.07005799 0.4530015  1      0      1      4

# selected columns only
col2select <- c("p1", "p2")
df %>% 
  mutate_at(col2select, funs(bin = findInterval(., intv1)))
#>            p1        p2 p3 p1_bin p2_bin
#> 1  0.23275132 0.2335964  1      0      0
#> 2  0.20646243 0.5809412  1      0      2
#> 3  0.45350161 0.8289807  1      1      3
#> 4  0.06855271 0.3852559  1      0      1
#> 5  0.36940842 0.8034923  1      1      3
#> 6  0.48816350 0.5678450  1      1      2
#> 7  0.43997997 0.8983940  1      1      3
#> 8  0.05839214 0.3368955  1      0      1
#> 9  0.27314439 0.7233537  1      0      2
#> 10 0.07005799 0.4530015  1      0      1

# for all columns
df %>% 
  mutate_all(funs(bin = findInterval(., intv1)))
#>            p1        p2 p3 p1_bin p2_bin p3_bin
#> 1  0.23275132 0.2335964  1      0      0      4
#> 2  0.20646243 0.5809412  1      0      2      4
#> 3  0.45350161 0.8289807  1      1      3      4
#> 4  0.06855271 0.3852559  1      0      1      4
#> 5  0.36940842 0.8034923  1      1      3      4
#> 6  0.48816350 0.5678450  1      1      2      4
#> 7  0.43997997 0.8983940  1      1      3      4
#> 8  0.05839214 0.3368955  1      0      1      4
#> 9  0.27314439 0.7233537  1      0      2      4
#> 10 0.07005799 0.4530015  1      0      1      4

Создано в 2018-05-08 пакетом Представить (v0.2.0).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...