【问题标题】:Extend numerical series in data frame扩展数据框中的数字序列
【发布时间】:2020-04-26 21:05:30
【问题描述】:

数据
我们来看一个简单的数据集(我的实际是>200,000行):

df <- data.frame(
  id = c(rep(1, 11), rep(2,6)),
  ref.pos = c(NA,NA,NA,301,302,303,800,801,NA,NA,NA, 500,501,502, NA, NA, NA),
  pos     = c(1:11, 30:35)
)

看起来像这样:

   id ref.pos pos
1   1      NA   1
2   1      NA   2
3   1      NA   3
4   1     301   4
5   1     302   5
6   1     303   6
7   1     800   7
8   1     801   8
9   1      NA   9
10  1      NA  10
11  1      NA  11
12  2     500  30
13  2     501  31
14  2     502  32
15  2      NA  33
16  2      NA  34
17  2      NA  35

我想要实现的目标
根据id,我想扩展ref.pos 中的数字以填充整列,其中ref.pos 数字在数据框中向上移动,在列中向下移动。这将产生以下数据框:

   id ref.pos pos
1   1     298   1
2   1     299   2
3   1     300   3
4   1     301   4
5   1     302   5
6   1     303   6
7   1     800   7
8   1     801   8
9   1     802   9
10  1     803  10
11  1     804  11
12  2     500  30
13  2     501  31
14  2     502  32
15  2     503  33
16  2     504  34
17  2     505  35

我尝试了什么
我希望我可以在这里提供一些代码,但是我在两天内还没有找到合适的方法,尤其是不适用于大型数据集的方法。我发现 df %&gt;% group_by(id) %&gt;% tidyr::fill(ref.pos, .direction = "downup") 很有趣,但是这对我来说是重复数字而不是上下波动。

希望我的问题很清楚,否则请在 cmets 中告诉我!

【问题讨论】:

    标签: r dataframe range numeric


    【解决方案1】:

    使用data.table的选项:

    fillends <- function(x) nafill(nafill(x, "locf"), "nocb")
    
    setDT(df)[, ref.pos2 := {
        dif <- fillends(c(diff(ref.pos), NA_integer_))
        frp <- fillends(ref.pos)
        fp <- fillends(replace(pos, is.na(ref.pos), NA_integer_))
        fifelse(is.na(ref.pos), frp + dif*(pos - fp), ref.pos)
    }, id]
    

    输出:

        id ref.pos pos ref.pos2
     1:  1      NA   1      298
     2:  1      NA   2      299
     3:  1      NA   3      300
     4:  1     301   4      301
     5:  1     302   5      302
     6:  1     303   6      303
     7:  1     802   7      802
     8:  1     801   8      801
     9:  1      NA   9      800
    10:  1      NA  10      799
    11:  1      NA  11      798
    12:  2     500  30      500
    13:  2     501  31      501
    14:  2     502  32      502
    15:  2      NA  33      503
    16:  2      NA  34      504
    17:  2      NA  35      505
    

    数据:

    df <- data.frame(
        id = c(rep(1, 11), rep(2,6)),
        ref.pos = c(NA,NA,NA,301,302,303,802,801,NA,NA,NA, 500,501,502, NA, NA, NA),
        pos     = c(1:11, 30:35)
    )
    

    【讨论】:

    • 谢谢您的回答!我只是在进行编辑...请参阅我对@ThomasIsCoding 的评论,但也许这太多了。非常感谢您的帮助,已经花了两天时间...
    • @CodeNoob,你能在你的数据集中添加一个例子吗?我还根据我对您评论的解释编辑了我的帖子
    • 哇太棒了,我感激不尽!我已经在这上面花了很多时间,需要把它包起来以提出建议,但无法弄清楚。
    【解决方案2】:

    一个基本的R选项是定义自定义函数fill,在ave中应用

    fill <- function(v) {
      inds <- range(which(!is.na(v)))
      l <- 1:inds[1]
      u <- inds[2]:length(v)
      v[l] <- v[inds[1]] - rev(l)+1
      v[u] <- v[inds[2]] + seq_along(u)-1
      v
    }
    
    df <- within(df,ref.pos <- ave(ref.pos,id,FUN = fill))
    

    这样

    > df
       id ref.pos pos
    1   1     298   1
    2   1     299   2
    3   1     300   3
    4   1     301   4
    5   1     302   5
    6   1     303   6
    7   1     800   7
    8   1     801   8
    9   1     802   9
    10  1     803  10
    11  1     804  11
    12  2     500  30
    13  2     501  31
    14  2     502  32
    15  2     503  33
    16  2     504  34
    17  2     505  35
    

    【讨论】:

    • 我在我的大集合上对此进行了测试,发现有时我需要指定 ref.pos 数字是否应该在数据框中向上移动或相反。抱歉,我之前没有意识到这是一个选项!我们可以从v 中的值顺序推导出这一点,例如:wo.na &lt;- purrr::discard(v, is.na); direction &lt;- wo.na[[1]] &lt; wo.na[[2]] 它为您现在的顺序给出TRUEref.pos 上升时下降,下降时上升,而当 FALSE 它下降时应该下降,上升时应该上升。如果这样更容易的话,我也可以将此作为列添加到df
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-19
    • 2019-06-18
    • 1970-01-01
    • 1970-01-01
    • 2021-03-15
    • 1970-01-01
    相关资源
    最近更新 更多