如何在dataframe中检查前一行值与当前行值

如何在dataframe中检查前一行值与当前行值,r,R,如何通过对特定ID进行分组,为数据帧的所有列动态检查前一行值和当前行值 我的数据帧: ID ITEM1 ITEM2 ITEM3 1 A A A 2 C B C 1 A B C 1 B A C 2 NA B F 3

如何通过对特定ID进行分组,为数据帧的所有列动态检查前一行值和当前行值

我的数据帧:

ID  ITEM1     ITEM2    ITEM3           
  1    A         A        A     
  2    C         B        C       
  1    A         B        C
  1    B         A        C    
  2    NA        B        F      
  3    A         A        D     
  4    R         G        J 
  4    H         T        J
例如:

ID  ITEM1     ITEM2    ITEM3    ITEM1change  ITEM2change   ITEM3change                   
  1    A         A        A       0            0             0          
  1    A         B        C       0            1             1
  1    B         A        C       1            1             0 
  2    C         B        C       0            0             0
  2    NA        B        F       1            0             1
  3    A         A        D       0            0             0
  4    R         G        J       0            0             0
  4    H         T        J       1            1             0
我的最终输出将是:

  Fiels         modifiedcout   unmodifiedcount Total      
  ITEM1change     3               5              8                
  ITEM2change     3               5              8    
  ITEM3change     2               6              8
我的数据:

structure(list(ID = c(1, 2, 1, 1, 2, 3, 4, 4), ITEM1 = structure(c(1L, 
3L, 1L, 2L, NA, 1L, 5L, 4L), .Label = c("A", "B", "C", "H", "R"
), class = "factor"), ITEM2 = structure(c(1L, 2L, 2L, 1L, 2L, 
1L, 3L, 4L), .Label = c("A", "B", "G", "T"), class = "factor"), 
    ITEM3 = structure(c(1L, 2L, 2L, 2L, 4L, 3L, 5L, 5L), .Label = c("A", 
    "C", "D", "F", "J"), class = "factor")), .Names = c("ID", 
"ITEM1", "ITEM2", "ITEM3"), row.names = c(NA, -8L), class = "data.frame")

如果
dat
是您的数据,请尝试:

创建
ITEMCHANGE
变量

dat["ITEM1Change"] <- c(NA, head(dat["ITEM1"], dim(dat)[1] - 1)[[1]])
dat["ITEM2Change"] <- c(NA, head(dat["ITEM2"], dim(dat)[1] - 1)[[1]])
dat["ITEM3Change"] <- c(NA, head(dat["ITEM3"], dim(dat)[1] - 1)[[1]])
这就是您需要的吗?

一个可能的解决方案:

library(dplyr)
library(tidyr)

df %>% 
  gather(item, value, -1) %>% 
  group_by(ID, item) %>% 
  mutate(change = lag(value, default = first(value)) != value,
         change = replace(change, is.na(change), TRUE)) %>% 
  group_by(item) %>% 
  summarise(modified = sum(change, na.rm = TRUE),
            unmodified = sum(!change, na.rm = TRUE)) %>% 
  mutate(total = modified + unmodified)
其中:

#一个tible:3 x 4
项目修改未修改总计
1项目13 5 8
2项目2 3 5 8
3项目3 2 6 8

下面是使用
zoo
中的
rollapply
的另一个想法。通过使用
rollapply
width=2
,我们正在测试
x
是否不等于
x-1
。将其包装为.integer将得到1s(
TRUE
)和0s(
FALSE
)。然后,我们将所有的<代码> n</代码> s替换为1,因为您认为它们是被修改的,并且使用<代码> CalSooS/<代码>来对修改/未修改的元素进行求和。总数只是原始数据帧的行数

library(zoo)

m1 <- do.call(rbind, lapply(split(df, df$ID), function(i) 
                     sapply(i[-1], function(j) 
                     as.integer(c(FALSE, rollapply(j, 2, function(k) k[1] != k[2]))))))

m1 <- replace(m1, is.na(m1), 1)

#giving

#   ITEM1 ITEM2 ITEM3
#      0     0     0
#      0     1     1
#      1     1     0
#      0     0     0
#      1     0     1
#3     0     0     0
#      0     0     0
#      1     1     0

给定的数据有许多相同类型的列。这强烈建议数据最好以长格式存储,而不是以宽格式存储

正在使用
tidyr
/
dplyr
重塑数据

但是,我想建议一种不改变数据形状的
data.table
解决方案。此外,它避免单独处理
NA

library(data.table)
# coerce to data.table, loop over columns and determine changes to previous row by ID
tmp <- setDT(DF)[, lapply(.SD, function(x) x == shift(x, fill = x[1])), by = ID]
tmp
现在,我们可以计算未更改的行数:

tmp[, lapply(.SD, sum, na.rm = TRUE), .SDcols = -"ID"]
从这里,OP的预期结果可以通过两种不同的方式实现

使用
melt()

或者通过转置:

as.data.table(
  t(tmp[, lapply(.SD, sum, na.rm = TRUE), .SDcols = -"ID"])
  , keep.rownames = "item")[, setnames(.SD, "V1", "unmodified")][
    , c("modified", "Total") := .(nrow(DF) - unmodified, nrow(DF))][]
两者都返回相同的结果:


为了完整起见,这里还有一个重塑方法的
data.table
实现。如上所述,
NA
通过首先计算未修改的行来处理,不包括任何
NA

melt(setDT(DF), id.vars = "ID", variable.name = "item")[
  , value == shift(value, fill = value[1L]), by = .(ID, item)][
    , .(unmodified = sum(V1, na.rm = TRUE)), by = item][
      , c("modified", "Total") := .(nrow(DF) - unmodified, nrow(DF))][]

类似于
c(0,as.integer(as.boolean)(diff(as.numeric)(as.factor(yourcol kЮЮЮ))
的东西应该有效注意,在您的示例中,您可以简单地将唯一项计数为不存在的
as.logical()
而不是
as.boolean()
?,感谢您的回复,但我的疑问是动态添加列,例如,如果列中有50到100项意味着我如何手动添加,这就是为什么我需要动态创建和汇总修改的计数和未修改的计数。感谢示例响应,同时我需要将NA值汇总为一个计数,例如:ITEM1 3 5 8。请告诉我怎么做…,同时你能帮我如何将_按多列进行分组。@udya我不确定我是否理解正确。你能更详细地解释一下你的问题吗?
       modified unmodified Total
ITEM1        3          5     8
ITEM2        3          5     8
ITEM3        2          6     8
library(data.table)
# coerce to data.table, loop over columns and determine changes to previous row by ID
tmp <- setDT(DF)[, lapply(.SD, function(x) x == shift(x, fill = x[1])), by = ID]
tmp
   ID ITEM1 ITEM2 ITEM3
1:  1  TRUE  TRUE  TRUE
2:  1  TRUE FALSE FALSE
3:  1 FALSE FALSE  TRUE
4:  2  TRUE  TRUE  TRUE
5:  2    NA  TRUE FALSE
6:  3  TRUE  TRUE  TRUE
7:  4  TRUE  TRUE  TRUE
8:  4 FALSE FALSE  TRUE
tmp[, lapply(.SD, sum, na.rm = TRUE), .SDcols = -"ID"]
   ITEM1 ITEM2 ITEM3
1:     5     5     6
melt(tmp[, lapply(.SD, sum, na.rm = TRUE), .SDcols = -"ID"]
     , measure.vars = patterns("^ITEM"), 
     variable.name = "item", 
     value.name = "unmodified")[
       , c("modified", "Total") := .(nrow(DF) - unmodified, nrow(DF))][]
as.data.table(
  t(tmp[, lapply(.SD, sum, na.rm = TRUE), .SDcols = -"ID"])
  , keep.rownames = "item")[, setnames(.SD, "V1", "unmodified")][
    , c("modified", "Total") := .(nrow(DF) - unmodified, nrow(DF))][]
    item unmodified modified Total
1: ITEM1          5        3     8
2: ITEM2          5        3     8
3: ITEM3          6        2     8
melt(setDT(DF), id.vars = "ID", variable.name = "item")[
  , value == shift(value, fill = value[1L]), by = .(ID, item)][
    , .(unmodified = sum(V1, na.rm = TRUE)), by = item][
      , c("modified", "Total") := .(nrow(DF) - unmodified, nrow(DF))][]