比较分组数据框中的组
Comparing between groups in grouped dataframe
我正在尝试对数据框中后续组中的项目进行比较 - 我想这很容易,因为您知道自己在做什么...
我的数据集可以表示如下:
set.seed(1)
data <- data.frame(
date = c(rep('2015-02-01',15), rep('2015-02-02',16), rep('2015-02-03',15)),
id = as.character(c(1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,16,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE)))
)
生成的数据框如下所示:
date id
1/02/2015 1008
1/02/2015 1009
1/02/2015 1011
1/02/2015 1015
1/02/2015 1008
1/02/2015 1014
1/02/2015 1015
1/02/2015 1012
1/02/2015 1012
1/02/2015 1006
1/02/2015 1008
1/02/2015 1007
1/02/2015 1012
1/02/2015 1009
1/02/2015 1013
2/02/2015 1010
2/02/2015 1013
2/02/2015 1015
2/02/2015 1009
2/02/2015 1013
2/02/2015 1015
2/02/2015 1008
2/02/2015 1012
2/02/2015 1007
2/02/2015 1008
2/02/2015 1009
2/02/2015 1006
2/02/2015 1009
2/02/2015 1014
2/02/2015 1009
2/02/2015 1010
3/02/2015 1011
3/02/2015 1010
3/02/2015 1007
3/02/2015 1014
3/02/2015 1012
3/02/2015 1013
3/02/2015 1007
3/02/2015 1013
3/02/2015 1010
然后我想按日期对数据进行分组 (group_by),然后在比较组之间之前过滤掉重复项(不同的)。我想做的是每天确定添加哪些新 ID 以及离开哪些 ID。因此,将比较第 1 天和第 2 天以确定第 2 天不在第 1 天的 id 和第 1 天但第 2 天不存在的 id,然后在第 2 天和第 3 天之间进行相同的比较等。
使用 anti_join (dplyr) 可以很容易地完成比较,但我不知道如何引用数据集中的各个组。
我的尝试(或我的尝试之一)看起来像:
data %>%
group_by(date) %>%
distinct(id) %>%
do(lost = anti_join(., lag(.), by="id"))
但这当然行不通,我只是得到:
Error in anti_join_impl(x, y, by$x, by$y) : Can't join on 'id' x 'id' because of incompatible types (factor / logical)
我正在尝试做的事情是否可行,或者我应该考虑编写一个笨拙的函数来完成它?
只需将输入 stringsAsFactors = FALSE
添加到您的数据框。这将使您的代码 运行: 虽然我不确定输出的结果是否是您要查找的结果。要查看整个结果,请将其通过管道传输到 data.frame 并查看它是否是您要查找的内容。希望这有帮助。
set.seed(1)
data <- data.frame(
date = c(rep('2015-02-01',15), rep('2015-02-02',16), rep('2015-02-3',15)),
id = as.character(c(1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,16,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE))),stringsAsFactors = FALSE)
data %>%
group_by(date) %>%
distinct(id) %>%
do(lost = anti_join(., lag(.), by="id"))%>%data.frame()
对数据和合并进行一些操作可能会达到您想要的效果。像这样
df <- unique(data)
df$date <- as.Date(df$date)
df$leftdate <- df$date + 1
df$prevdate <- df$date - 1
df2 <- cbind(df[,c("date","id")],flag = 1)
# merge the dataframe so that each day would attempt to join the next day
dfleft <- merge(df,df2,by.x = c("leftdate","id"),by.y = c("date","id"),all.x= TRUE)
# if there is no common id between a day and the next day, the merge returns NA, which is the desired results for those who left
dfleft <- dfleft[is.na(dfleft$flag),c("leftdate","id")]
# Here, you reverse the logic to find those who show up today but weren't there yesterday
dfnew <- merge(df,df2,by.x = c("prevdate","id"),by.y = c("date","id"),all.x= TRUE)
dfnew <- dfnew[is.na(dfnew$flag),c("date","id")]
我对这个问题的理解是,数据显示每个日期的 ID,我们想要遍历日期,比较该日期的 ID 和前一个日期的 ID。
首先获取唯一行 u
并将 id
转换为数字。然后将 id
拆分为 date
得到 s
并定义一个函数 diffs
,它使用负数表示已删除的 id,生成添加的 id 的数字向量。 lapply
到 seq_along(s) 除了第一个组件,因为它没有先前的组件。没有使用包。
u <- unique(data)
u$id <- as.numeric(as.character(u$id))
s <- split(u$id, u$date)
diffs <- function(i) c(setdiff(s[[i]], s[[i-1]]), - setdiff(s[[i-1]], s[[i]]))
diffs_list <- setNames(lapply(seq_along(s)[-1], diffs), names(s)[-1])
给予:
> diffs_list
$`2015-02-02`
[1] 1010 -1011
$`2015-02-03`
[1] 1011 -1015 -1009 -1008 -1006
或者如果你想要一个数据框作为输出
setNames(stack(diffs_list), c("id", "date"))
给予:
id date
1 1010 2015-02-02
2 -1011 2015-02-02
3 1011 2015-02-03
4 -1015 2015-02-03
5 -1009 2015-02-03
6 -1008 2015-02-03
7 -1006 2015-02-03
magrittr
这也可以使用像这样的 magrittr 包来表达,其中 diffs
已在上面定义。
library(magrittr)
data %>%
unique %>%
transform(id = as.numeric(as.character(id))) %>%
{ split(.$id, .$date) } %>%
{ setNames(lapply(seq_along(.)[-1], diffs), names(.)[-1]) }
注意:我已经将data$date
中的-3替换为-03。
我确定我不会为自己的答案投票,但我必须说我最喜欢我的答案。我希望得到一个使用 dplyr 工具解决问题的答案,所以我一直在研究,我想我现在有一个(半)优雅的解决方案(除了我函数中的 for 循环)。
以相同的方式生成示例数据集,但使用更多数据使其更有趣:
set.seed(1)
data <- data.frame(
date = c(rep('2015-02-01',15), rep('2015-02-02',16), rep('2015-02-03',15), rep('2015-02-04',15), rep('2015-02-05',15)),
id = as.character(c(1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,16,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE)))
)
通过互联网搜索,我找到了 dplyr 函数 'nest()',它看起来可以解决我所有的分组问题。 nest() 函数获取由 group_by() 创建的组并将它们滚动到数据框列表中,因此您最终为分组的每个变量得到一个条目,然后为所有剩余的变量创建一个数据框适合该组的变量 - 这里是:
dataNested <- data %>%
group_by(date) %>%
distinct(id) %>%
nest()
这会产生一个相当奇怪的数据框,如下所示:
date data
1 2015-02-01 list(id = c(3, 4, 6, 10, 9, 7, 1, 2, 8))
2 2015-02-02 list(id = c(5, 8, 10, 4, 3, 7, 2, 1, 9))
3 2015-02-03 list(id = c(6, 5, 2, 9, 7, 8))
4 2015-02-04 list(id = c(1, 5, 8, 7, 9, 3, 4, 6, 10))
5 2015-02-05 list(id = c(3, 5, 4, 7, 8, 1, 9))
因此列表中的索引引用了 id 的列表(奇怪但真实)。
这现在允许我们通过索引号引用组,即:
dataNested$data[[2]]
returns:
# A tibble: 9 × 1
id
<fctr>
1 1010
2 1013
3 1015
4 1009
5 1008
6 1012
7 1007
8 1006
从这里开始,只需编写一个函数即可 anti_join 让我们只知道每个后续组之间的差异(尽管这是我不引以为豪的部分,并且真正开始显示我缺乏 R 技能 - 请随时提出改进建议):
## Function departed() - returns the id's that were dropped from each subsequent time period
departed <- function(groups) {
tempList <- vector("list", nrow(groups))
# Loop through the groups and do an anti_join between each
for (i in seq(1, nrow(groups) - 1)) {
tempList[[i + 1]] <-
anti_join(data.frame(groups$data[[i]]), data.frame(groups$data[[i + 1]]), by = "id")
}
return(tempList)
}
将此函数应用于我们的嵌套数据会生成已故 ID 列表的列表:
> departedIDs <- dataNested %>% departed()
> departedIDs
[[1]]
NULL
[[2]]
id
1 1011
[[3]]
id
1 1006
2 1008
3 1009
4 1015
[[4]]
id
1 1007
[[5]]
id
1 1011
2 1015
我希望这个回答能帮助到和我的大脑运作方式相同的人。
我正在尝试对数据框中后续组中的项目进行比较 - 我想这很容易,因为您知道自己在做什么...
我的数据集可以表示如下:
set.seed(1)
data <- data.frame(
date = c(rep('2015-02-01',15), rep('2015-02-02',16), rep('2015-02-03',15)),
id = as.character(c(1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,16,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE)))
)
生成的数据框如下所示:
date id
1/02/2015 1008
1/02/2015 1009
1/02/2015 1011
1/02/2015 1015
1/02/2015 1008
1/02/2015 1014
1/02/2015 1015
1/02/2015 1012
1/02/2015 1012
1/02/2015 1006
1/02/2015 1008
1/02/2015 1007
1/02/2015 1012
1/02/2015 1009
1/02/2015 1013
2/02/2015 1010
2/02/2015 1013
2/02/2015 1015
2/02/2015 1009
2/02/2015 1013
2/02/2015 1015
2/02/2015 1008
2/02/2015 1012
2/02/2015 1007
2/02/2015 1008
2/02/2015 1009
2/02/2015 1006
2/02/2015 1009
2/02/2015 1014
2/02/2015 1009
2/02/2015 1010
3/02/2015 1011
3/02/2015 1010
3/02/2015 1007
3/02/2015 1014
3/02/2015 1012
3/02/2015 1013
3/02/2015 1007
3/02/2015 1013
3/02/2015 1010
然后我想按日期对数据进行分组 (group_by),然后在比较组之间之前过滤掉重复项(不同的)。我想做的是每天确定添加哪些新 ID 以及离开哪些 ID。因此,将比较第 1 天和第 2 天以确定第 2 天不在第 1 天的 id 和第 1 天但第 2 天不存在的 id,然后在第 2 天和第 3 天之间进行相同的比较等。
使用 anti_join (dplyr) 可以很容易地完成比较,但我不知道如何引用数据集中的各个组。
我的尝试(或我的尝试之一)看起来像:
data %>%
group_by(date) %>%
distinct(id) %>%
do(lost = anti_join(., lag(.), by="id"))
但这当然行不通,我只是得到:
Error in anti_join_impl(x, y, by$x, by$y) : Can't join on 'id' x 'id' because of incompatible types (factor / logical)
我正在尝试做的事情是否可行,或者我应该考虑编写一个笨拙的函数来完成它?
只需将输入 stringsAsFactors = FALSE
添加到您的数据框。这将使您的代码 运行: 虽然我不确定输出的结果是否是您要查找的结果。要查看整个结果,请将其通过管道传输到 data.frame 并查看它是否是您要查找的内容。希望这有帮助。
set.seed(1)
data <- data.frame(
date = c(rep('2015-02-01',15), rep('2015-02-02',16), rep('2015-02-3',15)),
id = as.character(c(1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,16,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE))),stringsAsFactors = FALSE)
data %>%
group_by(date) %>%
distinct(id) %>%
do(lost = anti_join(., lag(.), by="id"))%>%data.frame()
对数据和合并进行一些操作可能会达到您想要的效果。像这样
df <- unique(data)
df$date <- as.Date(df$date)
df$leftdate <- df$date + 1
df$prevdate <- df$date - 1
df2 <- cbind(df[,c("date","id")],flag = 1)
# merge the dataframe so that each day would attempt to join the next day
dfleft <- merge(df,df2,by.x = c("leftdate","id"),by.y = c("date","id"),all.x= TRUE)
# if there is no common id between a day and the next day, the merge returns NA, which is the desired results for those who left
dfleft <- dfleft[is.na(dfleft$flag),c("leftdate","id")]
# Here, you reverse the logic to find those who show up today but weren't there yesterday
dfnew <- merge(df,df2,by.x = c("prevdate","id"),by.y = c("date","id"),all.x= TRUE)
dfnew <- dfnew[is.na(dfnew$flag),c("date","id")]
我对这个问题的理解是,数据显示每个日期的 ID,我们想要遍历日期,比较该日期的 ID 和前一个日期的 ID。
首先获取唯一行 u
并将 id
转换为数字。然后将 id
拆分为 date
得到 s
并定义一个函数 diffs
,它使用负数表示已删除的 id,生成添加的 id 的数字向量。 lapply
到 seq_along(s) 除了第一个组件,因为它没有先前的组件。没有使用包。
u <- unique(data)
u$id <- as.numeric(as.character(u$id))
s <- split(u$id, u$date)
diffs <- function(i) c(setdiff(s[[i]], s[[i-1]]), - setdiff(s[[i-1]], s[[i]]))
diffs_list <- setNames(lapply(seq_along(s)[-1], diffs), names(s)[-1])
给予:
> diffs_list
$`2015-02-02`
[1] 1010 -1011
$`2015-02-03`
[1] 1011 -1015 -1009 -1008 -1006
或者如果你想要一个数据框作为输出
setNames(stack(diffs_list), c("id", "date"))
给予:
id date
1 1010 2015-02-02
2 -1011 2015-02-02
3 1011 2015-02-03
4 -1015 2015-02-03
5 -1009 2015-02-03
6 -1008 2015-02-03
7 -1006 2015-02-03
magrittr
这也可以使用像这样的 magrittr 包来表达,其中 diffs
已在上面定义。
library(magrittr)
data %>%
unique %>%
transform(id = as.numeric(as.character(id))) %>%
{ split(.$id, .$date) } %>%
{ setNames(lapply(seq_along(.)[-1], diffs), names(.)[-1]) }
注意:我已经将data$date
中的-3替换为-03。
我确定我不会为自己的答案投票,但我必须说我最喜欢我的答案。我希望得到一个使用 dplyr 工具解决问题的答案,所以我一直在研究,我想我现在有一个(半)优雅的解决方案(除了我函数中的 for 循环)。
以相同的方式生成示例数据集,但使用更多数据使其更有趣:
set.seed(1)
data <- data.frame(
date = c(rep('2015-02-01',15), rep('2015-02-02',16), rep('2015-02-03',15), rep('2015-02-04',15), rep('2015-02-05',15)),
id = as.character(c(1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,16,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE), 1005 + sample.int(10,15,replace=TRUE)))
)
通过互联网搜索,我找到了 dplyr 函数 'nest()',它看起来可以解决我所有的分组问题。 nest() 函数获取由 group_by() 创建的组并将它们滚动到数据框列表中,因此您最终为分组的每个变量得到一个条目,然后为所有剩余的变量创建一个数据框适合该组的变量 - 这里是:
dataNested <- data %>%
group_by(date) %>%
distinct(id) %>%
nest()
这会产生一个相当奇怪的数据框,如下所示:
date data
1 2015-02-01 list(id = c(3, 4, 6, 10, 9, 7, 1, 2, 8))
2 2015-02-02 list(id = c(5, 8, 10, 4, 3, 7, 2, 1, 9))
3 2015-02-03 list(id = c(6, 5, 2, 9, 7, 8))
4 2015-02-04 list(id = c(1, 5, 8, 7, 9, 3, 4, 6, 10))
5 2015-02-05 list(id = c(3, 5, 4, 7, 8, 1, 9))
因此列表中的索引引用了 id 的列表(奇怪但真实)。
这现在允许我们通过索引号引用组,即:
dataNested$data[[2]]
returns:
# A tibble: 9 × 1
id
<fctr>
1 1010
2 1013
3 1015
4 1009
5 1008
6 1012
7 1007
8 1006
从这里开始,只需编写一个函数即可 anti_join 让我们只知道每个后续组之间的差异(尽管这是我不引以为豪的部分,并且真正开始显示我缺乏 R 技能 - 请随时提出改进建议):
## Function departed() - returns the id's that were dropped from each subsequent time period
departed <- function(groups) {
tempList <- vector("list", nrow(groups))
# Loop through the groups and do an anti_join between each
for (i in seq(1, nrow(groups) - 1)) {
tempList[[i + 1]] <-
anti_join(data.frame(groups$data[[i]]), data.frame(groups$data[[i + 1]]), by = "id")
}
return(tempList)
}
将此函数应用于我们的嵌套数据会生成已故 ID 列表的列表:
> departedIDs <- dataNested %>% departed()
> departedIDs
[[1]]
NULL
[[2]]
id
1 1011
[[3]]
id
1 1006
2 1008
3 1009
4 1015
[[4]]
id
1 1007
[[5]]
id
1 1011
2 1015
我希望这个回答能帮助到和我的大脑运作方式相同的人。