【问题标题】:R: Adding NAs into Data FrameR:将 NA 添加到数据框中
【发布时间】:2014-10-27 16:03:19
【问题描述】:

我有一个像这样的数据框:

Name   Position   Value
a         1        0.2
a         3        0.4
a         4        0.3
b         1        0.5
b         2        0.4
b         5        0.3
c         2        0.3
c         3        0.4
c         5        0.1
d         1        0.2
d         2        0.4
d         3        0.5

我想让每个名称的 Position 始终从 1 变为 5,并将 NA 填充到 Value 中,如下所示:

Name   Position   Value
a         1        0.2
a         2        NA
a         3        0.4
a         4        0.3
a         5        NA
b         1        0.5
b         2        0.4
b         3        NA
b         4        NA
b         5        0.3
c         1        NA
c         2        0.3
c         3        0.4
c         4        NA
c         5        0.1
d         1        0.2
d         2        0.4
d         3        0.5
d         4        NA
d         5        NA

有没有办法做到这一点,而不用前 2 列创建一个虚拟数据框,然后使用合并进行某种外部连接?

谢谢。

【问题讨论】:

  • @Cinji18 使用merge 非常简单df1 <- expand.grid(Name=unique(df$Name), Position=1:5); merge(df1, df,all=TRUE)
  • @akrun Ops...没有看到您的评论并发布了相同的答案...我已将其删除。
  • @nicola 没关系。你可以发布它。它比我的代码更紧凑,而且有点笼统。我没有发布解决方案,因为 OP 提到不使用 merge

标签: r dataframe na


【解决方案1】:

我会使用data.table,但与@akrun 下划线的方式不同:

library(data.table)
dt = as.data.table(df)
setkey(dt, Name, Position)
dt[CJ(unique(Name),unique(Position))]

【讨论】:

    【解决方案2】:

    您可以使用reshape2 包:

    # make sample data frame
    df <- read.table(text = "Name   Position   Value
    a         1        0.2
    a         3        0.4
    a         4        0.3
    b         1        0.5
    b         2        0.4
    b         5        0.3
    c         2        0.3
    c         3        0.4
    c         5        0.1
    d         1        0.2
    d         2        0.4
    d         3        0.5", header = TRUE, stringsAsFactors = FALSE)
    
    library('reshape2')
    df2 <- dcast(df, Name ~ Position)
    df3 <- melt(df2, value.name = "Value", variable.name = "Position")
    df3[order(df3$Name), ]
    #    Name Position Value
    # 1     a        1   0.2
    # 5     a        2    NA
    # 9     a        3   0.4
    # 13    a        4   0.3
    # 17    a        5    NA
    # 2     b        1   0.5
    # 6     b        2   0.4
    # 10    b        3    NA
    # 14    b        4    NA
    # 18    b        5   0.3
    # 3     c        1    NA
    # 7     c        2   0.3
    # 11    c        3   0.4
    # 15    c        4    NA
    # 19    c        5   0.1
    # 4     d        1   0.2
    # 8     d        2   0.4
    # 12    d        3   0.5
    # 16    d        4    NA
    # 20    d        5    NA
    

    【讨论】:

      【解决方案3】:

      也许这是矫枉过正,但我​​认为你可以使用sqldf 来做到这一点:

      library(sqldf)
      # Your data frame:
      df <- data.frame(
        name = c('a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd'),
        position = c(1, 3, 4, 1, 2, 5, 2, 3, 5, 1, 2, 3),
        value = c(0.2, 0.4, 0.3, 0.5, 0.4, 0.3, 0.3, 0.4, 0.1, 0.2, 0.4, 0.5)
      )
      # A data frame to hold the positions you want to fill:
      pos = data.frame(pos = 1:5)
      # SQLdf let's you write SQL sentences that use data frames like SQL tables:
      df2 <- sqldf(
        "select a.*, b.value as value
        from (
          select a.name, p.pos as position 
          from (select distinct name from df) as a, pos as p
        ) as a
        left join df as b on a.name = b.name and a.position = b.position"
      )
      df2
      ## Result:
      ##   name position value
      ##1     a        1   0.2
      ##2     a        2    NA
      ##3     a        3   0.4
      ##4     a        4   0.3
      ##5     a        5    NA
      ##6     b        1   0.5
      ##7     b        2   0.4
      ##8     b        3    NA
      ##9     b        4    NA
      ##10    b        5   0.3
      ##11    c        1    NA
      ##12    c        2   0.3
      ##13    c        3   0.4
      ##14    c        4    NA
      ##15    c        5   0.1
      ##16    d        1   0.2
      ##17    d        2   0.4
      ##18    d        3   0.5
      ##19    d        4    NA
      ##20    d        5    NA
      

      当然,你可以将sqldf()的结果直接赋值给df,覆盖原来的数据框

      【讨论】:

        【解决方案4】:

        你可以使用data.table

         library(data.table)
         DT <- data.table(df)
         setkey(DT, Position)
         DT[, .SD[J(1:5), roll=FALSE], by=Name][order(Name, Position),]
         #   Name Position Value
         #1:    a        1   0.2
         #2:    a        2    NA
         #3:    a        3   0.4
         #4:    a        4   0.3
         #5:    a        5    NA
         #6:    b        1   0.5
         #7:    b        2   0.4
         #8:    b        3    NA
         #9:    b        4    NA
        #10:    b        5   0.3
        #11:    c        1    NA
        #12:    c        2   0.3
        #13:    c        3   0.4
        #14:    c        4    NA
        #15:    c        5   0.1
        #16:    d        1   0.2
        #17:    d        2   0.4
        #18:    d        3   0.5
        #19:    d        4    NA
        #20:    d        5    NA
        

        或者你可以使用tidyr/dplyr

         library(dplyr)
         library(tidyr)
        
          df %>% 
              spread(Position, Value) %>%
              gather(Position, Value, `1`:`5`) %>%
              arrange(Name, Position)    
        

        数据

         df <- structure(list(Name = c("a", "a", "a", "b", "b", "b", "c", "c", 
         "c", "d", "d", "d"), Position = c(1L, 3L, 4L, 1L, 2L, 5L, 2L, 
         3L, 5L, 1L, 2L, 3L), Value = c(0.2, 0.4, 0.3, 0.5, 0.4, 0.3, 
         0.3, 0.4, 0.1, 0.2, 0.4, 0.5)), .Names = c("Name", "Position", 
         "Value"), class = "data.frame", row.names = c(NA, -12L))
        

        【讨论】:

        • 这不是一个有效的方法。
        • @akrun 我可以问一个关于 CJ 和 SJ 的问题吗?我今天一直在研究 CJ 的一个例子。现在我正在用 SJ 搜索 SO 帖子。但我真的没有看到任何东西。你以前用过SJ吗?如果有,您是如何使用它的?
        • @jazzurro 不,我以前没用过SJ。不知道你有没有在r.789695.n4.nabble.com/What-is-the-point-of-SJ-td4670616.html之前看过这个链接
        • @akrun 非常感谢。看来SJ真的是为了排序。它可能类似于arrange。看到那里的帖子不多,SJ可能没那么有用?
        • @akrun 是的,我只是在收到您的消息之前看过它。到目前为止,这是我能找到的唯一东西。
        【解决方案5】:

        这里有几个基本解决方案:

        as.data.frame.table(tapply(df[[3]], df[2:1], c))
        

        merge(df, 
              expand.grid(Position = unique(df$Position), Name = unique(df$Name)), 
              all = TRUE)
        

        【讨论】:

          猜你喜欢
          • 2021-08-12
          • 2014-01-19
          • 2020-10-19
          • 1970-01-01
          • 1970-01-01
          • 2020-08-02
          • 1970-01-01
          • 1970-01-01
          • 2014-12-28
          相关资源
          最近更新 更多