Comparați doi vectori de caractere în R (Programare, R, Diagrama Venn)

Aslan986 a intrebat.

Am doi vectori de caractere de ID-uri.

Aș dori să compar cei doi vectori de caractere, în special mă interesează următoarele cifre:

  • Câte ID-uri sunt atât în A cât și în B
  • Câte ID-uri se află în A, dar nu și în B
  • Câte ID-uri se află în B, dar nu și în A

Mi-ar plăcea, de asemenea, să desenez o diagramă Venn.

Comentarii

  • a se vedea ??intersect și ??setdiff… –  > Por agstudy.
  • vezi Diagrame Venn cu R? –  > Por topchef.
  • nu este aceasta o utilizare incorectă a termenului „listă” în R? Este vorba doar de doi vectori. Nu este deloc același lucru. –  > Por emilBeBri.
  • @Florian Sunt de acord că „list” este incorect în termeni R, dar este ceea ce OP a crezut că este corect. Dacă și alții au aceeași idee greșită și caută de pe google, ar putea ateriza corect aici. Din acest motiv, de obicei sunt conservator în corectarea termenilor greșiți din întrebări. Oricum, doar ceva de care poate să țineți cont dacă vă aflați în plină campanie de editare. (Btw, folosesc „set” într-un răspuns de mai jos, pentru că, din punct de vedere conceptual, așa este tratat vectorul aici). –  > Por Frank.
6 răspunsuri
Mittenchops

Iată câteva noțiuni de bază pe care să le încerci:

> A = c("Dog", "Cat", "Mouse")
> B = c("Tiger","Lion","Cat")
> A %in% B
[1] FALSE  TRUE FALSE
> intersect(A,B)
[1] "Cat"
> setdiff(A,B)
[1] "Dog"   "Mouse"
> setdiff(B,A)
[1] "Tiger" "Lion" 

În mod similar, ați putea obține numărători pur și simplu ca:

> length(intersect(A,B))
[1] 1
> length(setdiff(A,B))
[1] 2
> length(setdiff(B,A))
[1] 2

Frank

De obicei, am de-a face cu seturi mari, așa că folosesc un tabel în loc de o diagramă Venn:

xtab_set <- function(A,B){
    both    <-  union(A,B)
    inA     <-  both %in% A
    inB     <-  both %in% B
    return(table(inA,inB))
}

set.seed(1)
A <- sample(letters[1:20],10,replace=TRUE)
B <- sample(letters[1:20],10,replace=TRUE)
xtab_set(A,B)

#        inB
# inA     FALSE TRUE
#   FALSE     0    5
#   TRUE      6    3

Comentarii

  • Ah, nu mi-am dat seama că diagramele Venn conțin numere… credeam că trebuie să arate elementele în sine. –  > Por Frank.
Teemu Daniel Laajala

Încă o altă modalitate, cu ajutorul %în%. și vectori booleeni de elemente comune în loc de intersect și setdiff. Să înțeleg că doriți de fapt să comparați două vectoriși nu doi liste – a listă este o clasă R care poate conține orice tip de element, în timp ce vectorii conțin întotdeauna elemente de un singur tip, de unde rezultă o comparație mai ușoară a ceea ce este cu adevărat egal. Aici, elementele sunt transformate în șiruri de caractere, deoarece acesta era cel mai inflexibil tip de element prezent.

first <- c(1:3, letters[1:6], "foo", "bar")
second <- c(2:4, letters[5:8], "bar", "asd")

both <- first[first %in% second] # in both, same as call: intersect(first, second)
onlyfirst <- first[!first %in% second] # only in 'first', same as: setdiff(first, second)
onlysecond <- second[!second %in% first] # only in 'second', same as: setdiff(second, first)
length(both)
length(onlyfirst)
length(onlysecond)

#> both
#[1] "2"   "3"   "e"   "f"   "bar"
#> onlyfirst
#[1] "1"   "a"   "b"   "c"   "d"   "foo"
#> onlysecond
#[1] "4"   "g"   "h"   "asd"
#> length(both)
#[1] 5
#> length(onlyfirst)
#[1] 6
#> length(onlysecond)
#[1] 4

# If you don't have the 'gplots' package, type: install.packages("gplots")
require("gplots")
venn(list(first.vector = first, second.vector = second))

După cum s-a menționat, există mai multe opțiuni pentru reprezentarea grafică a Diagramelor Venn în R. Iată rezultatul obținut cu ajutorul gplots.

rferrisx

Cu sqldf: Mai lent, dar foarte potrivit pentru cadrele de date cu tipuri mixte:

t1 <- as.data.frame(1:10)
t2 <- as.data.frame(5:15)
sqldf1 <- sqldf('SELECT * FROM t1 EXCEPT SELECT * FROM t2') # subset from t1 not in t2 
sqldf2 <- sqldf('SELECT * FROM t2 EXCEPT SELECT * FROM t1') # subset from t2 not in t1 
sqldf3 <- sqldf('SELECT * FROM t1 UNION SELECT * FROM t2') # UNION t1 and t2

sqldf1  X1_10
1
2
3
4
sqldf2   X5_15
11
12
13
14
15
sqldf3   X1_10
1
2 
3 
4 
5 
6 
7
8
9
10
11
12
13      
14
15

milan

Folosind același exemplu de date ca unul dintre răspunsurile de mai sus.

A = c("Dog", "Cat", "Mouse")
B = c("Tiger","Lion","Cat")

match(A,B)
[1] NA  3 NA

La match returnează un vector cu locația în B a tuturor valorilor din A. Deci, cat, al doilea element din A, este al treilea element din B. Nu există alte corespondențe.

Pentru a obține valorile corespunzătoare din A și B, se poate face:

m <- match(A,B)
A[!is.na(m)]
"Cat"
B[m[!is.na(m)]]
"Cat"

Pentru a obține valorile care nu se potrivesc în A și B:

A[is.na(m)]
"Dog"   "Mouse"
B[which(is.na(m))]
"Tiger" "Cat"

În continuare, puteți utiliza length() pentru a obține numărul total de valori corespunzătoare și necorespunzătoare.

mpag

Dacă A este un data.table cu câmpul a de tip listă, cu intrările în sine ca vectori de tip primitiv, de exemplu, creat după cum urmează

A<-data.table(a=c(list(c("abc","def","123")),list(c("ghi","zyx"))),d=c(9,8))

și B este o listă cu un vector de intrări de tip primitiv, de exemplu, creat după cum urmează

B<-list(c("ghi","zyx"))

și încercați să aflați care (dacă există) element din A$a se potrivește cu B

A[sapply(a,identical,unlist(B))]

dacă doriți doar intrarea din a

A[sapply(a,identical,unlist(B)),a]

dacă doriți indiciile care se potrivesc din a

A[,which(sapply(a,identical,unlist(B)))]

dacă, în schimb, B este el însuși un data.table cu aceeași structură ca și A, de ex.

B<-data.table(b=c(list(c("zyx","ghi")),list(c("abc","def",123))),z=c(5,7))

și căutați intersecția celor două liste cu o singură coloană, în cazul în care aveți nevoie de aceeași ordine a elementelor vectorului.

# give the entry in A for in which A$a matches B$b
A[,`:=`(res=unlist(sapply(list(a),function(x,y){
                                      x %in% unlist(lapply(y,as.vector,mode="character"))
                                  },list(B[,b]),simplify=FALSE)))
  ][res==TRUE
  ][,res:=NULL][] 

# get T/F for each index of A
A[,sapply(list(a),function(x,y){
                      x %in% unlist(lapply(y,as.vector,mode="character"))
                  },list(B[,b]),simplify=FALSE)]

Rețineți că nu puteți face ceva la fel de simplu ca și cum ar fi

setkey(A,a)
setkey(B,b)
A[B]

să unești A&B, deoarece nu poți introduce o cheie pe un câmp de tip list în data.table 1.12.2

în mod similar, nu puteți cere

A[a==B[,b]]

chiar dacă A și B sunt identice, deoarece == nu a fost implementat în R pentru tipul list

Comentarii

  • Baza R + data.table nu are o funcție numită simplify. Poate puneți apelurile necesare la library() înainte de celălalt cod? –  > Por Frank.
  • Mulțumesc pentru captură. Se pare că face parte din purrr, care este o componentă a tidyverse-ului lui Hadley. Se pare că este doar un apel la unlist în acest context, așa că va înlocui –  > Por mpag.