Creating and Analyzing a New Network
I am using a data set that is somewhat similar in structure to that of my final project. After recovering data from thousands of New York Times articles pulled through their API on Afghanistan from a 2-year period, I will be analyzing the network of article authorship and themes of articles. To understand the process, I am using for my assignment a data set of co-writers of songs played by the Grateful Dead over their 30-year touring career that I compiled. One aspect of the Grateful Dead song data is that the connections between co-writers is weighted, with the weights representing the number of time each song was played live.
Understanding this as an affiliation network, I created a matrix linking actors (songwriters) to an event (songs). I began by assigning a unique ID to each actor and event. Taking the data I have pulled from my research, I created an affiliation spreadsheet with the songwriters as rows and the songs as columns. When a songwriter was affiliated with a song, there was a number in that matrix spot. However, I struggled to get this affiliation data into a network in R, so I took a different approach.
In this example, I used a node list where unique IDs are numbers which correspond to the name of the songwriter. The edgelist is in a separate spreadsheet where the first two columns are the IDs of the source and the target node, regardless of whether the network is directed, for each edge. The following columns are edge attributes (weight, type, label, or anything else). In my edgelist, I have the two songwriters representing the relationship in columns “1” and “2”, the song ID in column “3”, the song name in column “4”, and the weight in column “5”.
Converting network data into igraph objects using the “graph.data.frame: function, which takes two data frames: d and vertices.
“d” describes the edges of the network and “vertices” the nodes.
set.seed(1234)
grateful_data <- graph_from_data_frame(d = gd_edgelist, vertices = gd_vertices, directed = FALSE)
Now to check the vertices and edges in the graph I’ve created to ensure they represent the data accurately, and confirm that all of the attributes have been represented properly:
head(V(grateful_data)$name)
head(E(grateful_data)$song.id)
head(E(grateful_data)$song.name)
head(E(grateful_data)$weight)
is_directed(grateful_data)
is_weighted(grateful_data)
is_bipartite(grateful_data)
igraph::vertex_attr_names(grateful_data)
igraph::edge_attr_names(grateful_data)
Next I want to take a first look at the network:
plot(grateful_data)
It’s basically plotting what I want it to illustrate, though I will need to do a lot more work to make the graph represent anything meaningful!
Finishing the look at the basic network information such as the dyad and triad census:
igraph::dyad.census(grateful_data)
$mut
[1] 555
$asym
[1] 0
$null
[1] -230
igraph::triad.census(grateful_data)
[1] 2043 0 233 0 0 0 0 0 0 0 237 0 0
[14] 0 0 87
Knowing this network has 26 vertices, I want to see if the triad census is working correctly by comparing the following data, which I can confirm it is here!
#possible triads in network
26*25*24/6
[1] 2600
sum(igraph::triad.census(grateful_data))
[1] 2600
Looking next at the global v. average local transitivity of the network:
#get global clustering cofficient: igraph
transitivity(grateful_data, type="global")
[1] 0.5240964
#get average local clustering coefficient: igraph
transitivity(grateful_data, type="average")
[1] 0.7755587
This transitivity tells me that the average network transitivity is significantly higher than the global transitivity, indicating, from my still naive network knowledge, that the overall network is generally more loose, and that there is a more connected sub-network.
Looking at the geodesic distance tells me that on average, the path length is just over 2.
average.path.length(grateful_data,directed=F)
[1] 2.01
Getting a look at the components of the network shows that there are 2 components in the network, and 25 of the 26 nodes make up the giant component with 1 isolate.
names(igraph::components(grateful_data))
[1] "membership" "csize" "no"
igraph::components(grateful_data)$no
[1] 2
igraph::components(grateful_data)$csize
[1] 25 1
This is a great start - now I can get to looking at the network density, centrality, and centralization.
The network density measure: First with just the call “graph.density” and then with adding “loops=TRUE”. Since I’m using igraph, I know that its’ default output assumes that loops are not included but does not remove them, which can be corrected with the addition of “loops=TRUE” per the course tutorials when comparing output to statnet. This gives me confidence that my network density is closer to 1.58.
graph.density(grateful_data)
[1] 1.707692
graph.density(grateful_data, loops=TRUE)
[1] 1.581197
The network degree measure: This gives me a clear output showing the degree of each particular node (songwriter). It is not suprising, knowing my subject matter, that Jerry Garcia is the highest degree node in this network as the practical and figurative head of the band. The other band members’ degree measures are not necessarily what I expected, though. I did not anticipate that his songwriting partner, Robert Hunter, would have a lower degree than band members Phil Lesh and Bob Weir. Further, I did not anticipate that the degree measure of band member ‘Pigpen’ would be so high given his early death in the first years of the band’s touring life.
igraph::degree(grateful_data)
Eric Andersen John Barlow Bob Bralove Andrew Charles
1 30 12 1
John Dawson Willie Dixon Jerry Garcia Donna Godchaux
2 2 215 16
Keith Godchaux Gerrit Graham Frank Guida Mickey Hart
19 1 2 23
Bruce Hornsby Robert Hunter Bill Kreutzmann Ned Lagin
4 134 119 1
Phil Lesh Peter Monk Brent Mydland Dave Parker
158 1 24 10
Robert Petersen Pigpen Joe Royster Rob Wasserman
5 119 2 10
Bob Weir Vince Welnick
188 11
To look further I will create a dataframe for easier review going forward.
grateful_nodes<-data.frame(name=V(grateful_data)$name, degree=igraph::degree(grateful_data))
grateful_nodes
name degree
Eric Andersen Eric Andersen 1
John Barlow John Barlow 30
Bob Bralove Bob Bralove 12
Andrew Charles Andrew Charles 1
John Dawson John Dawson 2
Willie Dixon Willie Dixon 2
Jerry Garcia Jerry Garcia 215
Donna Godchaux Donna Godchaux 16
Keith Godchaux Keith Godchaux 19
Gerrit Graham Gerrit Graham 1
Frank Guida Frank Guida 2
Mickey Hart Mickey Hart 23
Bruce Hornsby Bruce Hornsby 4
Robert Hunter Robert Hunter 134
Bill Kreutzmann Bill Kreutzmann 119
Ned Lagin Ned Lagin 1
Phil Lesh Phil Lesh 158
Peter Monk Peter Monk 1
Brent Mydland Brent Mydland 24
Dave Parker Dave Parker 10
Robert Petersen Robert Petersen 5
Pigpen Pigpen 119
Joe Royster Joe Royster 2
Rob Wasserman Rob Wasserman 10
Bob Weir Bob Weir 188
Vince Welnick Vince Welnick 11
A quick look at the summary statistics confirms for me the minimum, maximum, median, and mean node degree data.
summary(grateful_nodes)
name degree
Length:26 Min. : 1.00
Class :character 1st Qu.: 2.00
Mode :character Median : 10.50
Mean : 42.69
3rd Qu.: 28.50
Max. :215.00
hist(grateful_nodes$degree, main="Grateful Dead Network Distribution", xlab="Node Level")
There is a lot more to do, but this is a great start!
Citations:
Allan, Alex; Grateful Dead Lyric & Song Finder: https://whitegum.com/~acsa/intro.htm
ASCAP. 18 March 2022.
Dodd, David; The Annotated Grateful Dead Lyrics: http://artsites.ucsc.edu/gdead/agdl/
Schofield, Matt; The Grateful Dead Family Discography: http://www.deaddisc.com/
This information is intended for private research only, and not for any commercial use. Original Grateful Dead songs are ©copyright Ice Nine Music