Сопоставление строк со столбцами и подсчет одинаковых вхождений R - PullRequest
3 голосов
/ 25 марта 2020

У меня есть набор данных, который имеет следующую форму: -

a <- data.frame(X1=c("A", "B", "C", "A", "B", "C"),
                X2=c("B", "C", "C", "A", "A", "B"),
                X3=c("B", "E", "A", "A", "A", "B"),
                X4=c("E", "C", "A", "A", "A", "C"),
                X5=c("A", "C", "C", "A", "B", "B")
               )

И у меня есть другой набор следующей формы: -

b <- data.frame(col_1=c("ASD", "ASD", "BSD", "BSD"),
                col_2=c(1, 1, 1, 1),
                col_3=c(12, 12, 31, 21),
                col_4=("A", "B", "B", "A")
               )

Что я хочу сделать, это взять столбец col_4 из набора b и сопоставить строку в наборе a, чтобы он сказал мне, в какой строке содержится сколько элементов из col_4 в новом столбце. Имя нового столбца не имеет значения.

Например: - Первая и пятая строки в наборе a содержат все элементы col_4 из набора b.

Кроме того, дубликаты не должны быть найдены. Например шестой ряд в наборе a имеет 3 "B" с. Но поскольку col_4 из набора b имеет только два "B" с, он должен указывать мне 2, а не 3.

Ожидаемый результат имеет вид: -

c <- data.frame(X1=c("A", "B", "C", "A", "B", "C"),
                X2=c("B", "C", "C", "A", "A", "B"),
                X3=c("B", "E", "A", "A", "A", "B"),
                X4=c("E", "C", "A", "A", "A", "C"),
                X5=c("A", "C", "C", "A", "B", "B"),
                found=c(4, 1, 2, 2, 4, 2)
               )

Ответы [ 3 ]

6 голосов
/ 25 марта 2020

Мы можем использовать vecsets::vintersect, который заботится о дубликатах.

Используя apply построчно, мы можем посчитать, сколько общих значений существует между b$col4 и каждой строкой в ​​a.

apply(a, 1, function(x) length(vecsets::vintersect(b$col_4, x)))
#[1] 4 1 2 2 4 2
1 голос
/ 25 марта 2020

Еще одна идея для эффективной работы с наборами - считать и сравнивать элемент вхождений из b$col_4 в каждом ряду a:

b1 = c(table(b$col_4))
#b1
#A B 
#2 2

a1 = table(factor(as.matrix(a), names(b1)), row(a))
#a1
#   
#    1 2 3 4 5 6
#  A 2 0 2 5 3 0
#  B 2 1 0 0 2 3

Наконец, укажите наименьшее количество вхождений на элемент (для каждой строки) и сумму:

colSums(pmin(a1, b1))
#1 2 3 4 5 6 
#4 1 2 2 4 2

В случае большего измерения a «data.frame» и других элементов, Matrix::sparseMatrix предлагает подходящая альтернатива:

library(Matrix)

a.fac = factor(as.matrix(a), names(b1))
.i = as.integer(a.fac)
.j = c(row(a))

noNA = !is.na(.i)  ## need to remove NAs manually
.i = .i[noNA]
.j = .j[noNA]

a1 = sparseMatrix(i = .i, j = .j, x = 1L, dimnames = list(names(b1), 1:nrow(a)))

a1
#2 x 6 sparse Matrix of class "dgCMatrix"
#  1 2 3 4 5 6
#A 2 . 2 5 3 .
#B 2 1 . . 2 3

colSums(pmin(a1, b1))
#1 2 3 4 5 6 
#4 1 2 2 4 2
1 голос
/ 25 марта 2020

Опция, использующая data.table:

library(data.table)

#convert a into a long format
m <- melt(setDT(a)[, rn:=.I], id.vars="rn", value.name="col_4")

#order by row number and create an index for identical occurrences in col_4
setorder(m, rn, col_4)[, vidx := rowid(col_4), rn]

#create a similar index for b
setDT(b, key="col_4")[, vidx := rowid(col_4)]

#count occurrences and lookup this count into original data
a[b[m, on=.(col_4, vidx), nomatch=0L][, .N, rn], on=.(rn), found := N]

, вывод:

   X1 X2 X3 X4 X5 rn found
1:  A  B  B  E  A  1     4
2:  B  C  E  C  C  2     1
3:  C  C  A  A  C  3     2
4:  A  A  A  A  A  4     2
5:  B  A  A  A  B  5     4
6:  C  B  B  C  B  6     2
...