我有一个包含5个数字列的数据集,例如{A,B,C,D,E}, 其中任何列的值都可以在1到100之间变化。
1 <= A / B / C / D / E中的所有值<= 100
我们的数据集如下:
A B C D E
1 5 7 19 2
90 12 8 45 30
30 10 20 50 40 #need this row
33 11 22 55 44
50 40 10 20 30 #and this row
40 40 10 20 30 #not this one
,而我只想过滤包含以下5个值中的每个值的那些行,例如:{10,20,30,40,50}。顺序无关紧要,但5列应包含所有5个值。
所以输出应该是这样的:
A B C D E
30 10 20 50 40
50 40 10 20 30
我尝试使用大量的ifelse
来过滤所有5个列条件,但问题是我需要将此概念应用于更复杂的问题,在这些问题中它们可能不是定义的否。列甚至定义的“查找”数据集。因此,非常感谢使用dplyr,data.table,tidyverse的任何解决方案,但是任何其他可以提出的创意都请分享。
答案 0 :(得分:2)
tb <- data.frame(A = c(1, 90, 30 ,33,50,40),
B = c(5,12,10,11,40,40),
C = c(7,8,20,22,10,10),
D = c(19,45,50,55,20,20),
E = c(2,30,40,44,30,30))
cols <- paste0(c(10,20,30,40,50), collapse = "_")
index <- apply(tb, 1, function(x) paste0(sort(x), collapse = "_") == cols)
tb[index,]
答案 1 :(得分:2)
使用基础apply
中的sum
,%in%
和R
my_vals = c(10, 20, 30, 40, 50)
df[apply(df, 1, function(row) all(my_vals %in% row)), ]
A B C D E
3 30 10 20 50 40
5 50 40 10 20 30
这可以扩展到任意数量的列,您要做的就是更新my_vals
。
根据OP的评论,即当my_vals
可能具有重复的元素时要选择正确的行,可以对上述代码进行如下修改
my_vals = sort(c(10, 20, 30, 40, 40))
df[apply(df, 1, function(row) all(my_vals == sort(row))), ]
A B C D E
6 40 40 10 20 30
答案 2 :(得分:1)
也许是这样吗?
library(dplyr)
dat %>%
rowwise() %>%
filter(paste(sort(c(A, B, C, D, E)), collapse = ".") == "10.20.30.40.50") %>%
ungroup()
# A tibble: 2 x 5
A B C D E
<int> <int> <int> <int> <int>
1 30 10 20 50 40
2 50 40 10 20 30
数据:
dat <- read.table(text = "A B C D E
1 5 7 19 2
90 12 8 45 30
30 10 20 50 40
33 11 22 55 44
50 40 10 20 30
40 40 10 20 30", header = TRUE)
注意:我不确定这是否是扩展到您的“更复杂的问题,因为它们可能不是已定义的列数甚至是已定义的“查找”数据集”的好方法” ,因为定义有些模糊。如果您遇到更复杂的问题,强烈建议您提出问题以反映出来。
答案 3 :(得分:0)
这是一种重塑为长格式,过滤并重塑为宽体的方法:
my_vals = c(10, 20, 30, 40, 50)
library(tidyr)
library(dplyr)
df %>% mutate(id = row_number()) %>%
gather("col", "val", -id) %>%
group_by(id) %>%
filter(all(my_vals %in% val)) %>%
spread(col, val)
# A tibble: 2 x 6
# Groups: id [2]
id A B C D E
<int> <int> <int> <int> <int> <int>
1 3 30 10 20 50 40
2 5 50 40 10 20 30
(当然,如果您不想要,也可以删除id
列。)
答案 4 :(得分:0)
这是一个数据表解决方案:
library(data.table)
dt <- setDT(read.table(text = "A B C D E
1 5 7 19 2
90 12 8 45 30
30 10 20 50 40
33 11 22 55 44
50 40 10 20 30
40 40 10 20 30", header = TRUE))
dt = dt[, .SD[all(seq(10, 50, 10) %in% .SD)], by = 1:nrow(dt)]
答案 5 :(得分:0)
这是不对每一行进行排序的另一个选项。
这个想法是将数据集的每一列与查找值逐列连接。例如对于列A,请使用所有5个值来过滤原始数据集。
然后,对于B列,对上一步中的数据集的每个子集使用A列中未使用的任何内容进行联接。
然后,对于C列,使用上一步中每个数据集子集在A列和B列中未使用的任何内容进行联接。
然后,对于D列,使用上一步中数据集的每个子集的A,B和C列中未使用的任何内容进行联接。
依此类推。
以下是data.table
中上述想法的实现:
v <- c(10, 20, 30, 40, 40)
nm <- names(dat)
dat <- dat[.(A=unique(v)), on=.(A), nomatch=0L]
for (k in seq_along(nm)[-1L]) {
dat <- dat[, .SD[.(unique(v[-match(.BY, v)])),
on=eval(nm[k]),
nomatch=0L],
by=eval(nm[seq_len(k)[-k]])]
}
dat
v <- c(10, 20, 30, 40, 40)
的输出:
A B C D E
1: 10 40 40 20 30
2: 40 40 10 20 30
3: 40 40 10 20 30
v <- c(10, 20, 30, 40, 50)
的输出:
A B C D E
1: 30 10 20 50 40
2: 50 40 10 20 30
数据:
library(data.table)
dat <- fread("A B C D E
1 5 7 19 2
90 12 8 45 30
30 10 20 50 40
33 11 22 55 44
50 40 10 20 30
40 40 10 20 30
40 40 10 20 30
10 40 40 20 30") #2 dupe rows to demonstrate edge case