【问题标题】:Remove rows which are different with the first changing in R删除与 R 中的第一次更改不同的行
【发布时间】:2016-06-29 04:09:02
【问题描述】:

我有数据集

 ID <- c(1,1,1,2,2,2,2,3,3,4,4,4,4,4,4)
 x <- c(1,2,3,1,2,3,4,1,2,1,2,3,4,5,6)
 y <- c(2,2,3,6,6,4,5, 1,1,5,5,5,2,2,2)
 df <- data.frame(ID, x, y)
 df
    ID x y
1   1 1 2
2   1 2 2
3   1 3 3
4   2 1 6
5   2 2 6
6   2 3 4
7   2 4 5
8   3 1 1
9   3 2 1
10  4 1 5
11  4 2 5
12  4 3 5
13  4 4 2
14  4 5 2
15  4 6 2

如果你看到 ID 1 有 3 行,由第三行的 y 改变 y = 3,所以我想设置 y = 2(与前一行相同的数量), ID 2 在 y = 4 处有 y 改变,我想设置 y = 6 并删除下一行。当每个ID的y个数发生变化时,我们只设置第一行变化与上一行相同,其余的去掉。

表格将是

    ID x y
     1 1 2
     1 2 2
     1 3 2
     2 1 6
     2 2 6
     2 3 6
     3 1 1
     3 2 1
     4 1 5
     4 2 5
     4 3 5
     4 4 5

我想不通,你有什么想法,请帮助我,谢谢。

【问题讨论】:

  • 我们可以通过使用 for 循环来做到这一点你想在你的 df 中保留 ID 4 x 值 4
  • 是的,我们将保留所有重复的行直到下一行更改,ID 4 的 x 是 1,2,3,4。我们检查每个 ID 直到 y 不同,然后设置 y 具有相同的值,如果该 ID 左侧还有更多行,则将其删除

标签: r duplicates subset


【解决方案1】:

或者我们可以这样做

library(data.table)
df1 <- setDT(df)[, .SD[shift(rleid(y), fill = 1) == 1], .(ID)]
df1[, y := y[1], .(ID)]
df1
    ID x y
 1:  1 1 2
 2:  1 2 2
 3:  1 3 2
 4:  2 1 6
 5:  2 2 6
 6:  2 3 6
 7:  3 1 1
 8:  3 2 1
 9:  4 1 5
10:  4 2 5
11:  4 3 5
12:  4 4 5

【讨论】:

    【解决方案2】:

    我们可以使用data.table。将'data.frame'转换为'data.table'(setDT(df)),按'ID'分组,if'y'中只有一个unique元素获取行序列(1:.N)或者else得到'y'的差(diff),检查是否不等于0,使用which返回第一个TRUE的数字索引([1]),得到序列并换行它与.I 一起返回行索引。

    library(data.table)
    i1 <- setDT(df)[, if(uniqueN(y) >1)  .I[seq(which(c(FALSE,diff(y)!=0))[1])] 
                         else .I[1:.N], ID]$V1
    

    基于 'i1',我们对 'df' 的行进行子集化,按 'ID' 分组,我们分配 (:=),即 'y' 中的第一个元素来更改 'y' 列。

    df[i1][, y:= y[1],  ID][]
    #    ID x y
    #1:  1 1 2
    #2:  1 2 2
    #3:  1 3 2
    #4:  2 1 6
    #5:  2 2 6
    #6:  2 3 6
    #7:  3 1 1
    #8:  3 2 1
    #9:  4 1 5
    #10: 4 2 5
    #11: 4 3 5
    #12: 4 4 5
    

    或者我们可以使用更简单的编码dplyr。 (免责声明:这个想法有点类似于@Psidom 的代码)。按'ID'分组后,我们得到'y'的lag,通过与第一个观察比较得到一个逻辑索引,filter基于此的行并将'y'值更改为第一个值。

     library(dplyr)
     df %>%
          group_by(ID) %>%
          filter(first(y)==lag(y, default = first(y))) %>% 
          mutate(y, y=first(y))
     #        ID     x     y
     #     <dbl> <dbl> <dbl>
     #1      1     1     2
     #2      1     2     2
     #3      1     3     2
     #4      2     1     6
     #5      2     2     6
     #6      2     3     6
     #7      3     1     1
     #8      3     2     1
     #9      4     1     5
     #10     4     2     5
     #11     4     3     5
     #12     4     4     5
    

    或者另一个选项是ave from base R

     df1 <- df[with(df, as.logical(ave(y, ID, FUN = function(x)
                                   lag(x, default= x[1])== x[1]))),]
     df1$y <- with(df1, ave(y, ID, FUN= function(x) x[1]))
    

    【讨论】:

    • 我在使用 library(dplyr) 时收到此错误“错误:期望单个值”,你知道为什么吗?
    • @Stat 我正在使用dplyr_0.4.3.9001 您正在使用哪个版本的 dplyr?有时,如果您加载 plyr,它可能会发生。
    • 我用的是这个版本:0.4.3
    • @Stat 我有.9001,它可能已经解决了您版本中的任何错误。
    • @Stat 你可以通过不使用mutate 行来检查吗
    【解决方案3】:

    您可以使用 for 循环,匹配给定 ID 的第一个实例:

    for( i in 1:nrow(df) ){ 
        df$new[i] <- df$y[ match( df$ID[i], df$ID ) ] 
    }
    

    这是有效的,因为对于给定的 ID,您实际上要求将 y 的所有后续值替换为第一个值。 match 返回匹配给定条件的第一个值,这非常适合您所追求的。

    或者您可以通过首先将 ID 提取为变量来消除 for 循环:

    ID <- df$ID
    df$new <- df$y[ match( ID, df$ID ) ]
    

    编辑添加:抱歉,这是根据要求添加删除行的步骤

    df <- subset( df, y == new | 
            ( shift( y, 1, type = "lag" ) != y & 
                shift( ID, 1, type = "lag" ) == ID ) 
            )
    

    【讨论】:

    • 我运行了代码,但我应该在你更改后删除该行
    • 实际上,假设要删除一行。 ID 2,有 3 行,不是 4
    猜你喜欢
    • 2022-09-20
    • 2023-02-03
    • 1970-01-01
    • 2017-12-14
    • 2021-10-22
    • 2014-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多