Using egor to analyse ego-centered network data

Till Krenz

2018-06-19

The egor Object

library(egor)

An egor object contains all data levels associated with ego-centered network analysis, those levels are: ego, alter, alter-alter ties. By providing the egor()-function with data.frames containing data corresponding to these data levels, we construct an egor object. Here is an example of what the data.frames could look like. Pay attention to the ID variables connecting the levels with each other.

data("alters32")
data("egos32")
data("edges32") 
First rows of alter data.
egoID ego.sex age netsize alterID alter.sex alter.age
1 m 36 - 45 20 1 m 46 - 55
1 m 36 - 45 20 2 m 46 - 55
1 m 36 - 45 20 3 m 36 - 45
1 m 36 - 45 20 4 w 0 - 17
1 m 36 - 45 20 5 w 18 - 25
1 m 36 - 45 20 6 m 36 - 45
First rows of ego data.
egoID sex age netsize
1 m 36 - 45 20
2 m 66 - 100 18
3 m 36 - 45 32
4 m 26 - 35 11
5 m 36 - 45 23
6 w 46 - 55 11
First rows of alter-alter tie data.
egoID Source Target weight
1506 10 5 13 1
1726 12 8 15 3
2028 15 1 6 1
1929 13 13 21 3
1308 7 9 15 2
3299 23 5 10 1

All three data.frames contain an egoID identifying a unique ego and connecting their personal data to the alter and alter-alter tie data. The alterID is in the alter data is reused in the alter-alter tie data in the Source and Target columns.

Let’s create an egor object from the data we just loaded.

e1 <- egor(alters.df = alters32,
           egos.df = egos32,
           aaties = edges32,
           ID.vars = list(
             ego = "egoID",
             alter = "alterID",
             source = "Source",
             target = "Target"))
e1
#> # A tibble: 32 x 6
#>    egoID sex   age      netsize .alts                 .aaties             
#>    <int> <fct> <fct>      <int> <list>                <list>              
#>  1     1 m     36 - 45       20 <data.frame [20 x 6]> <data.frame [57 x 3~
#>  2     2 m     66 - 100      18 <data.frame [18 x 6]> <data.frame [55 x 3~
#>  3     3 m     36 - 45       32 <data.frame [32 x 6]> <data.frame [140 x ~
#>  4     4 m     26 - 35       11 <data.frame [11 x 6]> <data.frame [9 x 3]>
#>  5     5 m     36 - 45       23 <data.frame [23 x 6]> <data.frame [94 x 3~
#>  6     6 w     46 - 55       11 <data.frame [11 x 6]> <data.frame [15 x 3~
#>  7     7 m     36 - 45       17 <data.frame [17 x 6]> <data.frame [40 x 3~
#>  8     8 m     0 - 17         8 <data.frame [8 x 6]>  <data.frame [8 x 3]>
#>  9     9 m     36 - 45       13 <data.frame [13 x 6]> <data.frame [15 x 3~
#> 10    10 m     0 - 17        16 <data.frame [16 x 6]> <data.frame [42 x 3~
#> # ... with 22 more rows
#> Independent Sampling design (with replacement)
#> survey::svydesign(~1, data = egor)

An [egor] object is a [tibble] whose top-level columns store the ego attributes, and which has two special nested columns:

Import

There are currently three importing functions that read the data exported from data collection tools from the harddrive and load them as an egor object.

read_openeddi()
read_egoweb()
read_egonet()

There are three functions that help with the transformation of common data formats of ego-centered network data:

onefile_to_egor()
twofiles_to_egor()
threefiles_to_egor()

Manipulate

Manipulating an egor object can be done with base R functions or with dplyr verbs.

Base R

The different data levels of an egor object can be manipulated using square bracket subsetting or the subset() function.

Ego level:

e1[, "age"]
e1[e1$netsize > 15, ]

Alter level:

subset(e1, .alts$alter.sex=="w", unit="alter")

Alter-alter tie level:

subset(e1, .aaties$weight > 1, unit="aatie")

dplyr and purrr

An egor object can be manipulated with dplyr verbs. In combination with the map*() functions from the purrr package the list columns .alts and .aaties can be processed and modified. A few examples:

library(dplyr)
library(purrr)
e1 %>%
  mutate(.alts = map(.alts, ~{
    filter(., alter.sex == "m")
  }))

e1 %>%
  mutate(.aaties = map(.aaties, ~{
    filter(., weight > 1)
  }))

Analyse

Try these function to analyse you egor object.

Summary

summary(e1)
#> 32 Egos/ Ego Networks 
#>  550 Alters 
#> Average Netsize 17.1875 
#> Average Density 0.306741555801806
#> Ego sampling design:
#>   Independent Sampling design (with replacement)
#>   survey::svydesign(~1, data = egor)
#> Alter survey design:
#>   Maximum nominations: Inf

Density

ego_density(e1)
#>  [1] 0.3000000 0.3594771 0.2822581 0.1636364 0.3715415 0.2727273 0.2941176
#>  [8] 0.2857143 0.1923077 0.3500000 0.2435897 0.3714286 0.3523810 0.2272727
#> [15] 0.3508772 0.2904762 0.3190476 0.3602941 0.2571429 0.3856209 0.3333333
#> [22] 0.3777778 0.3052632 0.2761905 0.3083004 0.2666667 0.4117647 0.3157895
#> [29] 0.2875817 0.2857143 0.2571429 0.3602941

Composition

composition(e1, "alter.age") %>%
  head() %>%
  kable()
0 - 17 18 - 25 26 - 35 36 - 45 46 - 55 56 - 65 66 - 100
0.1500000 0.1000000 0.0500000 0.3000000 0.2000000 0.1000000 0.1000000
0.1666667 0.1111111 0.0555556 0.3333333 0.2222222 0.0555556 0.0555556
0.1250000 0.1250000 0.0625000 0.2812500 0.1250000 0.0937500 0.1875000
0.0909091 0.0909091 0.0909091 0.3636364 0.1818182 0.0909091 0.0909091
0.1304348 0.1304348 0.0434783 0.2608696 0.1739130 0.1304348 0.1304348
0.0909091 0.0909091 0.0909091 0.3636364 0.1818182 0.0909091 0.0909091

Diversity

alts_diversity_count(e1, "alter.age")
#>  [1] 7 7 7 7 7 7 7 5 7 7 7 7 7 7 7 7 7 7 7 7 7 6 7 7 7 7 7 7 7 7 7 7
alts_diversity_entropy(e1, "alter.age")
#>  [1] 1.808210 1.724935 1.845635 1.767761 1.853795 1.767761 1.731535
#>  [8] 1.494175 1.732659 1.771016 1.732659 1.767009 1.822618 1.791759
#> [15] 1.767378 1.822618 1.822618 1.731535 1.822618 1.724935 1.791759
#> [22] 1.609438 1.808210 1.822618 1.853795 1.771016 1.724935 1.767378
#> [29] 1.724935 1.767195 1.767009 1.731535

Ego-Alter Homophily (EI-Index)

comp_ei(e1, "alter.age", "age")
#>  [1] 0.4000000 0.8888889 0.4375000 0.8181818 0.4782609 0.6363636 0.2941176
#>  [8] 0.7500000 0.2307692 0.6250000 0.8461538 0.6000000 0.9047619 0.8333333
#> [15] 0.5789474 0.8095238 0.6190476 0.8823529 0.8095238 0.5555556 0.6666667
#> [22] 0.8000000 0.6000000 0.8095238 0.9130435 0.8750000 0.8888889 0.3684211
#> [29] 0.8888889 0.8571429 0.7333333 0.2941176

EI-Index for Alter-Alter Ties

EI(e1, "alter.age") %>%
  head() %>%
  kable()
#> EI-Index: alter.age
ei_sc 0 - 17 18 - 25 26 - 35 36 - 45 46 - 55 56 - 65 66 - 100
-0.1245257 -0.4166667 -0.5319149 NaN -0.0181818 0.0153846 1 -0.500000
-0.2262343 -0.3953488 -0.7066667 NaN -0.2086331 -0.0181818 NaN NaN
0.0471844 1.0000000 0.3293413 1 -0.0781250 0.3170732 1 -0.106383
0.0769231 NaN NaN NaN -0.0769231 1.0000000 NaN NaN
0.0123457 1.0000000 0.1304348 NaN 0.0144928 -0.2408163 1 0.047619
-0.0267380 NaN NaN NaN 0.3170732 -0.5652174 NaN NaN

comp_ply()

comp_ply() applies a user-defined function on an alter attribute and returns a numeric vector with the results. It can be used to apply base R functions like sd(), mean() or functions from other packages.

e2 <- make_egor(15, 32)
comp_ply(e2, "age.years", sd, na.rm = TRUE)
#>  [1] 31.93925 32.26195 30.80359 30.22067 31.30272 32.37045 30.63999
#>  [8] 32.66234 30.72259 32.38268 33.61385 32.38268 34.91375 32.55918
#> [15] 32.47782

Visualize

Clustered Graphs

data("egor32")

# Simplify networks to clustered graphs, stored as igraph objects
graphs <- clustered_graphs(egor32, "age") 

# Visualize
par(mar=c(0,0,0,0))
vis_clustered_graphs(graphs[1:3], 
                     node.size.multiplier = 10, 
                     edge.width.multiplier = 5,
                     label.size = 0.6)


graphs2 <- clustered_graphs(make_egor(400, 200)[1:4], "country") 

vis_clustered_graphs(graphs2[1:4], 
                     node.size.multiplier = 2, 
                     edge.width.multiplier = 15,
                     label.size = 0.6,
                     labels = TRUE)

igraph & network plotting

par(mar=c(0,0,0,0))
purrr::walk(as_igraph(egor32)[1:4], plot)

purrr::walk(as_network(egor32)[1:4], plot)

Shiny App for Visualization

egor_vis_app() starts a Shiny app that allows offers a graphical interface for adjusting the visualization parameters of the networks stored in an egor object.

egor_vis_app(egor32)
egor Vis App

egor Vis App

Conversions

In addition to as_igraph() and as_network() shown in the visualization section there are to conversion functions for egor objects:

as_alts_df() creates a global data frame of all alters.

as_alts_df(egor32, include.ego.vars = TRUE) %>%
  head() %>%
  kable(caption = "First rows of global alters data frame.")
First rows of global alters data frame.
egoID sex age age.years country income .altID sex1 age1 age.years1 country1 income1
1 m 46 - 55 49 Poland 41610 1 w 0 - 17 5 Germany 36135
1 m 46 - 55 49 Poland 41610 2 m 36 - 45 44 Australia 14235
1 m 46 - 55 49 Poland 41610 3 w 66 - 100 68 USA 23725
1 m 46 - 55 49 Poland 41610 4 w 66 - 100 87 Australia 13140
1 m 46 - 55 49 Poland 41610 5 m 66 - 100 94 Australia 4745
1 m 46 - 55 49 Poland 41610 6 w 26 - 35 29 Australia 58400

as_aaties_df() creates a global data frame of alter-alter ties.

as_aaties_df(egor32, include.alt.vars = TRUE) %>%
  head() %>%
  kable(caption = "First rows of global alter-alter tie data frame.")
First rows of global alter-alter tie data frame.
egoID .srcID .tgtID weight src_sex src_age src_age.years src_country src_income tgt_sex tgt_age tgt_age.years tgt_country tgt_income
1 18 33 0.3333333 w 0 - 17 13 Germany 54020 w 0 - 17 5 Germany 36135
1 7 15 0.3333333 w 18 - 25 18 Australia 57670 m 18 - 25 22 Poland 40880
1 23 31 1.0000000 w 46 - 55 55 Australia 31025 w 0 - 17 10 Poland 13140
1 5 27 0.3333333 m 66 - 100 94 Australia 4745 w 56 - 65 62 USA 10950
1 27 30 0.3333333 w 56 - 65 62 USA 10950 m 36 - 45 38 USA 1825
1 15 16 1.0000000 m 18 - 25 22 Poland 40880 w 66 - 100 69 Australia 13140