The memnet
package provides efficient implementations of network science tools to facilitate research into human (semantic) memory. In its current version, the package contains several methods to infer networks from verbal fluency data, various network growth models, diverse (switcher-) random walk processes, and tools to analyze and visualize networks.
The majority of memnet
is written in C++ to deliver maximum performance.
Have questions, found annoying errors, or have need/recommendation for additional functionality? Please don’t hesitate to write me at dirk.wulff@gmail.com
or https://github.com/dwulff/memnet
. Thanks!
Verbal fluency is a commonly employed task in cognitive science and neuropsychological diagnosis that requires individuals to retrieve within a limited time window, e.g., 1 minute, as many elements from a natural category as they can. Typically, researchers interpret the sequences that individuals produce in this task as reflecting the underlying semantic network structure. Several methods have been proposed to infer the network structure from verbal fluency including the three methods implement here: community_graph
, threshold_graph
, and rw_graph
. Of these three, community_graph
is the most complex. It adds edges for each pair of produced elements that occur within a window of l
steps and then retains only those that occur more often than min_cooc
and what is expected by chance giving a false positive rate of crit
. threshold_graph
and rw_graph
are both nested within community_graph
. The former retains min_cooc
as a parameter but sets l = 1
and crit = 1
, implying that only adjacent nodes are considered and that chance expectations are not directly taken into account. The latter sets all parameters to 1 by including edges for every adjacent pair of nodes. The results are illustrated below.
library(memnet)
# get data
data("animal_fluency")
age = as.numeric(names(animal_fluency))
# infer networks for age > 70
net_comunity = community_graph(animal_fluency[age > 70])
net_threshold = threshold_graph(animal_fluency[age > 70])
net_rw = rw_graph(animal_fluency[age > 70])
# show stats
network_stats(edg_to_adj(net_comunity))
#> |V| |E| k C Cc L
#> 91.0000000 170.0000000 1.8681319 0.2890767 14.0814358 3.6721981
#> Lc S A p
#> 4.1809481 3.3680006 -0.2343542 0.9780220
network_stats(edg_to_adj(net_threshold))
#> |V| |E| k C Cc
#> 70.00000000 152.00000000 2.17142857 0.31567992 10.17652372
#> L Lc S A p
#> 3.07778295 3.63950362 2.79612958 0.06264176 0.94285714
network_stats(edg_to_adj(net_rw))
#> |V| |E| k C Cc L
#> 209.0000000 747.0000000 3.5741627 0.1788195 10.4565117 3.0591645
#> Lc S A p
#> 3.7885372 2.7600393 0.0781339 1.0000000
# plot
network_plot(edg_to_adj(net_comunity), nod_cex = 2, lab_cex = 1)
network_plot(edg_to_adj(net_threshold), nod_cex = 2, lab_cex = 1)
network_plot(edg_to_adj(net_rw), nod_cex = 2, lab_cex = .5, lab_lwd = 1, lab_grid_size = 70)
# inspect neighborhood of cat
neighborhood_plot(edg_to_adj(net_comunity), k = 3, node = 'cat', nod_cex = 2, lab_cex = 1)
neighborhood_plot(edg_to_adj(net_threshold), k = 3, node = 'cat', nod_cex = 2, lab_cex = 1)
neighborhood_plot(edg_to_adj(net_rw), k = 3, node = 'cat', nod_cex = 2, lab_cex = 1)
The networks were plotted using the plotting functions currently available in memnet
: network_plot
and neighborhood
plot, which plot the entire network or the k- neighborhood of a specific node, respectively.
A key question in research on semantic networks is their developmental trajectory and memory growth models one possible answer. memnet
implements a total of five network growth models:
grow_st
grows networks according to Steyvers and Tenenbaum (2004).grow_hk
grows networks according to Holme and Kim (2002).grow_ba
grows networks according to Watts and Strogatz (1998).grow_ws
grows networks according to Barabási and Albert (1999).grow_lattice
grows regular lattice networks.The grow_ba
grows networks with scale-free degree distributions using a process known as preferential attachment, which connects incoming nodes preferably with nodes that are already highly connected. grow_st
and grow_hk
share this aspect of preferential attachment, but add to triad formation process that connects incoming nodes to neighbors of previously connected nodes, in order to account for the high clustering of naturally occurring (memory) networks. grow_ws
mixes regular lattices (grow_lattices
) with a random graph in order to simultaneously create high clustering and low average shortest path lengths, a property combination known as small-world.
# plot networks of different growth mechanisms
network_plot(grow_st(20, 2))
#> labeled nodes 1:network_size
network_plot(grow_hk(20, 2, p = .3))
#> labeled nodes 1:network_size
network_plot(grow_ba(20, 2))
#> labeled nodes 1:network_size
network_plot(grow_ws(20, 4, p = .5))
#> labeled nodes 1:network_size
network_plot(grow_ws(20, 4))
#> labeled nodes 1:network_size
Access from memory is often understood as a switcher-random process operating on an underlying memory network. memnet
contains various functions to implement such switcher-random walk processes that allow simulation of behavioral data. fluency
and its fast, imprecise sibling ffluency
produce sequences of memory responses based on a censored, switcher-random walk that emits responses only for first visits to a node. search_rw
and its repeated version search_rw_mean
use switcher-random walk processes to determine the (average) distance between nodes taken account of the entire network structure rather than only the direct path.
# extract adjlist from community network
adjlist = edg_to_adjlist(net_comunity)
# simulate fluency sequences
f = fluency(adjlist, c(10, 14, 16, 18))
restore_names(f, get_names(net_comunity))
#> [[1]]
#> [1] "spider" "rat" "dog" "ox" "lemur"
#> [6] "zebra" "fox" "grasshopper" "gazelle" "human"
#>
#> [[2]]
#> [1] "horse" "sheep" "hyena" "goat" "turkey"
#> [6] "ox" "kangaroo" "mouse" "tiger" "hen"
#> [11] "crocodile" "raccoon" "bull" "colt"
#>
#> [[3]]
#> [1] "goat" "penguin" "robin" "mosquito"
#> [5] "ox" "hen" "squirrel" "anteater"
#> [9] "hippopotamus" "whale" "zebra" "rabbit"
#> [13] "chicken" "donkey" "elephant" "sheep"
#>
#> [[4]]
#> [1] "wolf" "eagle" "mouse" "cheetah" "anteater"
#> [6] "raccoon" "panda" "sheep" "fish" "cow"
#> [11] "fox" "lion" "gazelle" "bear" "beaver"
#> [16] "puppy" "rhinoceros" "chipmunk"
# simulate fluency sequences
s = search_rw_mean(adjlist, 1:5, 1:5, nrep = 100)
restore_names(s, get_names(net_comunity))
#> [,1] [,2] [,3]
#> [1,] "alligator" "alligator" "217.93"
#> [2,] "alligator" "hippopotamus" "184.78"
#> [3,] "alligator" "rhinoceros" "358.61"
#> [4,] "alligator" "ant" "356.18"
#> [5,] "alligator" "ape" "75.38"
#> [6,] "hippopotamus" "alligator" "237.54"
#> [7,] "hippopotamus" "hippopotamus" "84.7"
#> [8,] "hippopotamus" "rhinoceros" "401.92"
#> [9,] "hippopotamus" "ant" "386.49"
#> [10,] "hippopotamus" "ape" "43.08"
#> [11,] "rhinoceros" "alligator" "271.25"
#> [12,] "rhinoceros" "hippopotamus" "228.95"
#> [13,] "rhinoceros" "rhinoceros" "166.64"
#> [14,] "rhinoceros" "ant" "412.3"
#> [15,] "rhinoceros" "ape" "107.93"
#> [16,] "ant" "alligator" "255.59"
#> [17,] "ant" "hippopotamus" "235.99"
#> [18,] "ant" "rhinoceros" "315.83"
#> [19,] "ant" "ant" "323.26"
#> [20,] "ant" "ape" "84.31"
#> [21,] "ape" "alligator" "255.81"
#> [22,] "ape" "hippopotamus" "189.21"
#> [23,] "ape" "rhinoceros" "330.02"
#> [24,] "ape" "ant" "398.02"
#> [25,] "ape" "ape" "55.23"