At the beginning of the semester, when we first read about the peer nomination studies using the Fraternity Data (Carolan, 2014, Chapters 5 and 6), I emailed Dr. Kellogg to ask if I could approximate this study within my own context as a teacher. As anyone at my school will tell you, I have a particularly “interesting” ecosystem within my classroom, with many conflicting personalities/emotions. I was interested to see how my perceptions of the classroom dynamics mirrored or differed from the students’ perceptions. As the adult in the room, I often sense that a student is seeking another student’s attention and being rebuffed and/or manipulated by that other student. I wanted to see if these patterns of interaction would be captured in the friendship nomination. Therefore, I arrived at the following research questions:
RQ1: To what degree do students reciprocate friendship nominations as measured by lunch-buddy nominations?
RQ2: Do friendship nominations/friendship groups, as measured by measures of transitivity (formation of triads) change over time?
As a proxy for “friendship nomination,” I asked my students to write down the names of three students from our class with whom they would most want to sit at lunch. Students created valued data by listing students 1 to 3, with 1 being “most” desired and 3 being “want to sit next to.” When converting this data into the square datasets shown below, however, I inverted this so that 3 is “most desired,” 1 is “want to sit next to,” and 0 is “no nomination present.”
I collected these data points three times throughout the semester. Unfortunately, the beginning six-ish weeks of the semester were significantly impacted by COVID, so I was not able to start data collection until well into the semester. Therefore, the data may be impacted by the reduced timespan.
My target audience is primarily myself because I am using this information to guide my understanding of my classroom dynamics, and it will influence how I group students for projects, seating, and in-class peer support. My secondary audience is my school counselor, with whom I will share the data, and who can use the results to create small group interventions for friend-making and social support.
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✓ ggplot2 3.3.5 ✓ purrr 0.3.4
## ✓ tibble 3.1.6 ✓ dplyr 1.0.8
## ✓ tidyr 1.2.0 ✓ stringr 1.4.0
## ✓ readr 2.1.2 ✓ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(ggraph)
library(tidygraph)
##
## Attaching package: 'tidygraph'
## The following object is masked from 'package:stats':
##
## filter
library(igraph)
##
## Attaching package: 'igraph'
## The following object is masked from 'package:tidygraph':
##
## groups
## The following objects are masked from 'package:dplyr':
##
## as_data_frame, groups, union
## The following objects are masked from 'package:purrr':
##
## compose, simplify
## The following object is masked from 'package:tidyr':
##
## crossing
## The following object is masked from 'package:tibble':
##
## as_data_frame
## The following objects are masked from 'package:stats':
##
## decompose, spectrum
## The following object is masked from 'package:base':
##
## union
library(ggthemes)
library(statnet)
## Loading required package: tergm
## Loading required package: ergm
## Loading required package: network
##
## 'network' 1.17.1 (2021-06-12), part of the Statnet Project
## * 'news(package="network")' for changes since last version
## * 'citation("network")' for citation information
## * 'https://statnet.org' for help, support, and other information
##
## Attaching package: 'network'
## The following objects are masked from 'package:igraph':
##
## %c%, %s%, add.edges, add.vertices, delete.edges, delete.vertices,
## get.edge.attribute, get.edges, get.vertex.attribute, is.bipartite,
## is.directed, list.edge.attributes, list.vertex.attributes,
## set.edge.attribute, set.vertex.attribute
##
## 'ergm' 4.1.2 (2021-07-26), part of the Statnet Project
## * 'news(package="ergm")' for changes since last version
## * 'citation("ergm")' for citation information
## * 'https://statnet.org' for help, support, and other information
## 'ergm' 4 is a major update that introduces some backwards-incompatible
## changes. Please type 'news(package="ergm")' for a list of major
## changes.
## Loading required package: networkDynamic
##
## 'networkDynamic' 0.11.1 (2022-04-04), part of the Statnet Project
## * 'news(package="networkDynamic")' for changes since last version
## * 'citation("networkDynamic")' for citation information
## * 'https://statnet.org' for help, support, and other information
## Registered S3 method overwritten by 'tergm':
## method from
## simulate_formula.network ergm
##
## 'tergm' 4.0.2 (2021-07-28), part of the Statnet Project
## * 'news(package="tergm")' for changes since last version
## * 'citation("tergm")' for citation information
## * 'https://statnet.org' for help, support, and other information
##
## Attaching package: 'tergm'
## The following object is masked from 'package:ergm':
##
## snctrl
## Loading required package: ergm.count
##
## 'ergm.count' 4.0.2 (2021-06-18), part of the Statnet Project
## * 'news(package="ergm.count")' for changes since last version
## * 'citation("ergm.count")' for citation information
## * 'https://statnet.org' for help, support, and other information
## Loading required package: sna
## Loading required package: statnet.common
##
## Attaching package: 'statnet.common'
## The following object is masked from 'package:ergm':
##
## snctrl
## The following objects are masked from 'package:base':
##
## attr, order
## sna: Tools for Social Network Analysis
## Version 2.6 created on 2020-10-5.
## copyright (c) 2005, Carter T. Butts, University of California-Irvine
## For citation information, type citation("sna").
## Type help(package="sna") to get started.
##
## Attaching package: 'sna'
## The following objects are masked from 'package:igraph':
##
## betweenness, bonpow, closeness, components, degree, dyad.census,
## evcent, hierarchy, is.connected, neighborhood, triad.census
## Loading required package: tsna
##
## 'statnet' 2019.6 (2019-06-13), part of the Statnet Project
## * 'news(package="statnet")' for changes since last version
## * 'citation("statnet")' for citation information
## * 'https://statnet.org' for help, support, and other information
library(readr)
Time_1_Sheet1 <- read_csv("Time 1 - Sheet1.csv")
## Rows: 20 Columns: 20
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (20): 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
library(readr)
Time_2_Sheet1 <- read_csv("Time 2 - Sheet1.csv")
## Rows: 20 Columns: 20
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (20): 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
library(readr)
Time_3_04_14_Sheet1 <- read_csv("Time 3_ 04.14 - Sheet1.csv")
## Rows: 20 Columns: 20
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## dbl (20): 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Time_3_04_14_Sheet1
## # A tibble: 20 × 20
## `1` `2` `3` `4` `5` `6` `7` `8` `9` `10` `11` `12` `13`
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0 0 0 0 0 0 0 2 0 0 0 0 0
## 2 0 0 0 2 0 0 0 0 0 0 0 0 1
## 3 0 0 0 3 2 0 0 1 0 0 0 0 0
## 4 0 0 3 0 0 0 0 0 0 0 0 0 1
## 5 1 0 0 0 0 0 0 0 0 0 0 0 0
## 6 0 0 0 0 0 0 3 0 0 0 0 0 1
## 7 0 0 0 0 0 0 0 3 0 0 0 0 0
## 8 0 0 0 1 0 0 3 0 0 0 0 0 0
## 9 0 0 0 0 0 0 0 0 0 0 0 0 0
## 10 0 1 2 0 0 0 3 0 0 0 0 0 0
## 11 1 0 0 0 0 0 0 0 0 0 0 0 0
## 12 0 0 2 1 0 0 0 0 0 0 0 0 0
## 13 0 1 0 2 0 0 0 0 0 0 0 0 0
## 14 0 2 0 3 0 0 0 0 0 0 0 0 1
## 15 0 0 1 2 0 0 0 0 0 0 0 3 0
## 16 0 0 0 0 0 0 0 0 0 0 0 0 0
## 17 3 0 0 0 0 0 0 2 0 0 0 0 0
## 18 0 0 0 0 2 0 0 0 0 0 0 0 0
## 19 0 0 0 0 2 0 0 0 0 0 3 0 0
## 20 1 0 0 0 0 0 3 0 0 2 0 0 0
## # … with 7 more variables: `14` <dbl>, `15` <dbl>, `16` <dbl>, `17` <dbl>,
## # `18` <dbl>, `19` <dbl>, `20` <dbl>
In order to maintain anonymity, I am not using actual student names. Therefore, I have assigned each student a number and will be using this to track each student’s nominations.
colnames(Time_1_Sheet1) <- 1:20
rownames(Time_1_Sheet1) <- 1:20
## Warning: Setting row names on a tibble is deprecated.
colnames(Time_2_Sheet1) <- 1:20
rownames(Time_2_Sheet1) <- 1:20
## Warning: Setting row names on a tibble is deprecated.
colnames(Time_3_04_14_Sheet1) <- 1:20
rownames(Time_3_04_14_Sheet1) <- 1:20
## Warning: Setting row names on a tibble is deprecated.
Simply because I find the assigned names from R cumbersome, I am renaming each dataset with a more succinct title.
Time1 <- Time_1_Sheet1
Time2 <- Time_2_Sheet1
Time3 <- Time_3_04_14_Sheet1
In order to be able to work with the data more easily, I need to convert the datasets to matrices and graph objects. This will allow me to complete the analyses that I intend.
Time1_matrix <- as.matrix(Time1)
Time2_matrix <- as.matrix(Time2)
Time3_matrix <- as.matrix(Time3)
Time1_matrix
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
## 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 1 0 0 0
## 2 0 0 0 2 0 0 1 0 3 0 0 0 0 0 0 0 0 0 0 0
## 3 0 0 0 3 2 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
## 4 0 0 3 0 0 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0
## 5 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 3 2 0
## 6 0 0 3 2 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
## 7 0 0 0 0 0 0 0 3 0 2 0 0 0 0 0 1 0 0 0 0
## 8 1 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0
## 9 3 0 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0
## 10 0 0 0 1 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 2
## 11 3 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 1 0 0 0
## 12 0 1 0 2 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0
## 13 0 0 0 2 0 3 0 0 0 0 0 0 0 1 0 0 0 0 0 0
## 14 0 0 0 3 0 0 1 0 0 0 0 0 2 0 0 0 0 0 0 0
## 15 0 2 1 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## 16 0 0 0 0 1 0 0 2 0 0 0 0 0 0 0 0 0 3 0 0
## 17 3 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 1 0 0
## 18 0 0 0 0 3 0 0 2 0 0 0 0 0 0 0 1 0 0 0 0
## 19 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 2 0 1 0 0
## 20 0 1 0 0 0 0 2 0 0 3 0 0 0 0 0 0 0 0 0 0
Time2_matrix
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
## 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 1 3 0 0 0
## 2 0 0 2 0 0 0 0 0 0 0 0 0 0 3 1 0 0 0 0 0
## 3 0 0 0 3 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0
## 4 0 0 3 0 0 0 0 0 0 0 0 0 1 3 0 0 0 0 0 0
## 5 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 1 0
## 6 0 0 3 2 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
## 7 0 0 0 1 0 0 0 3 0 2 0 0 0 0 0 0 0 0 0 0
## 8 0 0 0 0 0 0 3 0 0 1 0 0 0 0 0 0 0 2 0 0
## 9 0 0 3 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 1 0
## 10 0 0 0 0 0 0 3 2 0 0 0 0 0 0 0 0 0 0 0 1
## 11 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 3 0
## 12 0 0 2 1 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0
## 13 0 1 0 2 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0
## 14 0 1 0 3 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0
## 15 0 2 1 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## 16 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 1 0
## 17 3 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0
## 18 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 2 0 0 1 0
## 19 0 0 0 0 2 0 0 0 0 0 3 0 0 0 0 1 0 0 0 0
## 20 0 0 0 0 0 0 2 1 0 3 0 0 0 0 0 0 0 0 0 0
Time3_matrix
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
## 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 1 3 0 0 0
## 2 0 0 0 2 0 0 0 0 0 0 0 0 1 3 0 0 0 0 0 0
## 3 0 0 0 3 2 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
## 4 0 0 3 0 0 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0
## 5 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 2 0
## 6 0 0 0 0 0 0 3 0 0 0 0 0 1 2 0 0 0 0 0 0
## 7 0 0 0 0 0 0 0 3 0 0 0 0 0 0 1 0 0 0 0 2
## 8 0 0 0 1 0 0 3 0 0 0 0 0 0 0 0 2 0 0 0 0
## 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## 10 0 1 2 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0
## 11 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 3 0
## 12 0 0 2 1 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0
## 13 0 1 0 2 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0
## 14 0 2 0 3 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
## 15 0 0 1 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0
## 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## 17 3 0 0 0 0 0 0 2 0 0 0 0 0 0 0 1 0 0 0 0
## 18 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 1 0 0 3 0
## 19 0 0 0 0 2 0 0 0 0 0 3 0 0 0 0 1 0 0 0 0
## 20 1 0 0 0 0 0 3 0 0 2 0 0 0 0 0 0 0 0 0 0
Time1_network <- as_tbl_graph(Time1_matrix, directed = TRUE)
Time2_network <- as_tbl_graph(Time2_matrix, directed = TRUE)
Time3_network <- as_tbl_graph(Time3_matrix, directed = TRUE)
Time1_network
## # A tbl_graph: 20 nodes and 60 edges
## #
## # A directed simple graph with 1 component
## #
## # Node Data: 20 × 1 (active)
## name
## <chr>
## 1 1
## 2 2
## 3 3
## 4 4
## 5 5
## 6 6
## # … with 14 more rows
## #
## # Edge Data: 60 × 3
## from to weight
## <int> <int> <dbl>
## 1 1 8 2
## 2 1 16 3
## 3 1 17 1
## # … with 57 more rows
Time2_network
## # A tbl_graph: 20 nodes and 59 edges
## #
## # A directed simple graph with 1 component
## #
## # Node Data: 20 × 1 (active)
## name
## <chr>
## 1 1
## 2 2
## 3 3
## 4 4
## 5 5
## 6 6
## # … with 14 more rows
## #
## # Edge Data: 59 × 3
## from to weight
## <int> <int> <dbl>
## 1 1 8 2
## 2 1 16 1
## 3 1 17 3
## # … with 56 more rows
Time3_network
## # A tbl_graph: 20 nodes and 54 edges
## #
## # A directed simple graph with 2 components
## #
## # Node Data: 20 × 1 (active)
## name
## <chr>
## 1 1
## 2 2
## 3 3
## 4 4
## 5 5
## 6 6
## # … with 14 more rows
## #
## # Edge Data: 54 × 3
## from to weight
## <int> <int> <dbl>
## 1 1 8 2
## 2 1 16 1
## 3 1 17 3
## # … with 51 more rows
Since ERGMs require binary data, I will create a second dataset with a dichotomized version of the data from Time3. I will only be running the ERGM for the third dataset because we have not learned how to incorporate multi-temporal datasets into ERGMs.
For these data, values of 0 in the original datasets will remain 0 and values of 1, 2, or 3 will become a 1, thereby indicating that a relationship/tie is present.
Time3_matrix[Time3_matrix >= 1] <- 1
Time3_matrix
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
## 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0
## 2 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0
## 3 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
## 4 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0
## 5 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
## 6 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0
## 7 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1
## 8 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0
## 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## 10 0 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
## 11 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0
## 12 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
## 13 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
## 14 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
## 15 0 0 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
## 16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## 17 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0
## 18 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0
## 19 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0
## 20 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0
Time3_network_binary <- as_tbl_graph(Time3_matrix, directed = TRUE)
Time3_network_binary
## # A tbl_graph: 20 nodes and 54 edges
## #
## # A directed simple graph with 2 components
## #
## # Node Data: 20 × 1 (active)
## name
## <chr>
## 1 1
## 2 2
## 3 3
## 4 4
## 5 5
## 6 6
## # … with 14 more rows
## #
## # Edge Data: 54 × 3
## from to weight
## <int> <int> <dbl>
## 1 1 8 1
## 2 1 16 1
## 3 1 17 1
## # … with 51 more rows
adjacency_matrix <- graph.adjacency(Time3_matrix,
diag = FALSE)
class(adjacency_matrix)
## [1] "igraph"
adjacency_matrix
## IGRAPH 01b2fcd DN-- 20 54 --
## + attr: name (v/c)
## + edges from 01b2fcd (vertex names):
## [1] 1 ->8 1 ->16 1 ->17 2 ->4 2 ->13 2 ->14 3 ->4 3 ->5 3 ->8 4 ->3
## [11] 4 ->13 4 ->14 5 ->1 5 ->18 5 ->19 6 ->7 6 ->13 6 ->14 7 ->8 7 ->15
## [21] 7 ->20 8 ->4 8 ->7 8 ->16 10->2 10->3 10->7 11->1 11->17 11->19
## [31] 12->3 12->4 12->15 13->2 13->4 13->14 14->2 14->4 14->13 15->3
## [41] 15->4 15->12 17->1 17->8 17->16 18->5 18->16 18->19 19->5 19->11
## [51] 19->16 20->1 20->7 20->10
student_edges <- get.data.frame(adjacency_matrix) |>
mutate(from = as.character(from)) |>
mutate(to = as.character(to))
student_edges
## from to
## 1 1 8
## 2 1 16
## 3 1 17
## 4 2 4
## 5 2 13
## 6 2 14
## 7 3 4
## 8 3 5
## 9 3 8
## 10 4 3
## 11 4 13
## 12 4 14
## 13 5 1
## 14 5 18
## 15 5 19
## 16 6 7
## 17 6 13
## 18 6 14
## 19 7 8
## 20 7 15
## 21 7 20
## 22 8 4
## 23 8 7
## 24 8 16
## 25 10 2
## 26 10 3
## 27 10 7
## 28 11 1
## 29 11 17
## 30 11 19
## 31 12 3
## 32 12 4
## 33 12 15
## 34 13 2
## 35 13 4
## 36 13 14
## 37 14 2
## 38 14 4
## 39 14 13
## 40 15 3
## 41 15 4
## 42 15 12
## 43 17 1
## 44 17 8
## 45 17 16
## 46 18 5
## 47 18 16
## 48 18 19
## 49 19 5
## 50 19 11
## 51 19 16
## 52 20 1
## 53 20 7
## 54 20 10
student_network <- as.network(student_edges)
class(student_network)
## [1] "network"
summary(student_network ~ edges + mutual)
## edges mutual
## 54 13
set.seed(589)
ergm_mod_1 <-ergm(student_edges ~ edges + mutual)
## Starting maximum pseudolikelihood estimation (MPLE):
## Evaluating the predictor and response matrix.
## Maximizing the pseudolikelihood.
## Finished MPLE.
## Starting Monte Carlo maximum likelihood estimation (MCMLE):
## Iteration 1 of at most 60:
## Optimizing with step length 1.0000.
## The log-likelihood improved by 0.0064.
## Convergence test p-value: < 0.0001. Converged with 99% confidence.
## Finished MCMLE.
## Evaluating log-likelihood at the estimate. Fitting the dyad-independent submodel...
## Bridging between the dyad-independent submodel and the full model...
## Setting up bridge sampling...
## Using 16 bridges: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 .
## Bridging finished.
## This model was fit using MCMC. To examine model diagnostics and check
## for degeneracy, use the mcmc.diagnostics() function.
summary(ergm_mod_1)
## Call:
## ergm(formula = student_edges ~ edges + mutual)
##
## Monte Carlo Maximum Likelihood Results:
##
## Estimate Std. Error MCMC % z value Pr(>|z|)
## edges -2.2512 0.2053 0 -10.966 <1e-04 ***
## mutual 2.2004 0.4629 0 4.754 <1e-04 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Null Deviance: 474.1 on 342 degrees of freedom
## Residual Deviance: 278.6 on 340 degrees of freedom
##
## AIC: 282.6 BIC: 290.2 (Smaller is better. MC Std. Err. = 0.2409)
reciprocity(Time1_network)
## [1] 0.5
transitivity(Time1_network)
## [1] 0.3977901
reciprocity(Time2_network)
## [1] 0.6101695
transitivity(Time2_network)
## [1] 0.3877551
reciprocity(Time3_network)
## [1] 0.4814815
transitivity(Time3_network)
## [1] 0.3624161
centr_degree(Time1_network, mode = "all")
## $res
## [1] 7 6 7 11 8 4 7 10 5 5 4 3 6 5 4 7 5 8 4 4
##
## $centralization
## [1] 0.1385042
##
## $theoretical_max
## [1] 722
centr_degree(Time1_network, mode = "out")
## $res
## [1] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
##
## $centralization
## [1] 0
##
## $theoretical_max
## [1] 380
centr_degree(Time1_network, mode = "in")
## $res
## [1] 4 3 4 8 5 1 4 7 2 2 1 0 3 2 1 4 2 5 1 1
##
## $centralization
## [1] 0.2631579
##
## $theoretical_max
## [1] 380
centr_degree(Time2_network, mode = "all")
## $res
## [1] 7 6 9 10 6 3 7 7 3 6 6 3 5 7 5 6 4 6 8 4
##
## $centralization
## [1] 0.1135734
##
## $theoretical_max
## [1] 722
centr_degree(Time2_network, mode = "out")
## $res
## [1] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 3 3 3
##
## $centralization
## [1] 0.002631579
##
## $theoretical_max
## [1] 380
centr_degree(Time2_network, mode = "in")
## $res
## [1] 4 3 6 7 3 0 4 4 0 3 3 0 2 4 2 3 2 3 5 1
##
## $centralization
## [1] 0.2131579
##
## $theoretical_max
## [1] 380
centr_degree(Time3_network, mode = "all")
## $res
## [1] 7 6 7 10 6 3 7 7 0 4 4 4 7 7 5 5 5 4 6 4
##
## $centralization
## [1] 0.1274238
##
## $theoretical_max
## [1] 722
centr_degree(Time3_network, mode = "out")
## $res
## [1] 3 3 3 3 3 3 3 3 0 3 3 3 3 3 3 0 3 3 3 3
##
## $centralization
## [1] 0.01578947
##
## $theoretical_max
## [1] 380
centr_degree(Time3_network, mode = "in")
## $res
## [1] 4 3 4 7 3 0 4 4 0 1 1 1 4 4 2 5 2 1 3 1
##
## $centralization
## [1] 0.2263158
##
## $theoretical_max
## [1] 380
Time1_network <- Time1_network |>
activate(nodes) |>
mutate(degree = centrality_degree(mode = "all"))
Time2_network <- Time2_network |>
activate(nodes) |>
mutate(degree = centrality_degree(mode = "all"))
Time3_network <- Time3_network |>
activate(nodes) |>
mutate(degree = centrality_degree(mode = "all"))
Time1_network
## # A tbl_graph: 20 nodes and 60 edges
## #
## # A directed simple graph with 1 component
## #
## # Node Data: 20 × 2 (active)
## name degree
## <chr> <dbl>
## 1 1 7
## 2 2 6
## 3 3 7
## 4 4 11
## 5 5 8
## 6 6 4
## # … with 14 more rows
## #
## # Edge Data: 60 × 3
## from to weight
## <int> <int> <dbl>
## 1 1 8 2
## 2 1 16 3
## 3 1 17 1
## # … with 57 more rows
Time2_network
## # A tbl_graph: 20 nodes and 59 edges
## #
## # A directed simple graph with 1 component
## #
## # Node Data: 20 × 2 (active)
## name degree
## <chr> <dbl>
## 1 1 7
## 2 2 6
## 3 3 9
## 4 4 10
## 5 5 6
## 6 6 3
## # … with 14 more rows
## #
## # Edge Data: 59 × 3
## from to weight
## <int> <int> <dbl>
## 1 1 8 2
## 2 1 16 1
## 3 1 17 3
## # … with 56 more rows
Time3_network
## # A tbl_graph: 20 nodes and 54 edges
## #
## # A directed simple graph with 2 components
## #
## # Node Data: 20 × 2 (active)
## name degree
## <chr> <dbl>
## 1 1 7
## 2 2 6
## 3 3 7
## 4 4 10
## 5 5 6
## 6 6 3
## # … with 14 more rows
## #
## # Edge Data: 54 × 3
## from to weight
## <int> <int> <dbl>
## 1 1 8 2
## 2 1 16 1
## 3 1 17 3
## # … with 51 more rows
ggraph(Time1_network, layout = "kk") +
geom_node_point(size = 3) +
geom_node_text(aes(label = name), color = "white", show.legend = FALSE, repel = TRUE) +
geom_edge_link(arrow = arrow(length = unit(3, 'mm')),
end_cap = circle(2, 'mm'),
aes(colour = weight)) +
ggtitle("Time 1 Nominations") +
theme_dark()
ggraph(Time2_network, layout = "kk") +
geom_node_point(size = 3) +
geom_node_text(aes(label = name), color = "white", show.legend = FALSE, repel = TRUE) +
geom_edge_link(arrow = arrow(length = unit(3, 'mm')),
end_cap = circle(2, 'mm'),
aes(colour = weight)) +
ggtitle("Time 2 Nominations") +
theme_dark()
ggraph(Time3_network, layout = "kk") +
geom_node_point(size = 3) +
geom_node_text(aes(label = name), color = "white", show.legend = FALSE, repel = TRUE) +
geom_edge_link(arrow = arrow(length = unit(3, 'mm')),
end_cap = circle(2, 'mm'),
aes(colour = weight)) +
ggtitle("Time 3 Nominations") +
theme_dark()
Time1:
0.5
Time2:
0.6101695
Time3:
0.4814815
Time1:
0.3977901
Time2:
0.3877551
Time3:
0.3624161
As these results indicate, triads were more consistent across the three time periods (i.e. changed less) than reciprocity.
Transitivity measures were much more consistent across the three time periods than the reciprocity measures. At all three times, transitivity values fell between 0.36 and 0.4, whereas reciprocity varied from 0.4814815 to 0.6101695. This is roughly a variance of 13 hundredths (reciprocity) versus a variance of 4 hundredths (transitivity). Overall, this indicates that triads were more consistent throughout the semester than dyads. It does not have any huge implications on my action steps, however, because I am more interested in the students who did not receive any nominations than I am in the formation of triads v. dyads.
Nominations as a proxy for popularity aligned with what I see in the classroom. The most easy going, least judgmental students had the highest number of nominations. This is also visible in the sociograms. Since each student was asked to nominate three other students, I interpret the more “popular” students as those with in-degree nominations > 3 and the less “popular” students as those with nominations < 3. The most “popular” student (measured as highest number of nominations) remained consistent at all three time periods. Below, I have charted any student who received >- 5 nominations at any of the given time periods.
Time1
Time2
Time3
Student 3: 4 nominations
Student 4: 7 nominations
Student 16: 5 nominations
As an aside: I found it interesting that characteristics of popularity do not align with what television and movies depict as popular. The most popular student in my classroom is not the wealthiest, nor the most outspoken, nor does this student put down others or project a superior attitude, which is what television would lead us to believe makes a person popular. Instead, Student 4 is just a genuinely nice kid who gets along well with everyone in class, doesn’t judge others, and is always willing to work with whomever I pair them with. It’s actually kind of reassuring that these are the qualities that my kids look for in a friend.
Interestingly, only Time3 had an isolate. On the day of the nominations, this student was mad and chose not to nominate any other students, writing “none” on the nominations slip. Since no students nominated Student 9, Student 9 appears as an isolate in the Time3 sociogram, creating a two-component network. Although this student did not receive any in-degree nominations in Time2, either, they received two in-degree nominations in Time1. Thus, the fragility and fickle-nature of pre-adolescent friendships is highlighted in these sociograms: when mad, Student 9 neither gave nor received nominations. However, I have to ask myself: did the change between Time1 and Time 2, which decreased Student 9’s nominations from 2 to 0 contribute to the anger at Time3? Sociograms only show results—we must guess as the causes. It is difficult to determine, therefore, if the anger demonstrated at Time3 contributed to the lack of nominations or if the lack of nominations (which were not shared with the students but which reflect classroom dynamics) cause the anger? Most likely the cause and effect were cyclical, each impacting the other.
I conducted centrality measures on each of the three time periods, but overall I did not find the results very informative. The centrality measures were more clearly shown in the sociograms. Overall, however, the three networks are not very centralized, with centralization scores far below the theoretical max. In terms of answering my research questions, however, the sociograms (with the centrality_all scores included) were more informative than the raw data.
Based on the ERGM results, there is overall a low possibility (-2.2512) that a tie will occur between two edges in my network. This makes sense given that I limited the nominations for each student to 3. It would be mathematically difficult for there to be a high probability on inter-class ties when each student could only nominate three others. Therefore, the model’s prediction that future data collection would render low tie probability is accurate and logical.
However, the mutuality estimate of 2.2004 indicates that, if this data were collected again, there would be a medium-high probability that ties within my network would be reciprocated, based upon the dataset at Time3. In other words, the students within my classroom tend to reciprocate friendship nominations more than would be expected by pure chance, suggesting the presence of actual friendships rather than random nominations.
Overall, the analyses conducted in this project confirmed what I intuitively know as a teacher. There were no students who received fewer nominations than I expected, and those who consistently received the fewest nominations were those students that I hypothesized would receive the fewest.
The area that surprised me the most, actually, was that the same student received the most nominations at all three time periods. Since this student has a generally affable disposition, I might pair this student with Student 9 (this isolate in Time3) in order to bring Student 9 more into the social fold of my class.
Additionally, I will share these results with my school counselor. Although we only have six weeks left of school, it is possible that she could create some small group interventions to support the students in my class who received few nominations—particularly Student 9.
Finally, when creating class lists for next year, I will work to make sure that students with few (or no) nominations are paired with at least one other person they perceive as a friend. Although we always try to do this as teachers, it is helpful that I now have concrete data to support my placements.
This study had two major limitations. First, in order to avoid participant fatigue, I limited the number of nominations to 3. By default, this meant that all other 17 students were coded as 0, suggesting “not a friend.” However, in reality I know that this is not true. Had I asked my students to rank each student as either “friend” or “not friend,” probably most students (with the possible exception of Student 9) would have ranked the majority of his/her classmates as a “friend.” Therefore, the ERGM model produced somewhat skewed results. Forced to select only three others, it looks as though there is limited possibility for friendship within my classroom, but in reality, most of my students get along quite well.
Second, since my NCSU semester is much shorter than my school semester, the time spans between nominations were quite short. For all of January and into February, large portions of my class were absent due to COVID quarantines. Therefore, in order to get accurate data, I had to wait until well into the semester before starting data collection. This meant that there were only a few weeks between Time1 and Time2 and only one week between Time2 and Time3. For this reason, I assume, the similarities between Time2 data and Time3 data are more pronounced than the similarities between Time1 and Time2. If I were to conduct this study again, I would collect data in September, January, and May in order to space out the nomination periods. Given COVID, the semester-long nature of this course, and the timing of the public school Spring Break, however, this was not possible.
Finally, the only ethical concern that I had was making sure to anonymize my data. I did this by converting student names into numbers and by avoiding any sort of identifying references when discussing specific students. For example, I did not even specify if a student was male or female when describing their results. This enabled me to maintain completely anonymous data while also allowing me, the teacher, to meaningfully interpret my data and results.
Carolan, Brian. 2014. “Social Network Analysis and Education: Theory, Methods & Applications.” https://doi.org/10.4135/9781452270104.