【问题标题】:How to make this code more efficient in R?如何使这段代码在 R 中更高效?
【发布时间】:2018-08-31 00:18:16
【问题描述】:

我知道这是一个愚蠢的问题,但我对我的代码有点失望,因为它需要很多时间。 Jere 是我的代码的一部分。 基本上我有一个叫做“距离”的矩阵......

   a  b  c  
1  2  5  7
2  6  8  4
3  9  2  3

然后假设我在数据框中有一列,包含 {a,b,c}

c1  c2  c3
c  ...  ...
a
a  just another column
b
c ... ...

所以我想做一个匹配,我想用 ncol=nrow(distance) 和 nrow=nrow(c1) 制作另一个矩阵。其中用它们的距离值替换因子值。这是我要制作的矩阵第一列的示例

a will replaced by 2 
b will replaced by 5
c will replaced by 7

对于第二列,我将从距离矩阵中取出第 2 行,依此类推......所以结果将是这样的

m1  m2  m3
7   4   3
2   6   9
2   6   9
5   8   2
7   4   3

这只是一个简单的例子,我正在运行这段代码,但是当它处理大量迭代时,对我来说有点压力。

for(l in 1:ncol(d.cat)){
  get.unique = sort(unique(d.cat[, l]))
  for(j in 1:nrow(d.cat)){
    value = as.character(d.cat[j, l])
    index = which(get.unique == value)
    d2[j,l] = (d[[l]][i, index])
  }
}

d.cat 是分类数据。 d[[...]] 是 d.cat 中每一列的矩阵距离列表。

【问题讨论】:

  • 我删除了[rcpp]标签,因为这与Rcpp无关。

标签: r performance dataframe matrix


【解决方案1】:

尝试存储索引并一次性进行更新。假设您的距离矩阵是 dmat 并且数据框是 df 并且您想创建一个名为 newmat 的矩阵

a.ind = which(df$c1=="a")
b.ind = which(df$c1=="b")
c.ind = which(df$c1=="c")
newmat = matrix(0,nrow=length(df$c1),ncol=3)
newmat[a.ind,] = dmat[,1]
newmat[b.ind,] = dmat[,2]
newmat[c.ind,] = dmat[,3]

【讨论】:

    【解决方案2】:

    您的数据

    mat <- matrix(c(2,6,9,5,8,2,7,4,3), nrow=3)
    rownames(mat) <- 1:3
    colnames(mat) <- letters[1:3]
    
    library(dplyr)
    set.seed(1)
    df <- as.data.frame(matrix(sample(letters[1:3], 12, replace=TRUE), nrow=4)) %>%
            setNames(paste0("c", 1:3))
    
      # c1 c2 c3
    # 1  a  a  b
    # 2  b  c  a
    # 3  b  c  a
    # 4  c  b  a
    

    使用purrr::map2_df,遍历df的列和tmat的列

    library(purrr)
    tmat <- t(mat)
    map2_df(df, seq_len(ncol(tmat)), ~tmat[,.y][.x])
    
    # # A tibble: 4 x 3
         # c1    c2    c3
      # <dbl> <dbl> <dbl>
    # 1    2.    6.    2.
    # 2    5.    4.    9.
    # 3    5.    4.    9.
    # 4    7.    8.    9.
    

    【讨论】:

      【解决方案3】:

      这是我使用 tidyverse 的尝试:

      library(tidyverse)
      
      # Lets create some example
      distance <- data_frame(a = sample(1:10, 1000, T), b = sample(1:10, 1000, T), c = sample(1:10, 1000, T))
      c1 <- data_frame(c1 = sample(letters[1:3], 1000, T), c2 = sample(letters[1:3], 1000, T))
      
      # First rearrange a little bit your data to make it more tidy
      distance2 <- distance %>% 
        mutate(i = seq_len(n())) %>% 
        gather(col, value, -i)
      c2 <- c1 %>% 
        mutate(i = seq_len(n()) %>%
        gather(col, value, -i)
      
      # Now just join the data and spread it again
      c12 %>% 
        left_join(distance2, by = c("i", "value" = "col")) %>% 
        select(i, col, value.y) %>% 
        spread(col, value.y)
      

      【讨论】:

        【解决方案4】:

        这是一些数据

        set.seed(123)
        d = matrix(1:9, 3, dimnames=list(NULL, letters[1:3]))
        df = data.frame(c1 = sample(letters[1:3], 10, TRUE), stringsAsFactors=FALSE)
        

        和解决方案

        t(d[, match(df$c1, colnames(d))])
        

        例如

        > d
             a b c
        [1,] 1 4 7
        [2,] 2 5 8
        [3,] 3 6 9
        > df$c1
         [1] "a" "c" "b" "c" "c" "a" "b" "c" "b" "b"
        > t(d[,match(df$c1, colnames(d))])
          [,1] [,2] [,3]
        a    1    2    3
        c    7    8    9
        b    4    5    6
        c    7    8    9
        c    7    8    9
        a    1    2    3
        b    4    5    6
        c    7    8    9
        b    4    5    6
        b    4    5    6
        

        【讨论】:

        • 用你的方式让我的代码在之前的 1.7 分钟内运行,现在只需 9 秒......非常感谢你
        猜你喜欢
        • 1970-01-01
        • 2019-07-28
        • 2015-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多