如何对下面的数据框进行子集,以便仅显示列AAA:CCC
列的行具有相同的值并保留IndID
字段?
Dat <- data.frame(IndID = LETTERS[seq(1,10)],
AAA = c(1,5,3,2,3,1,5,4,6,2),
BBB = c(1,8,5,2,5,4,8,4,4,5),
CCC = c(1,5,3,2,3,5,5,4,6,5))
> Dat
IndID AAA BBB CCC
1 A 1 1 1
2 B 5 8 5
3 C 3 5 3
4 D 2 2 2
5 E 3 5 3
6 F 1 4 5
7 G 5 8 5
8 H 4 4 4
9 I 6 4 6
10 J 2 5 5
我想返回以下结果。
Result <- data.frame(IndID = c("A", "D", "H"),
AAA = c(1,2,4),
BBB = c(1,2,4),
CCC = c(1,2,4))
> Result
IndID AAA BBB CCC
1 A 1 1 1
2 D 2 2 2
3 H 4 4 4
我发现了许多相关帖子,其中包括Find duplicated rows (based on 2 columns) in Data Frame in R和Find duplicated elements with dplyr等,但无法使用三列重现所需的结果。例如,虽然关闭下面的代码显示所有distinct
行,但是包含行的不希望的结果只有两个值相等。
Dat %>% distinct(AAA, BBB, CCC)
我怀疑解决方案涉及filter
,但不确定如何从示例mentioned above获取所需的结果。首选dplyr
解决方案。
加成
我也想知道这是否适用于多种因素。例如,下面的数据(包含IndID
和三个日期存储为因子)可以通过允许因子或将因子更改为数值来产生类似的结果吗?
Dat <- structure(list(GenIndID = structure(c(1L, 2L, 6L, 7L, 3L, 4L,
8L, 5L), .Label = c("BHS_601", "BHS_603", "BHS_604", "BHS_605",
"BHS_631", "BHS_635", "BHS_636", "BHS_637"), class = "factor"),
CptrDate = structure(c(1L, 2L, 3L, 3L, 2L, 2L, 3L, 4L), .Label = c("2016-02-01",
"2016-02-02", "2016-02-04", "2016-12-11"), class = "factor"),
DtLastAlive = structure(c(2L, 2L, 1L, 1L, 2L, 2L, 1L, 3L), .Label = c("2016-02-04",
"2017-07-13", "2017-08-27"), class = "factor"), DtFnlFate = structure(c(2L,
2L, 1L, 1L, 2L, 2L, 1L, 3L), .Label = c("2016-02-04", "2017-07-13",
"2017-08-27"), class = "factor")), .Names = c("GenIndID",
"CptrDate", "DtLastAlive", "DtFnlFate"), row.names = c(82L, 83L,
224L, 225L, 84L, 85L, 226L, 360L), class = "data.frame")
> Dat
GenIndID CptrDate DtLastAlive DtFnlFate
82 BHS_601 2016-02-01 2017-07-13 2017-07-13
83 BHS_603 2016-02-02 2017-07-13 2017-07-13
224 BHS_635 2016-02-04 2016-02-04 2016-02-04
225 BHS_636 2016-02-04 2016-02-04 2016-02-04
84 BHS_604 2016-02-02 2017-07-13 2017-07-13
85 BHS_605 2016-02-02 2017-07-13 2017-07-13
226 BHS_637 2016-02-04 2016-02-04 2016-02-04
360 BHS_631 2016-12-11 2017-08-27 2017-08-27
期望的结果是
> Dat[c(3, 4, 7),]
GenIndID CptrDate DtLastAlive DtFnlFate
224 BHS_635 2016-02-04 2016-02-04 2016-02-04
225 BHS_636 2016-02-04 2016-02-04 2016-02-04
226 BHS_637 2016-02-04 2016-02-04 2016-02-04
答案 0 :(得分:5)
以下是apply
和all
的另一种解决方案:
Dat[apply(Dat[,-1], 1, function(x) all(x==x[1])),]
或来自filter_at
的{{1}}:
dplyr
<强>结果:强>
library(dplyr)
Dat %>%
filter_at(vars(AAA:CCC), all_vars(. == .data$AAA))
修改强>
作为对OP的另外一个例子的回应,无论变量类型如何, IndID AAA BBB CCC
1 A 1 1 1
4 D 2 2 2
8 H 4 4 4
示例都能正常工作。因此,以下内容适用于新示例:
apply
<强>结果:强>
Dat[apply(Dat[,-1], 1, function(x) all(x==x[1])),]
对于 GenIndID CptrDate DtLastAlive DtFnlFate
224 BHS_635 2016-02-04 2016-02-04 2016-02-04
225 BHS_636 2016-02-04 2016-02-04 2016-02-04
226 BHS_637 2016-02-04 2016-02-04 2016-02-04
,如果要比较的列为filter_at
,则需要首先转换为factor
:
character
请注意,您只需要将Dat %>%
filter_at(vars(-1), all_vars(as.character(.) == .data$CptrDate))
转换为字符,而不是.
,因为因素可以使用字符进行转换,但不能使用不同级别的其他因素。
另一种选择是:
.data$CptrDate
<强>结果:强>
Dat %>%
mutate_at(vars(-1), as.character) %>%
filter_at(vars(-1), all_vars(. == .data$CptrDate))
答案 1 :(得分:2)
如果您只需要3列的子集,则可以使用DF [,]运算符。
# DF[where rows have a value, select columns]
# [where rows where AAA==BBB==CCC, select all columns with ""]
temp <- Dat[Dat$AAA == Dat$BBB & Dat$BBB == Dat$CCC,]
答案 2 :(得分:1)
您可以使用range()
和diff()
的组合。
Dat[apply(Dat[ ,-1], 1, function(x) diff(range(x)))==0, ]
# IndID AAA BBB CCC
# 1 A 1 1 1
# 4 D 2 2 2
# 8 H 4 4 4
range()
为您提供向量的最小值和最大值。 diff()
为您提供向量中值之间的差异。如果min-value
和max-value
之间的差异为零,则表示所有值均相等。如果我们使用apply
逐行应用此行,我们会得到一个TRUE
/ FALSE
向量,我们可以用它来索引Dat
。
用于说明逻辑的小例子:
test <- c(1, 5, 3)
minmax <- range(test) # gives c(1,5)
diff(minmax) # gives 4
diff(range(c(1, 1, 1))) # gives 0
如果我们检查每一行,diff(range(your_row))
是否等于零,我们可以使用它的输出来索引Dat
,就像我们上面所做的那样。
答案 3 :(得分:1)
您可以使用矢量化解决方案:
Dat[do.call(function(...) pmax(...) - pmin(...), Dat[, -1]) == 0,]
# IndID AAA BBB CCC
#1 A 1 1 1
#4 D 2 2 2
#8 H 4 4 4