Моя цель - найти индексы строк матрицы (dat
), которые содержат совпадающие строки другой матрицы (xy
).
Я считаю, что это легко сделать с меньшими матрицами, как показано в примерах. Но в матрицах у меня очень большое количество строк.
Для примера ниже приведены матрицы dat
и xy
. Задача - восстановить индексы 14, 58, 99. В моем случае обе эти матрицы имеют очень большее количество строк.
# toy data
dat <- iris
dat$Sepal.Length <- dat$Sepal.Length * (1 + runif (150))
xy <- dat[c(14, 58, 99), c(1, 5)]
Для небольших матриц решения были бы
# solution 1
ind <- NULL
for(j in 1 : length(x)) {
ind[j] <- which((dat$Sepal.Length ==xy[j, 1]) & (dat$Species == xy[j, 2]))
}
Или
# solution 2
which(outer(dat$Sepal.Length, xy[, 1], "= = ") &
outer(dat$Species, xy[, 2], "= = "), arr.ind=TRUE)
Но, учитывая размер моих данных, эти методы неосуществимы. Первый метод занимает много времени, а второй не работает из-за нехватки памяти.
Хотел бы я узнать больше о data.table
и dplyr
.
Это могло быть обманом. Я действительно хорошо посмотрел, но все же, возможно, я это пропустил.
Вы можете попробовать это решение dplyr
. Зависит от размера ваших фреймов данных.
#use dplyr filter
library(dplyr)
dat %>%
mutate(row_no = row_number()) %>%
filter(Sepal.Length %in% xy$Sepal.Length & Species %in% xy$Species) %>%
select(row_no)
#> row_no
#> 1 14
#> 2 58
#> 3 99
Спасибо. Я попробую и вернусь. В dat
примерно полмиллиона строк.
Я использовал paste0 () для объединения Sepal.Length и Species во временную переменную.
Затем соответствие(), чтобы вернуть индекс совпадений между двумя временными переменными.
Тогда нет, '!', is.na (), чтобы удалить несовпадения и преобразовать в логический вектор.
Затем верните который(), индексы верны.
which(!is.na(match(paste0(dat$Sepal.Length, dat$Species), paste0(xy$Sepal.Length, xy$Species))))
[1] 14 58 99
PS: merge () принимает комбинированные переменные в by.x и by.y:
merge(dat, xy, by.x=c("Sepal.Length", "Species"), by.y=c("Sepal.Length", "Species"), all.x=FALSE, all.y=TRUE)
Следуя предложению chinsoon12, попробуйте следующее:
library(dplyr)
dat$rowind <- 1:nrow(dat) # adds row index if wanted (not necessary though)
newDf <- semi_join(dat, xy, by = c("Species", "Sepal.Length"))
Для предоставленной вами настройки вы можете использовать:
library(tidyverse)
dat %>%
mutate(row_num = row_number()) %>%
inner_join(xy, by = c("Sepal.Length", "Species")) %>%
pull(row_num)
Это добавляет столбец для начального номера строки, выполняет внутреннее соединение для создания фрейма данных со строками в dat, которые соответствуют строкам из xy, а затем извлекает индексы. (Внутреннее соединение вернет все строки из dat, которые соответствуют строкам из xy, а полусоединение вернет только одну строку из dat для каждой строки в xy.)
Стоит отметить, что в этом примере мы имеем дело с фреймами данных, а не с матрицами:
> class(xy)
[1] "data.frame"
> class(dat)
[1] "data.frame"
Приведенный выше код не будет работать, если данные находятся в матричной форме - можете ли вы преобразовать свои матрицы во фреймы данных или таблицы?
Спасибо. Да, их можно преобразовать в data.frame или tibble.
если ваши данные огромны, вы можете сначала хэшировать свои строки (для обеих матриц), а затем сопоставить значения хэша строк, используя пакет дайджеста.
target_matrix<-iris
query_matrix<-iris[c(14, 58, 99),]
target_row_hash<-apply(target_matrix,1,digest)
query_row_hash<-apply(query_matrix,1,digest)
row_nums<-match(query_row_hash,target_row_hash)
row_nums
14 58 99
С data.table это соединение:
library(data.table)
setDT(dat); setDT(xy)
dat[xy, on=names(xy), which=TRUE]
# [1] 14 58 99
Похоже на обман. Вы можете использовать соединение, чтобы найти точные совпадения. Что-то вроде xy [dat, on =. (Длина, виды)]