如何在dataframe中检查前一行值与当前行值
如何通过对特定ID进行分组,为数据帧的所有列动态检查前一行值和当前行值 我的数据帧:如何在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 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))][]