Как найти равные столбцы в R?
Учитывая следующее:
a <- c(1,2,3)
b <- c(1,2,3)
c <- c(4,5,6)
A <- cbind(a,b,c)
Я хочу найти, какие столбцы в A равны, например, моему вектору a.
Моя первая попытка будет:
> which(a==A)
[1] 1 2 3 4 5 6
Который не делал этого. (Слишком честно, я даже не понимаю, что это сделал) Вторая попытка была:
a==A
a b c
[1,] TRUE TRUE FALSE
[2,] TRUE TRUE FALSE
[3,] TRUE TRUE FALSE
что определенно является шагом в правильном направлении, но кажется расширенным в матрицу. Я бы предпочел что-то вроде одной из строк. Как сравнить вектор со столбцами и как найти столбцы в матрице, которые равны вектору?
4 ответа
Если вы добавите дополнительную строку:
> A
a b c
[1,] 1 1 4 4
[2,] 2 2 5 2
[3,] 3 3 6 1
Тогда вы можете увидеть, что эта функция верна:
> hasCol=function(A,a){colSums(a==A)==nrow(A)}
> A[,hasCol(A,a)]
a b
[1,] 1 1
[2,] 2 2
[3,] 3 3
Но более ранняя принятая версия не делает:
> oopsCol=function(A,a){colSums(a==A)>0}
> A[,oopsCol(A,a)]
a b
[1,] 1 1 4
[2,] 2 2 2
[3,] 3 3 1
Он возвращает столбец 4,2,1, потому что 2 соответствует 2 в 1,2,3.
Использование identical
, Это оператор скалярного сравнения R; он возвращает единственное логическое значение, а не вектор.
apply(A, 2, identical, a)
# a b c
# TRUE TRUE FALSE
Если A
это фрейм данных в вашем реальном случае, вам лучше использовать sapply
или же vapply
так как apply
принуждает его вводить в матрицу.
d <- c("a", "b", "c")
B <- data.frame(a, b, c, d)
apply(B, 2, identical, a) # incorrect!
# a b c d
# FALSE FALSE FALSE FALSE
sapply(B, identical, a) # correct
# a b c d
# TRUE TRUE FALSE FALSE
Но учтите, что data.frame
Приводит ввод символов к факторам, если вы не спросите иначе:
sapply(B, identical, d) # incorrect
# a b c d
# FALSE FALSE FALSE FALSE
C <- data.frame(a, b, c, d, stringsAsFactors = FALSE)
sapply(C, identical, d) # correct
# a b c d
# FALSE FALSE FALSE TRUE
Идентичность также значительно быстрее, чем при использовании all
+ ==
:
library(microbenchmark)
a <- 1:1000
b <- c(1:999, 1001)
microbenchmark(
all(a == b),
identical(a, b))
# Unit: microseconds
# expr min lq median uq max
# 1 all(a == b) 8.053 8.149 8.2195 8.3295 17.355
# 2 identical(a, b) 1.082 1.182 1.2675 1.3435 3.635
Конечно, есть лучшее решение, но работает следующее:
> a <- c(1,2,3)
> b <- c(1,2,3)
> c <- c(4,5,6)
> A <- cbind(a,b,c)
> sapply(1:ncol(A), function(i) all(a==A[,i]))
[1] TRUE TRUE FALSE
И чтобы получить индексы:
> which(sapply(1:ncol(A), function(i) all(a==A[,i])))
[1] 1 2
colSums(a==A)==nrow(A)
Переработка ==
марки a
эффективно матрица, которая имеет все столбцы, равные a
и размеры равны тем из A
, colSums
суммирует каждый столбец; в то время как TRUE
ведет себя как 1 и FALSE
как 0, столбцы равны a
будет иметь сумму, равную количеству строк. Мы используем это наблюдение, чтобы окончательно свести ответ к логическому вектору.
РЕДАКТИРОВАТЬ:
library(microbenchmark)
A<-rep(1:14,1000);c(7,2000)->dim(A)
1:7->a
microbenchmark(
apply(A,2,function(b) identical(a,b)),
apply(A,2,function(b) all(a==b)),
colSums(A==a)==nrow(A))
# Unit: microseconds
# expr min lq median
# 1 apply(A, 2, function(b) all(a == b)) 9446.210 9825.6465 10278.335
# 2 apply(A, 2, function(b) identical(a, b)) 9324.203 9915.7935 10314.833
# 3 colSums(A == a) == nrow(A) 120.252 121.5885 140.185
# uq max
# 1 10648.7820 30588.765
# 2 10868.5970 13905.095
# 3 141.7035 162.858