Поиск строк большой матрицы, которые соответствуют определенным значениям - PullRequest
0 голосов
/ 15 сентября 2018

Моя цель - найти индексы строк матрицы (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.

Ответы [ 6 ]

0 голосов
/ 16 сентября 2018

С data.table это соединение:

library(data.table)
setDT(dat); setDT(xy)

dat[xy, on=names(xy), which=TRUE]
# [1] 14 58 99
0 голосов
/ 15 сентября 2018

если ваши данные огромны, вы можете сначала хэшировать свои строки (для обеих матриц), а затем сопоставлять значения хешей строк, используя пакет дайджеста.

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

0 голосов
/ 15 сентября 2018

Для настройки, которую вы указали, вы можете использовать:

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"

Приведенный выше код не будет работать, если данные представлены в матричной форме. Можете ли вы преобразовать свои матрицы в фреймы данных или таблицы?

0 голосов
/ 15 сентября 2018

Следуя совету 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"))
0 голосов
/ 15 сентября 2018

Я использовал paste0 () для объединения Sepal.Length и Species во временную переменную.

Затем match () , чтобы вернуть индекс совпадений между двумя временными переменными.

Тогда нет, '! ', 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)
0 голосов
/ 15 сентября 2018

Вы можете попробовать это 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...