【问题标题】:Selecting observations within a data frame and reversing their order在数据框中选择观察并颠倒它们的顺序
【发布时间】:2020-05-19 19:38:17
【问题描述】:

我有一个巨大的数据框,其中包含对数百个人的多个变量的许多时间相关观察。每个人在ID 列中都有一个唯一编号。我将使用下面模拟的数据,其结构类似于我的数据来提出我的问题:

set.seed(123)
dat <- data.frame(ID = rep(letters[1:10], each = 10),
                  time = rep(c(1:10), times = 10),
                  var1 = rnorm(100))

请注意,在真实数据中,每个ID 的实际观察次数是不同的。 假设有几个人(例如,IDs:b、e 和 g)我需要对其进行观察并完全“翻转”或“颠倒”顺序,并且仍然保留每个人的数据time。我的意思是(以个人 b 为例)个人 b 的数据帧中的第一个观察结果将是“时间间隔”10 处的数据,而不是“时间间隔”1 处的数据。换句话说,数据看起来像这样:

ID   time   Var1
a     1
a     2
…     … 
a     10 
b     10
b     9 
b     8
…     …
b     1
c     1
c     2
c     3
c     4
ect...

执行此操作并保持其在数据框中的位置的最安全方法是什么(即,b 位于 ac 等之间)?

【问题讨论】:

  • 可以澄清您是否尝试重新排序数据行,同时保持 timeVar1 之间的关系或更改数据以使 timeVar1 关系为不一样?
  • 你好我想保留timeVar1之间的关系
  • @Ryan 我想应该保持顺序吧?

标签: r dataframe


【解决方案1】:

使用data.table:

library(data.table)
setDT(dat)
ids.to.reverse <- c('b', 'e', 'g')

dat[, if(ID %in% ids.to.reverse) .SD[.N:1] else .SD, by='ID']

【讨论】:

    【解决方案2】:

    一种选择是通过 ID 来group_split,然后根据值 'b'、'e'、'g' 中的 any 是否是 map 来循环 list %n% 'ID'

    library(dplyr)
    library(purrr)
    out <- dat %>% 
            group_split(ID) %>%
            map_dfr(~ if(any(c('b', 'e', 'g') %in% first(.x$ID)))
             .x %>%
                 arrange(desc(time)) else .x)   
    
    out %>% 
       filter(ID %in% c('a', 'b'))
    # A tibble: 20 x 3
    #   ID     time    var1
    #   <fct> <int>   <dbl>
    # 1 a         1 -0.560 
    # 2 a         2 -0.230 
    # 3 a         3  1.56  
    # 4 a         4  0.0705
    # 5 a         5  0.129 
    # 6 a         6  1.72  
    # 7 a         7  0.461 
    # 8 a         8 -1.27  
    # 9 a         9 -0.687 
    #10 a        10 -0.446 
    #11 b        10 -0.473 
    #12 b         9  0.701 
    #13 b         8 -1.97  
    #14 b         7  0.498 
    #15 b         6  1.79  
    #16 b         5 -0.556 
    #17 b         4  0.111 
    #18 b         3  0.401 
    #19 b         2  0.360 
    #20 b         1  1.22  
    

    或者我们可以以一种 hacky 的方式使用arrange,即根据 ID 'b'、'e'、'g' 将 time 更改为负数,而其余的都是正数

    out1 <- dat %>%
         arrange(ID,  time * c(1, -1)[c(1 + (ID %in% c('b', 'e', 'g')))])
    

    -检查

    all.equal(out, out1, check.attributes = FALSE)
    #[1] TRUE
    

    【讨论】:

    • 我很好奇:这很好用,但是当我将它应用到我的真实数据集时,虽然它仍然可以正常工作,但 R 认为 map_dfr() 和 @ 中有一个 unmatched bracket ( 987654334@ 行。它仍然运行并且没有给出错误,但是红色 x 留在我的 R 笔记本的一侧。您对它为什么这样做有任何想法吗?
    • @Ryan 在我的控制台中,虽然我没有遇到任何不匹配的问题
    • @Ryan 你能指定{}out &lt;- dat %&gt;% group_split(ID) %&gt;% map_dfr(~ if(any(c('b', 'e', 'g') %in% first(.x$ID))) { .x %&gt;% arrange(desc(time))} else .x)
    • RawData % dplyr::group_split(ID)%>% map_dfr(~ if(any(c("1083", "291", "384", "999", "612", "614", "175", "1032") %in% first(.x$ID))) .x %>% 排列(desc(distance)) else .x)
    • @Ryan 这似乎对我有用,因为我没有找到任何不匹配的括号
    【解决方案3】:
    library(tidyverse)
    
    dat <- tibble(ID = rep(letters[1:10], each = 10),
                      time = rep(c(1:10), times = 10),
                      var1 = rnorm(100))
    
    flip_vars <- c("b", "e", "g")
    
    dat %>% 
      # This line turns each ID into its own column
      pivot_wider(names_from = ID, values_from = var1) %>% 
      # This line reverses the order of the flip_vars
      mutate_at(
        flip_vars,
        rev
      ) %>% 
      # This puts things back in their original, tidy format
      pivot_longer(cols = a:j, names_to = "ID", values_to = "var1")
    

    【讨论】:

      【解决方案4】:

      这是一种使用splitorderrev 的基于R 的方法:

      rev.ids <- c("b", "e", "g")
      split <- split(dat, dat$ID)
      dat <- do.call(rbind,lapply(split,function(x){
        if(x[1,1] %in% rev.ids)
          x[order(rev(x$time)),] 
        else 
          x
        }))
      dat
          ID time         var1
      1    a    1 -0.560475647
      2    a    2 -0.230177489
      ...
      8    a    8 -1.265061235
      9    a    9 -0.686852852
      10   a   10 -0.445661970
      11   b   10 -0.472791408
      12   b    9  0.701355902
      ...
      18   b    3  0.400771451
      19   b    2  0.359813827
      20   b    1  1.224081797
      21   c    1 -1.067823706
      

      编辑

      我认为这种data.table 方法会更快:

      library(data.table)
      rev.ids <- c("b", "e", "g")
      setDT(dat)[,.SD[order(time,decreasing = (unlist(.BY) %in% rev.ids))],by = ID]
          ID time         var1
        1:  a    1 -0.560475647
        2:  a    2 -0.230177489
      ...
        8:  a    8 -1.265061235
        9:  a    9 -0.686852852
       10:  a   10 -0.445661970
       11:  b   10 -0.472791408
       12:  b    9  0.701355902
      ...
       19:  b    2  0.359813827
       20:  b    1  1.224081797
       21:  c    1 -1.067823706
       22:  c    2 -0.217974915
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-10
        • 1970-01-01
        • 2023-01-04
        • 1970-01-01
        • 1970-01-01
        • 2017-04-11
        • 1970-01-01
        • 2019-01-12
        相关资源
        最近更新 更多