2017-10-12 1 views
0

J'ai deux colonnes de chaînes dans une trame de données, et pour chaque ligne, je veux voir les caractères qui diffèrent.Extraction par ligne de caractères qui diffèrent entre deux chaînes

donné par exemple

Lines <- " 
a  b 
cat car 
dog ding 
cow haw" 
df <- read.table(text = Lines, header = TRUE, as.is = TRUE) 

retour

a  b  diff 
cat car t 
dog ding o 
cow haw co 

J'ai vu

Extract characters that differ between two strings

ainsi que

Split comma-separated column into separate rows

où un certain nombre de solutions soignées sont retournées, qui travaillerait pour une ligne individuelle (première référence), ou agir ligne sage, mais pas exactement ce que je veux (deuxième référence).

Idéalement, je voudrais utiliser quelque chose comme ceci:

Reduce(setdiff, strsplit(c(a, b), split = "")) 

J'ai essayé:

apply(df, function(a,b) Reduce(setdiff, strsplit(c(a, b), split = ""))) 

mais en vain.

Comment cela peut-il être fait?

p.s. Je suis particulièrement désireux de le faire en utilisant dplyr si possible, mais seulement pour des raisons stylistiques

+1

Votre exemple n'est pas reproductible. S'il vous plaît envisager d'utiliser 'dput'. Par exemple, nous verrons si vous avez réellement des vecteurs de caractères ou factorisez dans vos colonnes, ce qui est une source de confusion courante. – lmo

Répondre

2

En supposant df indiquées dans la note reproductible à la fin définissent une fonction Diff qui accepte deux vecdors de cordes, court le setdiff sur eux et pâtes le résultat ensemble, puis utilisez mapply pour exécuter cela sur les deux colonnes après les avoir divisées en caractères individuels.

Diff <- function(x, y) paste(setdiff(x, y), collapse = "") 
transform(df, diff = mapply(Diff, strsplit(a, ""), strsplit(b, ""))) 

donnant:

a b diff 
1 cat car t 
2 dog ding o 
3 cow haw co 

Note: L'entrée df utilisé ci-dessus est la suivante:

Lines <- " 
a  b 
cat car 
dog ding 
cow haw" 
df <- read.table(text = Lines, header = TRUE, as.is = TRUE) 
0

Voici une autre méthode de base R à l'aide Map.

diffList <- Map(setdiff, strsplit(dat[[1]], ""), strsplit(dat[[2]], "")) 
diffList 
[[1]] 
[1] "t" 

[[2]] 
[1] "o" 

[[3]] 
[1] "c" "o" 

Vous pouvez envelopper cela dans sapply pour retourner un vecteur de caractère pour vos données.cadre:

dat$charDiffs <-sapply(diffList, paste, collapse="") 

qui retourne

dat 
    a b charDiffs 
1 cat car   t 
2 dog ding   o 
3 cow haw  co 

données (de dput)

dat <- 
structure(list(a = c("cat", "dog", "cow"), b = c("car", "ding", 
"haw")), .Names = c("a", "b"), row.names = c(NA, -3L), class = "data.frame") 
1

Une solution de tidyverse et stringr.

library(tidyverse) 
library(stringr) 

dt2 <- dt %>% 
    mutate(a_list = str_split(a, pattern = ""), b_list = str_split(b, pattern = "")) %>% 
    mutate(diff = map2(a_list, b_list, setdiff)) %>% 
    mutate(diff = map_chr(diff, ~paste(., collapse = ""))) %>% 
    select_if(~!is.list(.)) 
dt2 
# A tibble: 3 x 3 
     a  b diff 
    <chr> <chr> <chr> 
1 cat car  t 
2 dog ding  o 
3 cow haw co 

DONNÉES

dt <- read.table(text = "a  b 
cat car 
       dog ding 
       cow haw", 
       header = TRUE, stringsAsFactors = FALSE) 
1

En utilisant dplyr

library(dplyr) 
ff = data.frame(a = c("dog","chair","love"),b = c("dot","liar","over"),stringsAsFactors = F) 
st = ff %>% mutate(diff = sapply(Map(setdiff,strsplit(a,""),strsplit(b,"")),paste,collapse = "")) 

> st 
     a b diff 
1 dog dot g 
2 chair liar ch 
3 love over l