【问题标题】:R generate sequence for each pair in a vectorR为向量中的每一对生成序列
【发布时间】:2020-10-11 19:06:58
【问题描述】:

我有一个长度可能为 N 的向量。例如

  x <- c(298, 307, 347, 374, 416)

我想为每对向量生成数字序列,如下所示:

  298:307
  308:347
  348:374
  375:416

并将其放入数据框中:

  temp_df <- data.frame(i = c(298:307, 308:347, 348:374, 375:416),
                    j = c(rep(1, length(298:307)), rep(2, length(308:347)), 
                          rep(3, length(348:374)), rep(4, length(375:416))))

我需要编写一个函数,它可以采用任意长度的向量并生成temp_df

  temp_func <- function(my.vec){

     temp.length <- length(my.vec) - 1
     temp_list <- list()

    for(j in 1:temp.length){
    
       jk <- j + 1
      
       if(j == 1){
      
         temp_list[[j]] <- 
          data.frame(i = my.vec[j]:my.vec[jk],                        
                     j = j)
      
        } else {
          temp_list[[j]] <- data.frame(i = (my.vec[j] + 1):my.vec[jk],                        
                                      j = j)
       }
    }

   test <- do.call('rbind', temp_list)

  return(test)
}

  temp_func(x)

在 R 中是否有更快的方法来执行此操作?

【问题讨论】:

    标签: r apply


    【解决方案1】:

    一个选项是Map 来创建两个向量的对应元素序列,这两个向量是通过删除“x”的第一个和最后一个元素创建的,然后通过unlisting 向量的list 创建data.frame 和基于listlengthslistreplicated 序列

    x1 <- x[-length(x)]
    x1[-1] <- x1[-1] + 1
    lst1 <-  Map(`:`, x1, x[-1])
    temp_df2 <- data.frame(i = unlist(lst1), j = rep(seq_along(lst1), lengths(lst1)))
    all.equal(temp_df2, temp_df)
    #[1] TRUE
    

    可以封装成函数

    f1 <- function(vec){
           vec1 <- vec[-length(vec)]
           vec1[-1] <- vec1[-1] + 1
           lst1 <- Map(`:`, vec1, vec[-1])
           data.frame(i = unlist(lst1), j = rep(seq_along(lst1), lengths(lst1)))
         }
    
    f1(x)
    

    stack

    stack(setNames(lst1, seq_along(lst1)))[2:1]
    

    或作为单线

    stack(setNames(Map(`:`, (x + rep(0:1, c(1, length(x)-1)))[-length(x)], 
                x[-1]), seq_along(x[-1])))
    

    或者tidyverse

    library(dplyr)
    library(tidyr)
    library(purrr)
    tibble(x, x1 = lead(x) + 1) %>%
          na.omit %>% 
          transmute(j = row_number(),
                    i = map2(x, x1, `:`)) %>% 
          unnest(c(i))
    

    【讨论】:

      【解决方案2】:

      这是另一种基本的 R 解决方案:

      x <- c(298, 307, 347, 374, 416)
      
      splitInts <- function(x){
          x1 <- seq(x[1], x[length(x)])
          unname(split(x1, findInterval(x1, x[-1] + 1)))
      }
      
      splitInts(x)
      #> [[1]]
      #>  [1] 298 299 300 301 302 303 304 305 306 307
      #> 
      #> [[2]]
      #>  [1] 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
      #> [20] 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
      #> [39] 346 347
      #> 
      #> [[3]]
      #>  [1] 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
      #> [20] 367 368 369 370 371 372 373 374
      #> 
      #> [[4]]
      #>  [1] 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
      #> [20] 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
      #> [39] 413 414 415 416
      

      reprex package (v0.3.0) 于 2020-06-21 创建

      【讨论】:

        【解决方案3】:

        在这种情况下,您根本不需要任何循环。

        您可以在x 中的最小值和最大值之间创建一个序列,并获得j 列,您可以使用cutfindInterval

        vec <- seq(min(x), max(x))
        data.frame(i =vec, j = cut(vec, x, labels = FALSE, include.lowest = TRUE))
        
        #      i j
        #1   298 1
        #2   299 1
        #3   300 1
        #4   301 1
        #5   302 1
        #6   303 1
        #7   304 1
        #8   305 1
        #9   306 1
        #10  307 1
        #11  308 2
        #12  309 2
        #....
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-08-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-09-11
          • 1970-01-01
          相关资源
          最近更新 更多