У меня есть два фрейма данных. Первый выглядит так:

month     Joanne K. Rowling   Samuel L. Jackson
2000/01   1                   0
2000/02   1                   1
2000/03   0                   1
2000/04   0                   0
2000/05   0                   1
2000/06   1                   0

test_1 <-data.frame ("Месяц" = c ("2000/01", "2000/02", "2000/03", "2000/04", "2000/05", "2000/06"), «Джоан К. Роулинг» = c (1,1,0,0,0,1), «Сэмюэл Л. Джексон» = c (0,1,1,0,1,0))

Другой выглядит так

Name            Score
Samuel Jackson  67
Joanne Rowling  52

test_2 <-data.frame ("Name" = c ("Сэмюэл Джексон", "Джоан Роулинг"), "Score" = c (67,52))

Я хотел бы объединить их, чтобы получить следующий фрейм данных

month     Joanne K. Rowling   Samuel L. Jackson
2000/01   52                   0
2000/02   52                   67
2000/03   0                    67
2000/04   0                    0
2000/05   0                    67
2000/06   52                   0

Где значение 1 заменяется баллом в test_2. Имена столбцов из test_1 могут незначительно отличаться от значений в таблице_2, поэтому совпадение не должно быть исправлено. Я нашел способ сделать это:

for(i in 1:nrow(test_2)) {
  for(k in 1:ncol(test_1){
    for(l in 1:nrow(test_1)){
      if(grepl(test_2[i,6],as.data.frame(colnames(test_1))[k,1])) {
        if(test_1[l,k]==1){
          test_1[l,k]<-test_2[i,5]
        }
      }
    }
  }
}

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

-1
Edoardo Poli 28 Мар 2021 в 17:02

2 ответа

Лучший ответ

Я не думаю, что grepl будет работать здесь напрямую, поскольку 'Joanne Rowling' не будет соответствовать 'Joanne K. Rowling'. Вы можете использовать stringdist::stringdistmatrix, чтобы получить совпадения, а затем умножить соответствующие значения.

mat <- stringdist::stringdistmatrix(names(test_1)[-1], test_2$Name)
test_1[-1] <- sweep(test_1[-1], 2, test_2$Score[max.col(-mat)], `*`)
test_1

#    Month Joanne K. Rowling Samuel L. Jackson
#1 2000/01                52                 0
#2 2000/02                52                67
#3 2000/03                 0                67
#4 2000/04                 0                 0
#5 2000/05                 0                67
#6 2000/06                52                 0

Чтобы применить это к нескольким фреймам данных, вы можете:

lapply(test_1_list, function(x) {
  mat <- stringdist::stringdistmatrix(names(x)[-1], test_2$Name)
  x[-1] <- sweep(x[-1], 2, test2$Score[max.col(-mat)], `*`)
  x
}) -> result
result

Где test_1_list - это список фреймов данных.

данные

test_1<-data.frame("Month"=c("2000/01","2000/02","2000/03","2000/04","2000/05","2000/06"),
                   "Joanne K. Rowling"=c(1,1,0,0,0,1),
                   "Samuel L. Jackson"=c(0,1,1,0,1,0), check.names = FALSE)
test_2<-data.frame("Name"=c("Samuel Jackson","Joanne Rowling"),"Score"=c(67,52))
1
Ronak Shah 30 Мар 2021 в 10:37

Вы можете использовать функцию replace и определить вектор индекса, который решает, какие значения должны быть заменены:

# Just for JK Rowling
test_1[,2] <- replace(test_1[,2], test_1[,2] == 1, test_2[2,2])

test_1[,2] == 1 создает вектор индекса, который равен TRUE для единиц и FALSE для нулей.

Тогда можно было бы просто продублировать линию для Сэмюэля Джексона.

0
nikpau 28 Мар 2021 в 14:29