3
votes

comparer plusieurs colonnes et créer le nombre de correspondances

J'ai un ensemble de données avec des numéros d'identification pour les amis et les intimidateurs des répondants.

Je voudrais passer en revue toutes les nominations d'amitié et toutes les nominations d'intimidateurs dans chaque rangée et obtenir un compte du nombre de personnes qu'ils nomment comme les deux. Toute aide serait formidable!

AVOIR DES DONNÉES:

ID  friend_1  friend_2  friend_3  bully_1  bully_2  num_both
1          4        12         7       12       15         1
2          8         6         7       18       20         0
3          9        18         1        2        1         1
4         15         7         2        7       13         1
5          1        17         9       17        1         2
6          9        19        20       14       12         0
7         19        12        20        9       12         1
8          7         1        16        2       15         0
9          1        10        12        1        7         1
10         7        11         9       11        7         2

VOULEZ DES DONNÉES:

ID  friend_1  friend_2  friend_3  bully_1  bully_2
1          4        12         7       12       15
2          8         6         7       18       20
3          9        18         1        2        1
4         15         7         2        7       13 
5          1        17         9       17        1
6          9        19        20       14       12
7         19        12        20        9       12
8          7         1        16        2       15 
9          1        10        12        1        7
10         7        11         9       11        7


0 commentaires

4 Réponses :


3
votes

Nous pouvons utiliser apply par ligne et connaître le nombre d'amis communs qui sont présents à la fois dans les colonnes friend et bully XXX


Ou si vous n'êtes pas un grand fan de apply , vous pouvez utiliser sapply avec la même logique

apply(df, 1, function(x) sum(!is.na(intersect(x[friend_cols], x[bully_cols]))))

S'il y a des valeurs NA et que nous voulons les exclure, nous pouvons utilisez is.na et sum

friend_cols <- grep("friend", names(df))
bully_cols <- grep("bully", names(df))

sapply(seq_len(nrow(df)), function(i) 
 length(intersect(df[i, friend_cols, drop = TRUE], df[i, bully_cols, drop = TRUE])))

#[1] 1 0 1 1 2 0 1 0 1 2


2 commentaires

Hey, merci! Je pense que la version d'application est presque là, mais elle compte les NA en rangées où certaines des observations ont moins de nominations que d'autres. Une idée comment puis-je m'assurer que les NA sont ignorés lors du comptage des matchs?


nous pouvons utiliser sum et is.na pour ignorer les correspondances NA . J'ai mis à jour la réponse.



1
votes

Vous pouvez essayer de comparer chaque colonne intimidateur avec les colonnes d'amis, puis de prendre l'union pour calculer une matrice de correspondances. Pour obtenir votre num_both il vous suffit de rowSum cette matrice de correspondance:

#   ID friend_1 friend_2 friend_3 bully_1 bully_2 num_both
#1   1        4       12        7      12      15        1
#2   2        8        6        7      18      20        0
#3   3        9       18        1       2       1        1
#4   4       15        7        2       7      13        1
#5   5        1       17        9      17       1        2
#6   6        9       19       20      14      12        0
#7   7       19       12       20       9      12        1
#8   8        7        1       16       2      15        0
#9   9        1       10       12       1       7        1
#10 10        7       11        9      11       7        2

Le lapply calcule les correspondances pour chaque bully puis le Réduire les combine en une seule matrice à additionner sur les lignes.

bully_cols <- grep("bully", names(df))
friend_cols <- grep("friend", names(df))
df$num_both <- rowSums(Reduce("|", lapply(df[,bully_cols], function(x, compare) compare == x, compare = df[,friend_cols])))


0 commentaires

3
votes

En supposant que les valeurs sont uniques au sein des groupes d'amis / intimidateurs, une approche simple serait:

apply(df[,-1], 1, function (x) sum(table(x) > 1)) 
[1] 1 0 1 1 2 0 1 0 1 2


0 commentaires

0
votes

Voici une approche basée sur melt à partir de data.table . Nous fondons dans un format 'long' basé sur les modèles dans les noms de colonne (commencez par ami , intimidateur ) , groupé par 'ID', obtenez la longueur des éléments intersect des longues colonnes de l'ensemble de données 'value1', 'value2' et effectuez une jointure sur code > le 'ID'

df1 <- structure(list(ID = 1:10, friend_1 = c(4L, 8L, 9L, 15L, 1L, 9L, 
19L, 7L, 1L, 7L), friend_2 = c(12L, 6L, 18L, 7L, 17L, 19L, 12L, 
1L, 10L, 11L), friend_3 = c(7L, 7L, 1L, 2L, 9L, 20L, 20L, 16L, 
12L, 9L), bully_1 = c(12L, 18L, 2L, 7L, 17L, 14L, 9L, 2L, 1L, 
11L), bully_2 = c(15L, 20L, 1L, 13L, 1L, 12L, 12L, 15L, 7L, 7L
)), class = "data.frame", row.names = c(NA, -10L))

Ou en utilisant tidyverse en rassembler au format 'long', groupé par 'ID' , résumer avec la longueur de intersecter les éléments de «valeur» en fonction de l'occurrence de «ami» ou «intimidateur» dans la clé « 'et right_join avec l'ensemble de données d'origine

df1 %>% 
     mutate(num_both = pmap(.[-1], ~ c(...) %>%
                                 {length(intersect(.[1:3], .[4:5]))}))

ou une autre approche en bouclant les lignes avec pmap

library(tidyverse)
df1 %>% 
   gather(key, value, -ID) %>% 
   group_by(ID) %>% 
   summarise(num_both = length(intersect(value[str_detect(key, 'friend')], 
                         value[str_detect(key, 'bully')]))) %>% 
   right_join(df1)
# A tibble: 10 x 7
#      ID num_both friend_1 friend_2 friend_3 bully_1 bully_2
#   <int>    <int>    <int>    <int>    <int>   <int>   <int>
# 1     1        1        4       12        7      12      15
# 2     2        0        8        6        7      18      20
# 3     3        1        9       18        1       2       1
# 4     4        1       15        7        2       7      13
# 5     5        2        1       17        9      17       1
# 6     6        0        9       19       20      14      12
# 7     7        1       19       12       20       9      12
# 8     8        0        7        1       16       2      15
# 9     9        1        1       10       12       1       7
#10    10        2        7       11        9      11       7

données

library(data.table)
setDT(df1)[melt(df1, measure = patterns('^friend', '^bully'))[,
   .(num_both = length(intersect(value1, value2))), ID], on = .(ID)]
#    ID friend_1 friend_2 friend_3 bully_1 bully_2 num_both
# 1:  1        4       12        7      12      15        1
# 2:  2        8        6        7      18      20        0
# 3:  3        9       18        1       2       1        1
# 4:  4       15        7        2       7      13        1
# 5:  5        1       17        9      17       1        2
# 6:  6        9       19       20      14      12        0
# 7:  7       19       12       20       9      12        1
# 8:  8        7        1       16       2      15        0
# 9:  9        1       10       12       1       7        1
#10: 10        7       11        9      11       7        2


0 commentaires