Literary Data: Some Approaches Andrew Goldstone http://www.rci.rutgers.edu/~ag978/litdata April 23, 2015. Network basics.
# from data("flo", package="network") flo <- read.csv("network-intro/padgett-florence.csv", row.names=1) # pretty much the same flo <- as.matrix(flo) ▶ Which Florentine clans are linked by marriage? ▶ Guadagni is linked to Albizzi, Bischeri, Lamberteschi… ▶ Medici is linked to Acciaiuoli, Albizzi, Barbadori, …
formally A (simple) graph G is a set V (the vertices) together with a set E of two-element subsets of V (the edges). example: Florentine marriages V {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} E {{1,9}, {2,6}, {2,7}, {2,9}, {3,5}, {3,9}, {4,7}, {4,11}, {4,15}, {5,11}, {5,15}, {7,8}, {7,16}, {9,13}, {9,14}, {9,16}, {10,14}, {11,15}, {13,15}, {13,16}}
[1] 20 0 # why over 2? sum(flo) / 2 1 1 1 Medici 0 0 Lamberteschi 0 1 0 Guadagni Acciaiuoli Albizzi Barbadori adjacency matrix ▶ number families in alphabetical order ▶ we can represent these ties with a matrix flo ▶ flo[i, j] == 1 iff families i and j intermarried ▶ how many edges?
[1] 20 0 # why over 2? sum(flo) / 2 1 1 1 Medici 0 0 Lamberteschi 0 1 0 Guadagni Acciaiuoli Albizzi Barbadori adjacency matrix ▶ number families in alphabetical order ▶ we can represent these ties with a matrix flo ▶ flo[i, j] == 1 iff families i and j intermarried ▶ how many edges?
t(A) transpose of a matrix A ( A T ij = A ji ) ▶ What do we know about t(flo) ?
(parenthesis on directed graphs) A directed graph G is a set V together with a set E of ordered pairs of distinct elements of V . In general the corresponding adjacency matrix is not symmetric ( A ij ̸ = A ji ). ▶ models asymmetric relations (i.e. most of them)
3 1 Tornabuoni 4 2 3 Strozzi Salviati Ridolfi 0 3 1 Pucci Peruzzi Pazzi 6 4 Bischeri rowSums(flo) Guadagni Lamberteschi 1 3 3 Ginori Castellani Medici 2 3 1 Barbadori Albizzi Acciaiuoli degree ▶ how many families is a given family connected to?
0 1 2 3 4 6 table(rowSums(flo)) 1 4 2 6 2 1 degree distribution
0 1 2 3 4 6 table(rowSums(flo)) 1 4 2 6 2 1 degree distribution
flg <- graph.adjacency(flo, mode="undirected") library("igraph") class(flg) [1] "igraph" a data structure
V(flg) "Pazzi" vcount(flg) "Tornabuoni" [15] "Strozzi" "Salviati" [13] "Ridolfi" "Pucci" [11] "Peruzzi" [9] "Medici" Vertex sequence: "Lamberteschi" [7] "Guadagni" "Ginori" [5] "Castellani" "Bischeri" [3] "Barbadori" "Albizzi" [1] "Acciaiuoli" [1] 16
degree(flg) 6 Tornabuoni 4 2 3 Strozzi Salviati Ridolfi 0 3 1 Pucci Peruzzi Pazzi 1 Acciaiuoli 4 Medici Guadagni Lamberteschi 1 3 3 Ginori Castellani Bischeri 2 3 1 Barbadori Albizzi 3
ecount(flg) [1] 20 E(flg)[1:5] # and 15 more.... Edge sequence: [1] Medici -- Acciaiuoli [2] Ginori -- Albizzi [3] Guadagni -- Albizzi [4] Medici -- Albizzi [5] Castellani -- Barbadori
flg_edges <- get.edgelist(flg) head(flg_edges) [,1] [,2] [1,] "Acciaiuoli" "Medici" [2,] "Albizzi" "Ginori" [3,] "Albizzi" "Guadagni" [4,] "Albizzi" "Medici" [5,] "Barbadori" "Castellani" [6,] "Barbadori" "Medici" alternate representations: edge list
$Bischeri [1] 2 head(flg_adjlist) $Acciaiuoli [1] 9 $Albizzi [1] 6 7 9 $Barbadori [1] 5 9 flg_adjlist <- get.adjlist(flg) [1] 7 11 15 $Castellani [1] 3 11 15 $Ginori alternate representations: adjacency list ▶ graph.edgelist and graph.adjlist constructors exist (and others too)
old_par <- par() par(bg="gray10", fg="white") old_par_igraph <- igraph.options() igraph.options(vertex.label.color="white", vertex.color=NA, vertex.frame.color="white") aside on side-effect graphics ▶ base R graphical parameters: ▶ igraph plotting:
plot(flg) # easy---a little *too* easy Pazzi Salviati Acciaiuoli Ginori Medici Albizzi Tornabuoni Pucci Barbadori Ridolfi Guadagni Lamberteschi Castellani Strozzi Bischeri Peruzzi Figure 1: Our first network visualization
plot(flg) Pucci Lamberteschi Guadagni Bischeri Ginori Albizzi Peruzzi Tornabuoni Strozzi Ridolfi Castellani Medici Acciaiuoli Barbadori Salviati Pazzi Figure 2: The same, again?
plot(flg, edge.curved=T) Pazzi Salviati Ginori Acciaiuoli Medici Albizzi Pucci Tornabuoni Barbadori Ridolfi Guadagni Lamberteschi Strozzi Castellani Bischeri Peruzzi Figure 3: Uh…
plot(flg, layout=layout.fruchterman.reingold) Castellani Peruzzi Barbadori Pazzi Strozzi Salviati Ridolfi Bischeri Medici Tornabuoni Pucci Acciaiuoli Guadagni Albizzi Lamberteschi Ginori Figure 4: Still the same
plot(flg, layout=layout.circle) Castellani Ginori Bischeri Guadagni Barbadori Lamberteschi Albizzi Medici Acciaiuoli Pazzi Tornabuoni Peruzzi Strozzi Pucci Salviati Ridolfi Figure 5: Not not not different
plot(flg, layout=layout.random) Lamberteschi Ridolfi Strozzi Acciaiuoli Guadagni Albizzi Tornabuoni Pazzi Salviati Pucci Ginori Barbadori Castellani Bischeri Medici Peruzzi Figure 6: The idea of eternal return
set.seed(297) # otherwise non-deterministic # plot igraph object g with xyz layout plot(g, layout=layout.xyz) help("plot.igraph") help("igraph.plotting")
2.5137724 -1.22933776 [2,] [6,] [5,] -1.4483593 -0.09440367 [4,] -0.6464960 -1.91466136 0.58689322 [3,] -0.4090781 1.4642171 -0.91076618 1.31148122 coords <- layout.kamada.kawai(flg) 0.7265483 [1,] [,2] [,1] # 2 columns of coordinates head(coords) a “stat”
vs <- data_frame(family=V(flg)$name, x=coords[ , 1], y=coords[ , 2]) edges <- get.edgelist(flg, names=F) y1=coords[edges[ , 1], 2], x2=coords[edges[ , 2], 1], y2=coords[edges[ , 2], 2]) geom_point(size=15, shape=1, color="white") + geom_text(aes(label=family), color="white") aes(x=x1, y=y1, xend=x2, yend=y2), color="white") the grammar of the network graphic es <- data_frame(x1=coords[edges[ , 1], 1], p <- ggplot(vs, aes(x, y)) + p <- p + geom_segment(data=es,
p + plot_theme() Pucci 2 Pazzi Acciaiuoli Salviati Barbadori y Medici 0 Castellani Ridolfi Tornabuoni Strozzi Albizzi Ginori Peruzzi Guadagni Bischeri -2 Lamberteschi -2 -1 0 1 2 x Figure 7: The same, still, but with ggplot
heat_p <- get.adjacency(flg, sparse=F) %>% as.data.frame() %>% # matrix to frame mutate(ego=rownames(.)) %>% # family names as a column gather("alter", "weight", -ego) %>% ggplot(aes(ego, alter)) + geom_tile(aes(fill=weight)) + xlab("") + ylab("") or back to the adjacency matrix ▶ geom_tile : fill in squares at x , y aesthetics ▶ with color given by fill aesthetic ▶ and blank where there’s no data (sometimes useful, sometimes better to fill in zeroes)
heat_p + plot_theme() + theme(legend.position="none") Tornabuoni Strozzi Salviati Ridolfi Pucci Peruzzi Pazzi Medici Lamberteschi Guadagni Ginori Castellani Bischeri Barbadori Albizzi Acciaiuoli Acciaiuoli Albizzi Barbadori Bischeri Castellani Ginori Guadagni Lamberteschi Medici Pazzi Peruzzi Pucci Ridolfi Salviati Strozzi Tornabuoni Figure 8: The adjacency matrix, visually. Note the symmetry
neighbors(flg, "Medici") [1] 1 2 3 13 14 16 V(flg)[neighbors(flg, "Medici")] Vertex sequence: [1] "Acciaiuoli" "Albizzi" "Barbadori" [4] "Ridolfi" "Salviati" "Tornabuoni" neighbors ▶ incident(g, v) for edges of g touching a vertex v
sub_flg <- induced.subgraph(flg, c("Medici", "Ridolfi", "Tornabuoni", "Guadagni")) plot(sub_flg) subgraph Guadagni Tornabuoni Ridolfi Medici Figure 9: A subgraph
# returns a list even for one nbhd graph.neighborhood(flg, order=1, "Medici")[[1]] %>% plot() neighborhood subgraph Albizzi Barbadori Acciaiuoli Medici Tornabuoni Salviati Ridolfi Figure 10: A neighborhood order 1: a.k.a. ego network
[1] 2 medicis_gone <- flg - vertex("Medici") plot(medicis_gone) vertex.connectivity(flg2) subtraction Pazzi Salviati Barbadori Ridolfi Castellani Tornabuoni Strozzi Ginori Peruzzi Albizzi Bischeri Guadagni Lamberteschi Acciaiuoli Pucci Figure 11: Ciao, Lorenzo connectivity The vertex connectivity is iff you can remove any vertices and the graph is still connected (but no more than ). Guadagni Albizzi Bischeri Tornabuoni Peruzzi Medici Strozzi Ridolfi Castellani Figure 12: Well-connected families
cliques(flg) # all complete subgraphs largest.cliques(flg) # list of vertex numbers flg_clq <- largest.cliques(flg) plot(flg, mark.groups=flg_clq, vertex.label=NA) cliques Figure 13: The cliques, highlighted
weighted edges assign a number A ij ≥ 0 to each relation between vertices
Recommend
More recommend