4
votes

Existe-t-il une fonction R pour obtenir les arêtes uniques dans un réseau non dirigé (non dirigé)?

Je veux compter le nombre d'arêtes uniques dans un réseau non dirigé, par exemple net

   x  y
1  A  B
2  B  A
3  A  B

Il ne devrait y avoir qu'un seul bord pour cette matrice, car les arêtes AB et BA sont identiques pour le réseau non dirigé.

Pour le réseau dirigé, je peux obtenir le nombre d'arêtes uniques par:

nrow (unique (net [ c ("x", "y"]))

Mais cela ne fonctionne pas pour le réseau non dirigé.


1 commentaires

Vous pouvez tous les classer par ordre alphabétique, puis faire la même analyse, essayer stackoverflow.com/questions/47337732/...


4 Réponses :


2
votes

Essayez ceci,

library(tidyverse)
rev <- function(x){
  unname(sapply(x, function(x) {
    paste(sort(trimws(strsplit(x[1], ',')[[1]])), collapse=',')} ))
}
df <- data.frame(x=c("A", "B", "A"), y = c("B", "A", "B"))
rows <- df %>% 
  mutate(both = c(paste(x, y, sep = ", ")))

unique(rev(rows$both))

Comment cela fonctionne-t-il?

  1. Nous appliquons une fonction à chaque ligne de la trame de données, afin que nous puissions prendre chaque ligne à la fois. Prenez la deuxième rangée du df,

    df <- data.frame(x=c("A", "BC", "A"), y = c("B", "A", "BC"))
    df
       x  y
    1  A  B
    2 BC  A
    3  A BC
    unique(apply(df, 1, function(x) paste(sort(unlist(strsplit(x, " "))),collapse = " ")))
    [1] "A B"  "A BC"
    
  2. Nous avons ensuite divisé ( strsplit ) ceci, et unlist en un vecteur de chaque lettre, (Nous utilisons as.matrix pour isoler les éléments)

    df <- data.frame(x=c("A", "B", "A"), y = c("B", "A", "B"),  z = c("C", "D", "D"))
    unique(apply(df, 1, function(x) paste(sort(unlist(strsplit(x, " "))),collapse = " ")))
    [1] "A B C" "A B D"
    
  3. Utilisez la fonction de tri pour les mettre par ordre alphabétique, puis collez-les ensemble,

    paste(sort(unlist(strsplit(as.matrix(df[2,]), " "))), collapse = " ")
    [1] "A B"
    

Ensuite, la fonction apply fait cela pour toutes les lignes, car nous définissons l'index sur 1, puis utilisons la fonction unique pour identifier les arêtes uniques.

Cela peut être étendu à n variables, par exemple n = 3,

unlist(strsplit(as.matrix(df[2,]), " "))
[1] "B" "A"

Si vous avez besoin de plus de lettres, combinez simplement deux lettres comme suit,

df[2,]
  x y
1 B A

Ancienne version

En utilisant le tidyverse , créez une fonction appelée rev qui peut ordonner nos arêtes, puis utilisez muter pour créer une nouvelle colonne combinant les colonnes x et y, dans un tel comme cela fonctionne bien avec la fonction rev , puis exécutez la nouvelle colonne via la fonction et trouvez les paires uniques.

df <- data.frame(x=c("A", "B", "A"), y = c("B", "A", "B"))
unique(apply(df, 1, function(x) paste(sort(unlist(strsplit(x, " "))),collapse = " ")))
[1] "A B"


1 commentaires

Merci beaucoup! J'ai essayé votre ancienne version et cela a bien fonctionné :)



2
votes

Étant donné que vous travaillez avec des réseaux, une solution igraph :

dat %>% 
  graph_from_data_frame(., directed=FALSE) %>% # convert to undirected graph
  simplify %>%                                 # remove loops / multiple edges
  as_data_frame                                # return remaining edges

Ensuite, utilisez nrow


Explication

library(igraph)

as_data_frame(simplify(graph_from_data_frame(dat, directed=FALSE)))


3 commentaires

Merci! Cette méthode est plus simple :) et moins fastidieuse :)


Et ce qui est préférable d'utiliser cette méthode, c'est qu'elle exclut les arêtes auto-liées, ce qui est super pour moi.


@ZQu; oui, la valeur par défaut est de supprimer les boucles automatiques, bien que vous puissiez choisir de les conserver. Voir l'argument donc f ? Igraph :: simplify



0
votes

Voici une solution sans l'intervention de igraph , le tout dans un seul tube:

df %>%
  group_by(x, y) %>%
  mutate(edge_id = paste(sort(unique(c(x,y))), collapse=" ")) 

Il est possible d'utiliser group_by () code > puis sort () combinaisons de valeurs et paste () dans la nouvelle colonne via mutate () . unique () est utilisé si vous avez de "vrais" doublons (AB, AB entreront dans un groupe).

df = tibble(x=c("A", "B", "A"), y = c("B", "A", "B"))

Lorsque vous avez correctement trié noms d'arêtes dans une nouvelle colonne, il est assez simple de compter les valeurs uniques ou de filtrer les doublons hors de votre bloc de données.
Si vous avez des variables supplémentaires pour les arêtes, ajoutez-les simplement dans le groupe.


0 commentaires

1
votes

Si vous n'utilisez pas {igraph} ou si vous voulez simplement savoir comment le faire proprement sans aucune dépendance ...

Voici vos données ...

simplify_edgelist <- function(el, directed = TRUE, drop_loops = TRUE) {
  stopifnot(ncol(el) == 2)

  if (drop_loops) {
    el <- el[el[, 1] != el[, 2], ]
  }

  if (directed) {
    out <- unique(el)
  } else {
    out <- unique(t(apply(el, 1, sort)))
  }

  colnames(out) <- colnames(el)

  if (is.data.frame(el)) {
    as.data.frame(out, stringsAsFactors = FALSE)
  } else {
    out
  }
}

el2 <- rbind(your_edge_list, 
             data.frame(x = c("C", "C"), y = c("C", "A"), stringsAsFactors = FALSE))
el2
#>   x y
#> 1 A B
#> 2 B A
#> 3 A B
#> 4 C C
#> 5 C A

simplify_edgelist(el2, directed = FALSE)
#>   x y
#> 1 A B
#> 5 A C

et voici une ventilation étape par étape ...

unique(t(apply(your_edge_list, 1, sort)))
#>      [,1] [,2]
#> [1,] "A"  "B"

Si nous lâchons les tuyaux, le noyau ressemble à ceci. .

`%>%` <- magrittr::`%>%`

your_edge_list %>% 
  apply(1L, sort) %>%              # sort dyads
  t() %>%                          # transpose resulting matrix to get the original shape back
  unique() %>%                     # get the unique rows
  as.data.frame() %>%              # back to data frame
  setNames(names(your_edge_list))  # reset column names
#>   x y
#> 1 A B

Et nous pouvons l'envelopper dans une fonction qui 1) gère à la fois dirigée et non dirigée, 2) gère les blocs de données et les matrices (les plus courantes), et 3) peut déposer des boucles ...

your_edge_list <- data.frame(x = c("A", "B", "A"),
                             y = c("B", "A", "B"),
                             stringsAsFactors = FALSE)
your_edge_list
#>   x y
#> 1 A B
#> 2 B A
#> 3 A B


0 commentaires