在数据帧的每一行上使用apply时避免for循环

时间:2018-05-08 15:43:52

标签: r dataframe

我正在编写一个脚本,用于标识数字向量介于两者之间的间隔。例如0.3落在第一个间隔0.5,0.8,1中。下面代码的简化示例:

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)];
}

当r中的每个值应用于同一向量时,这很有效 - 在本例中为.numeric(df [1,])。但是,我现在需要将r中的每个值应用于数据集df中对应的唯一行。目前我正在循环中执行此操作,这似乎是无效的,但我无法找到循环遍历每一行的有效替代方法:

var temp = function (tab) {
    browser.tabs.executeScript(null, { file: "src/js/asdf.js" });
};
browser.tabs.onCreated.addListener(temp);

是否有比循环更有效的替代方案?

谢谢, 詹姆斯

2 个答案:

答案 0 :(得分:0)

正如@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

reprex package(v0.2.0)创建于2018-05-08。

答案 1 :(得分:0)

感谢您的建议。我使用过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))))

- 詹姆斯