Заменить символьную строку на основе отдельного списка / фрейма данных R - PullRequest
0 голосов
/ 13 марта 2019

Я пытаюсь сделать что-то, что, как мне показалось, будет довольно простым, что поставит меня в тупик.

Скажем, у меня есть следующий фрейм данных:

id <- c("bob_geldof", "billy_bragg", "melvin_smith")
code <- c("blah", "di", "blink")
df <- as.data.frame(cbind(id,code))

> df
             id  code
1    bob_geldof  blah
2   billy_bragg    di
3  melvin_smith blink

И еще один такой:

ID1 <- c("bob_geldof", "melvin_smith")
ID2 <- c("the_builder", "kelvin")
alternates <- as.data.frame(cbind(ID1, ID2))

> alternates
            ID1         ID2
1    bob_geldof the_builder
2  melvin_smith      kelvin

Если строка символов в df $ id совпадает с альтернативами $ ID1, я хотел бы заменить ее альтернативами $ ID2. Если он не совпадает, я бы хотел оставить все как есть.

Конечный df должен выглядеть как

> df
               id   code
1 bob_the_builder   blah
2     billy_bragg     di
3   melvin_kelvin  blink

Это явно глупый пример, и мой настоящий набор данных требует много замен.

Я включил столбец «код», чтобы продемонстрировать, что я работаю с фреймом данных, а не только с символьным вектором.

Я использовал gsub для их индивидуальной замены, но это отнимает много времени, и список постоянно меняется.

Я посмотрел в str_replace, но, кажется, вы можете указать только одно значение замены.

Любая помощь будет принята с благодарностью.

Ура!

РЕДАКТИРОВАТЬ: не все идентификаторы содержат подчеркивания, и мне нужно сохранить бит, который соответствует. Например. bob_geldolf становится bob_the_builder.

РЕДАКТИРОВАТЬ 2 (!): Спасибо всем за ваши предложения. Я обошёл проблему, объединив фреймы данных (так что есть NA, в которых нет изменений) и создав новые идентификаторы с помощью оператора ifelse. Это немного неуклюже, но это работает!

Ответы [ 2 ]

0 голосов
/ 13 марта 2019

Следующее решение использует base-R и немного упрощено.Шаг 1: объедините основные "df" и "альтернативные" df вместе, используя левое соединение.Шаг 2: проверьте, где значение ID2 не пропущено (NA), а затем присвойте эти значения «id».Это сохранит ваш оригинальный идентификатор, где это возможно;и замените его на ID2, если эти совпадающие идентификаторы доступны

Решение:

combined <- merge(x=df,y=alternates,by.x="id",by.y="ID1",all.x=T)
combined$id[!is.na(combined$ID2)] <- combined$ID2[!is.na(combined$ID2)]

С полными исходными определениями фрейма данных (с использованием stringsAsFactors = F):

id <- c("bob_geldof", "billy_bragg", "melvin_smith")
code <- c("blah", "di", "blink")
df <- as.data.frame(cbind(id,code),stringsAsFactors = F)

ID1 <- c("bob_geldof", "melvin_smith")
ID2 <- c("the_builder", "kelvin")
alternates <- as.data.frame(cbind(ID1, ID2),stringsAsFactors = F)

combined <- merge(x=df,y=alternates,by.x="id",by.y="ID1",all.x=T)
combined$id[!is.na(combined$ID2)] <- combined$ID2[!is.na(combined$ID2)]

Результаты: (полное слияние ниже, вы также можете сделать combined[,c("id","code")] для упорядоченных результатов).Здесь несоответствующий "billy_bragg" сохраняется;а остальные заменены на совпадающие ID

> combined
           id  code         ID2
1 billy_bragg    di        <NA>
2 the_builder  blah the_builder
3      kelvin blink      kelvin
0 голосов
/ 13 марта 2019

При создании dataframes используйте stringsAsFactors = FALSE, чтобы не иметь дело с факторами. Затем, если строки упорядочены, просто примените:

df <- as.data.frame(cbind(id,code),stringsAsFactors = FALSE)
alternates <- as.data.frame(cbind(ID1, ID2),stringsAsFactors = FALSE)

df$id[c(TRUE,FALSE)]=paste(gsub("(.*)(_.*)","\\1",df$id[c(TRUE,FALSE)]),
                         alternates$ID2,sep="_")

> df
               id  code
1 bob_the_builder  blah
2     billy_bragg    di
3   melvin_kelvin blink

Если они неупорядочены, мы можем использовать dlyr:

df%>%rowwise()%>%mutate(id=if_else(length(which(alternates$ID1==id))>0,
                                  paste(gsub("(.*)(_.*)","\\1",id),
                                        alternates$ID2[which(alternates$ID1==id)],sep="_"),
                                  id))
# A tibble: 3 x 2
  id              code 
  <chr>           <chr>
1 bob_the_builder blah 
2 billy_bragg     di   
3 melvin_kelvin   blink

Мы используем ту же логику, что и раньше. Здесь мы проверяем df по строке. Если id соответствует любому из alternatives$ID1 (проверено length()), мы обновляем его.

...