Более быстрый многоколонный цикл распознавания частичных строк в R

Я хочу создать быструю функцию, которая возвращает true или false, если строка символов, содержащаяся в одном столбце, совпадает с одним из моих столбцов. Значение true или false должно быть зарегистрировано в столбцах с индивидуальным именем. Ниже приведен пример структуры данных:

df = data.frame(Authors, A1, A2 [... all the way A63])
# Example of "Authors" column row values: ("A1, A12, A50")
# All other columns equal: NA
# Note: "Authors" has millions of rows.

У меня есть вложенный цикл, который распознает имя автора "A1" из столбца, который часто содержит несколько таких "Авторы" / "df[,1]" (Пример: "A1, A12, A50") и возвращает "True" в столбец, названный в честь конкретного автора ("A12"), если имя автора содержится в этой строке (альтернативно, "False"). Вот медленный вложенный цикл, который достигает желаемого результата:

for (i in 2:length(df)){
    for (j in 1:nrow(df)) {
df[j,i]= ifelse(grepl(df[j,1],colnames(df[i])), TRUE, FALSE)}}
# Intended result df[2,2] = "True" if df[2,1] = ("A1, A2, A50"), otherwise "False".

Вышеописанное работает, но мучительно медленно. У меня миллионы строк. Любые указатели относительно того, как я мог бы ускорить это?

Изменить: ниже, как выглядит мой dataframe через dput:

structure(list(Authurs = c("A. Trevor Thrall", "A. Trevor Thrall", 
"A. Trevor Thrall", "A. Trevor Thrall, Benjamin H. Friedman", 
"A. Trevor Thrall, Benjamin H. Friedman", "A. Trevor Thrall, Benjamin H. Friedman, Christopher A. Preble, Peter Russo", 
"A. Trevor Thrall, Caroline Dorminey", "A. Trevor Thrall, Caroline Dorminey", 
"A. Trevor Thrall, Caroline Dorminey", "A. Trevor Thrall, Caroline Dorminey", 
"A. Trevor Thrall, Caroline Dorminey", "A. Trevor Thrall, Caroline Dorminey", 
"A. Trevor Thrall, Caroline Dorminey", "A. Trevor Thrall, Caroline Dorminey", 
"A. Trevor Thrall, Caroline Dorminey"), `Jeffrey A. Singer` = c(NA_character_, 
NA_character_, NA_character_, NA_character_, NA_character_, NA_character_, 
NA_character_, NA_character_, NA_character_, NA_character_, NA_character_, 
NA_character_, NA_character_, NA_character_, NA_character_), 
    `Caroline Dorminey` = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_
    ), `Eric Gomez` = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_
    ), `John Samples` = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_
    ), `Emma Ashford` = c(NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_, 
    NA_character_, NA_character_, NA_character_, NA_character_
    )), row.names = c(NA, 15L), class = "data.frame")

1 ответ

Решение

Я изменил ваш объектный фрагмент так, чтобы он имел некоторые реальные хиты.

df <- 
structure(list(Authors = c("A. Trevor Thrall", "A. Trevor Thrall", 
"A. Trevor Thrall", "A. Trevor Thrall, Benjamin H. Friedman", 
"A. Trevor Thrall, Benjamin H. Friedman", "A. Trevor Thrall, Benjamin H. Friedman, Christopher A. Preble, Peter Russo", 
"A. Trevor Thrall, Caroline Dorminey", "A. Trevor Thrall, Caroline Dorminey", 
"A. Trevor Thrall, Caroline Dorminey", "A. Trevor Thrall, Caroline Dorminey", 
"A. Trevor Thrall, Caroline Dorminey", "A. Trevor Thrall, Caroline Dorminey", 
"A. Trevor Thrall, Caroline Dorminey", "A. Trevor Thrall, Caroline Dorminey", 
"A. Trevor Thrall, Caroline Dorminey"), `A. Trevor Thrall` = c(TRUE, 
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 
TRUE, TRUE, TRUE), `Benjamin H. Friedman` = c(FALSE, FALSE, FALSE, 
TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
FALSE, FALSE), `Christopher A. Preble` = c(FALSE, FALSE, FALSE, 
FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
FALSE, FALSE, FALSE), `Peter Russo` = c(FALSE, FALSE, FALSE, 
FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 
FALSE, FALSE, FALSE), `Caroline Dorminey` = c(FALSE, FALSE, FALSE, 
FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 
TRUE, TRUE)), row.names = c(NA, 15L), class = "data.frame")

Теперь, когда есть некоторые хиты, попробуйте это:

df[-1] <- lapply(names(df[-1]), function(nm) grepl(nm, df[[1]]))

Он перебирает все имена столбцов, отличных от "Авторы", и устанавливает значение "ИСТИНА" или "ЛОЖЬ" в зависимости от того, есть ли в столбце "Авторы" grepl-попадание. Я думаю, это то, что вы просили, и я уверяю вас, это будет намного быстрее, чем двойной вложенный цикл с ifelse тестирование. Я исключил внутренний цикл и заменил его векторной операцией. Внешний цикл практически не изменился, так как lapply а также sapply оба действительно эквивалентны для цикла с точки зрения скорости. Это алгоритм внутри цикла, который имеет значение.

Другие вопросы по тегам