Structural balance (tutorial) - juergenlerner/eventnet GitHub Wiki

Analyzing strucural balance in networks of signed events

In this tutorial we illustrate the analysis of networks of positive (friendly, cooperative) and negative (hostile, conflictive) interaction events with eventnet. Specifically, we describe how to test predictions of balance theory, such as "the enemy of an enemy is a friend" or "the enemy of a friend is an enemy."

Adding to previous, more basic tutorials, we illustrate two main issues: (1) how to assess the effect of exogenously given covariates (that is, externally defined properties of nodes or dyads) on dyadic interaction and (2) the different possibilities to model interaction events that are typed and/or weighted. We assume basic familiarity with other tutorials in the eventnet wiki.

In this tutorial we describe how to specify and estimate two types of models: models explaining the dyadic rate of cooperative (or conflictive, respectively) events and models explaining dyadic tendencies to engage in cooperation, rather than conflict, given that the actors interact at all. Both types of models provide insights into the question which actors consider each other as friends and which actors consider each other as enemies. Consequently both models can in principle be applied to test the predictions of balance theory that perceptions of friendship or enmity depend in part on indirect relations to third actors. However, the two types of models differ considerably in how they operationalize such tests and actually yield different conclusions. One of the main contributions of this tutorial is to explain these differences.

Background literature

Relational event models for typed and weighted events are described in the reference

The difference between models for the rate of typed events and models for the conditional event type is discussed in

Data

In this tutorial we exemplarily analyze daily interaction events among state actors (sovereign countries) related with the Persian Gulf region from 1979 to 1999. Interaction events are typed by WEIS codes and have associated weights ranging from -10 to +10, where a negative weight indicates hostile/conflictive interaction and a positive weight indicates friendly/cooperative interaction. The interaction events have been extracted from news reports by the Computational Event Data System. The file contains some 218 thousand interaction events on 168 actors. Additionally, the file contains exogenous covariates (among others encoding geographic proximity of countries, trade, alliances, and capability scores) provided by the Correlates of War project; some of these exogenous covariates change by the year. The data is provided in the file gulf_events.zip (file size 18MB; uncompressed file size 200MB), having the following structure:

"fine.grained.type";"Time";"Source";"Target";"Description";"Weight";"Type"
...
181;790415;"SYR";"LEB";"NONMIL DEMO ";-5.2;"conflict"
31;790416;"UAR";"ISR";"MEET        ";1;"cooperation"
32;790416;"USA";"ITA";"VISIT       ";1.9;"cooperation"
42;790416;"USA";"SAU";"ENDORSE     ";3.6;"cooperation"
...

The first event in this list encodes an event in which state SYR (Syria) initiated on 15th April 1979 (790415) an event of type NONMIL DEMO (non-military demonstration), having the WEIS code 181, directed at state LEB (Lebanon). The event has negative weight (-5.2) and is therefore a negative, conflictive event (the distinction between conflictive and cooperative events is further given in the last column). The other three events in this list are events with varying levels of cooperativeness.

The file further contains rows that are not interaction events among state actors, but that set covariates, as illustrated in the following list

"fine.grained.type";"Time";"Source";"Target";"Description";"Weight";"Type"
...
set.logCapRat;790101;"FRN";"GER";"log capability ratio";0.3124244;"set.logCapRat"
set.allies;790101;"FRN";"GER";"allies";1.0;"set.allies"
set.polityWeakLink;790101;"FRN";"GER";"polity score of less democratic actor";8.0;"set.polityWeakLink"
set.majPow;790101;"FRN";"GER";"dyad contains a major power";1.0;"set.majPow"
set.logTrade;790101;"FRN";"GER";"log1p of mutual trade";10.546209482901759;"set.logTrade"
set.contig;790101;"FRN";"GER";"states are contiguous";1.0;"set.contig"
setlogDist;790101;"FRN";"GER";"log1p of distance";5.521460917862246;"set.logDist"
set.logJointIGO;790101;"FRN";"GER";"log1p of number of joint IGOs";4.454347296253507;"set.logJointIGO"
set.logCapRat;790101;"FRN";"KEN";"log capability ratio";2.996605;"set.logCapRat"
set.allies;790101;"FRN";"KEN";"allies";0.0;"set.allies"
...

The first eight rows in this list set the various dyadic covariates on the dyad (FRN,GER), France and Germany, for the year 1979. Values can change by the year and the respective rows have a timestamp of the form yy0101 (1st January in the respective year) and appear before the first interaction event in that year. All covariates are symmetric, that is, values for the dyad (GER,FRN) are identical with (FRN,GER) and are not given explicitly. The last two rows in this list set covariates on the dyad connecting France with Kenya. As a side-note, this way to encode covariates is not space-efficient as some dyadic covariates could be computed from node-level covariates and some rarely change their values (which are nonetheless given explicitly each year). We have choosen this encoding to treat all covariates in a unified way - and since the data size is still manageable. We will describe below different ways how effects of these covariates on event rates and types can be tested.

Dealing with exogenous covariates in eventnet

The externally given covariates, such as formal alliances or geographic proximity, obviously have a strong impact on the incidence and/or type of interaction among state actors. Thus, even if our main hypothesis is about the effect of indirect relations (such as being an enemy of an enemy) on dyadic interaction, models have to control for the effect of covariates.

Depending on the assumed form of these covariate effects, they can be specified and estimated in two different ways. (1) If covariates are assumed to have just a direct effect on the dyad on which they are defined, then covariates can just be merged into the output files of eventnet after the variables encoding the network effects have been computed. (2) If dyadic or node-level covariates are assumed to interact with either previous events on the same or other dyads - or with covariates on other dyads - then covariates have to be entered into eventnet before starting the processing and the values of these more complex statistics (defined as functions of covariates and interaction events) are directly written to the output file(s).

An example of such a complex covariate effect would be the assumption that actors fight those who attack their allies. Specifically, if actors A and B share a formal alliance (given by an exogenous covariate) and actor C initiated many hostile events towards B than A might be more likely to fight C (an enemy of A's ally). This more complex indicator of an indirect relation between A and C cannot be directly extracted from the covariate information but requires to combine covariates with past interaction on a different dyad. To achieve this, covariates have to be entered into eventnet and their values have to be stored in dedicated dyad-level or node-level attributes.

The second approach to specifiy covariate effects is actually generally applicable. That is, even in situations in which covariates could be merged into the output files of eventnet, they can also be entered before starting the processing. In this tutorial we will only apply and illustrate this second, more general, approach.

Model specification in eventnet

We describe in the following how to specify a a model testing the predictions of balance theory, controlling for many other network and covariate effects in eventnet. For convenience the eventnet configuration for this model can be downloaded in the file gulf.config.xml or viewed online. This configuration can be loaded into eventnet via file menu -- merge into current configuration. It should work directly if eventnet-x.y.jar has been started from the same directory in which the data file gulf_events.csv is located; otherwise change the input directory and output directory accordingly.

In the files tab of the eventnet GUI browse to the input file gulf_events.csv (described and linked above; the CSV file has to be extracted from the ZIP file before opening it with eventnet). Further, select an output directory and set the csv settings as shown in the image below.

In the events tab map the various event components to the respective column names. Before clicking the button learn event types from file type 0 into the text field to the right. This ensures that the whole file is read to detect all event types (some come relatively late in the file). The tab should then look as in the image below.

In the time tab set the time format to DATE_TIME and the interval type to TIME (events with the same time stamp, that is, those that happen on the same day, are considered simultaneous). Set the time unit to 1 and the calendar time unit to DAY - this will later make it more intuitive to set the decay of attributes. The appropriate date format pattern is yyMMdd: two digits for the year, two digits for the month, and two digits for the day.

Attributes

We define two dyad-level attributes recording positive and negative interaction (conflict and cooperation), four node-level attributes recording the out-going/in-coming positive/negative events, and eight dyad-level attributes holding the values of the externally given covariates.

Specification of the dyadic attributes recording events is exemplified in the image below. The dyad-level attribute named conflict (recording past conflictive interaction on the dyad) has update type set to INCREMENT_VALUE_BY so that weights of events are added to previous attribute values. We specify a decay with a halflife of 30 TIME_UNITS (that is, days) and round values down to zero if they drop below 0.01. Thus, influence of past events on this attribute gets halved whenever time increases by 30 days. The attribute responds to one event type (named conflict, it uses the WEIGHT of events of that type and applies the function ABS (absolute value) before adding these weights to previous attribute values. Indeed, weights of conflictive events are negative and we want the attribute to attain higher values (more positive) if more, or more serious, conflictive events recently happened on that dyad. The attribute named cooperation is defined similarly with the difference that it responds to events of type cooperation and taking the absolute value is not necessary.

The node-level attribute named neg.outdeg shares many settings with the attribute conflict (clicking on the edit copy button to the right of the latter saves the time to make these common settings; alternatively it is also possible to edit the XML configuration file directly, copy attribute definitions, and make necessary changes). Differences are that its attribute class is NODE_LEVEL and that when adding the event type, the direction has to be set to OUT, as shown in the image below. The node-level attributes recording in-coming events (indeg) have to set the direction to IN, and the node-level attributes recording cooperative events (pos) respond to events of type cooperation, instead of conflict.

The eight dyad-level attributes setting the values of covariates use settings as in the image below (illustrated on the example of the allies covariate). In contrast to the attributes recording interaction, these covariate attriutes use the update type SET_VALUE_TO (since values are set rather than added to previous values) and they have no decay. The various covariate attributes just differ by the type of events they respond to (set.allies in the example shown below).

Statistics

This study uses a relatively large number of 26 different statistics that serve as variables explaining frequency and/or type of interaction on dyads connecting a source actor A to a target actor B. The different types of statistics are (1) four statistics characterizing past interaction on the same dyad (repetition/reciprocation of positive/negative events), (2) eight statistics encoding the degree of the two actors involved (indegree/outdegree with respect to positive/negative events of the source/target actor), (3) four statistics - applied to test the predictions of balance theory - characterizing the dyad (A,B) by past interaction with third actors (encoding to what extent B is a friend of a friend of A, an enemy of a friend, a friend of an enemy, or an enemy of an enemy), (4) eight statistics encoding the different dyadic covariates, and (5) two statistics characterizing to what extent B is the enemy of an ally of A or the ally of an enemy of A. The last two statistics serve as an example illustrating how combinations of covariates and past interaction events can explain future interaction. In the following we describe in detail the specification of the four triadic statistics used to test balance theory (see the configuration file gulf.config.xml for how to specify the other statistics).

The image below illustrates settings to create the statistic enemy.of.friend. This statistic characterizes, for a focal dyad (A,B), to what extent B is connected by past conflictive events to a third actor who, in turn, is connected by past cooperative events with A. The statistic has type TRIANGLE_STATSTIC. The first dyad (that is, the one connecting the source actor A with any third actor C) takes values of the attribute cooperation in both directions (direction is equal to SYM). That is, values of the attribute cooperation on the dyads (A,C) and (C,A) are added. Accordingly, the second dyad (that is, the one connecting the target actor B to the third actor C) takes values of the attribute conflict in both directions. Values on these two dyads are combined by the function MIN, that is, the minimum of the two values are taken. If A and B are indirectly connected via more than one third actor, the values of these typed parallel two-paths are added. The statistics friend.of.friend, friend.of.enemy, and enemy.of.enemy are defined accordingly, by switching the attributes of the two dyads.

Observations

We specify three observations, two of which (COOPERATE and CONFLICT) are used to model the rate of cooperative (or conflictive, respectively) dyadic events, the third (CONDITIONAL_WEIGHT) is used to model the conditional probability to engage in cooperation, rather than conflict, given that there is interaction.

The image below displays settings to create an observation named CONFLICT used to model the rate of conflictive events. The observation considers only events of type conflict, it excludes loops from the risk set, and it applies case-control sampling from the non-event dyads, where we sample two non-events per event. The observation named COOPERATE is very similar with the only difference that it considers only events of type cooperation.

The image below displays settings to create an observation named CONDITIONAL_WEIGHT. In contrast to the other two observations it considers events of two different types, cooperation or conflict, and - most crucially - it conditions on the source and on the target of observed events. This means, only dyads on which an event is observed are returned (there are no non-events at all). Thus, the sources and targets of events are not considered as random, but are conditioned upon. In fact, the only random components are the event type (which could be either cooperation or conflict) and the event weight, a numeric value ranging from -10 (for the most conflictive events) to +10 (for the most cooperative events). Case-control sampling is not necessary for this observation since there are no non-events in the risk set. We will illustrate below how effects explaining the conditional type, or weight, are estimated.

With these settings, the computation of explanatory variables can be started by clicking on the process button in the left-hand panel of the eventnet GUI, or by calling java -jar eventnet-x.y.jar gulf.config.xml (assuming that the configuration has been saved in the file gulf.config.xml).

Marginal vs. conditional probability of conflict

To explain the difference between the approach to model the rate of cooperative or conflictive events and the conditional proabability of cooperation, we note the following (symbolic) decomposition of the probability of conflictive interaction; also see Lerner (2016) for more background

P(conflict event) = P(event) x P(conflict | event)

and similarly for the probability of cooperative events

P(cooperation event) = P(event) x P(cooperation | event)

The first equation decomposes the probability of a conflictive event on a dyad (A,B) into the probability of an event (of any type, conflictive or cooperative) on (A,B) times the conditional proabaility that A engages in conflictive (rather than cooperative) interaction towards B, given that there is an interaction event on (A,B). The observations
COOPERATE and CONFLICT can be applied to estimate models for the left-hand side of these equations (marginal rate of cooperative or conflictive events) and the observation CONDITIONAL_WEIGHT can be used to estimate the second factor on the right-hand side (conditional probabilities of cooperation or conflict).

Balance theory predicts, among others, that the enemy of an enemy is a friend. That is, we would expect that if A and B have many common enemies, then the rate of conflictive events on (A,B) should decrease, the rate of cooperative events on (A,B) should increase, and the conditional probability that A engages in conflictive, rather than cooperative, interaction towards B should decrease. Thus, it seems that analyzing the effect of having common enemies on P(conflict event) should yield the same result as analyzing the effect of this variable on P(conflict | event). However, this ignores that having a common enemy might also have an effect on P(event), that is, on the rate of interaction of any kind (cooperative or conflictive); in particular, this effect might be positive due to triadic closure and thus, might work against the hypothetical conflict-decreasing effect of having a common enemy.

Model estimation in R

We illustrate how to analyze the output files produced by eventnet with the R software for statistical computing. We fit different types of models: Cox proportional hazard models are estimated to explain the marginal rate of cooperative or conflictive events. Logistic regression models are used to explain the conditional probability to engage in cooperative (rather than conflictive) interaction, given that actors do interact. Linear regression models are estimated to explain the conditional weight of interaction (indicating the level of cooperativeness or hostility), given that actors do interact.

Modeling the marginal rate of cooperative or conflictive interaction

Models for the marginal rate of conflictive or cooperative events can be estimated with the survival package in R, as illustrated in the following code snippets.

First, install necessary packages, load the data, and standardize some variables.

## install the R package 'survival' if necessary (uncomment the following line)
#install.packages("survival")
# attach the library
library(survival)

# set the working directory
setwd("<eventnet output directory>")

# read observations for cooperative events events
coop.events <- read.csv("gulf_events_COOPERATE.csv", sep = ";")

# all endogenous statistics (network effects) are first logarithmized and then standardized
coop.events[,c(12:27,36,37)] <- log1p(coop.events[,c(12:27,36,37)])
coop.events[,c(12:27,36,37)] <- scale(coop.events[,c(12:27,36,37)])

# the numerical statistics based on exogenous covariates are standardized
coop.events[,c(28,29,32,33,34)] <- scale(coop.events[,c(28,29,32,33,34)])
# binary statistics based on exogenous covariates are left unchanged

Specify and estimate models. Below we illustrate how to estimate a model using all computed statistics. Of course, model specifications can also use subsets of all available variables.

## specify and estimate a Cox proportional hazard model
coop.surv <- Surv(time = rep(1,dim(coop.events)[1]), event = coop.events$IS_OBSERVED)
coop.model <- coxph(coop.surv ~ pos.repetition + neg.repetition
                      + pos.reciprocation + neg.reciprocation
                      + pos.outdeg.source + neg.outdeg.source
                      + pos.indeg.source + neg.indeg.source
                      + pos.outdeg.target + neg.outdeg.target
                      + pos.indeg.target + neg.indeg.target
                      + friend.of.friend + friend.of.enemy
                      + enemy.of.friend + enemy.of.enemy
                      + enemy.of.ally + ally.of.enemy
                      + logDistance + logCapRat + majorPower + contiguity
                      + logTrade + polityWeakLink + logJointIGO + allies
                      + strata(TIME)
                      , data = coop.events)
# print out estimated parameters, standard errors, and more
summary(coop.model)

Relevant output includes the following.

  n= 236784, number of events= 97557 
                       coef exp(coef)  se(coef)       z Pr(>|z|)    
pos.repetition    -0.134397  0.874243  0.009693 -13.865  < 2e-16 ***
neg.repetition    -0.134803  0.873888  0.009847 -13.690  < 2e-16 ***
pos.reciprocation -0.122240  0.884936  0.009035 -13.529  < 2e-16 ***
neg.reciprocation -0.088418  0.915378  0.009253  -9.556  < 2e-16 ***
pos.outdeg.source  0.659849  1.934500  0.020078  32.864  < 2e-16 ***
neg.outdeg.source  0.207492  1.230588  0.020434  10.154  < 2e-16 ***
pos.indeg.source   0.399055  1.490415  0.021061  18.947  < 2e-16 ***
neg.indeg.source   0.064069  1.066166  0.018989   3.374 0.000741 ***
pos.outdeg.target  0.416100  1.516037  0.018699  22.253  < 2e-16 ***
neg.outdeg.target  0.102980  1.108469  0.019037   5.409 6.32e-08 ***
pos.indeg.target   0.628247  1.874321  0.020851  30.130  < 2e-16 ***
neg.indeg.target   0.120887  1.128498  0.018875   6.405 1.51e-10 ***
friend.of.friend   0.504998  1.656983  0.026285  19.212  < 2e-16 ***
friend.of.enemy   -0.471047  0.624348  0.024322 -19.367  < 2e-16 ***
enemy.of.friend   -0.445339  0.640607  0.024665 -18.055  < 2e-16 ***
enemy.of.enemy     0.338675  1.403087  0.024293  13.941  < 2e-16 ***
enemy.of.ally     -0.015697  0.984426  0.004598  -3.414 0.000641 ***
ally.of.enemy     -0.009774  0.990274  0.004402  -2.221 0.026382 *  
logDistance       -0.295838  0.743908  0.006469 -45.733  < 2e-16 ***
logCapRat         -0.105711  0.899685  0.005221 -20.246  < 2e-16 ***
majorPower         0.238397  1.269213  0.013315  17.905  < 2e-16 ***
contiguity         0.073775  1.076565  0.012352   5.973 2.33e-09 ***
logTrade           0.160429  1.174015  0.005657  28.362  < 2e-16 ***
polityWeakLink    -0.035350  0.965268  0.004353  -8.121 4.63e-16 ***
logJointIGO       -0.142875  0.866863  0.007999 -17.863  < 2e-16 ***
allies             0.177362  1.194063  0.010450  16.972  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Discussing the findings related with the structural balance effects, we find that actors that are friends of friends and actors that are enemies of enemies have an increased rate of interacting via cooperative events. Conversely, we find that actors have a decreased rate of positive interaction with the friends of their enemies and with the enemies of their friends. The findings on these four effects support balance theory.

Estimating models for the marginal rate of conflictive (negative) events is quite similar. The only difference is that we load observations from another output file of eventnet.

conf.events <- read.csv("gulf_events_CONFLICT.csv", sep = ";")

# all endogenous statistics (network effects) are first logarithmized and then standardized
conf.events[,c(12:27,36,37)] <- log1p(conf.events[,c(12:27,36,37)])
conf.events[,c(12:27,36,37)] <- scale(conf.events[,c(12:27,36,37)])

# the numerical statistics based on exogenous covariates are standardized
conf.events[,c(28,29,32,33,34)] <- scale(conf.events[,c(28,29,32,33,34)])
# binary statistics based on exogenous covariates are left unchanged

## specify and estimate a Cox proportional hazard model
conf.surv <- Surv(time = rep(1,dim(conf.events)[1]), event = conf.events$IS_OBSERVED)
conf.model <- coxph(conf.surv ~ pos.repetition + neg.repetition
                      + pos.reciprocation + neg.reciprocation
                      + pos.outdeg.source + neg.outdeg.source
                      + pos.indeg.source + neg.indeg.source
                      + pos.outdeg.target + neg.outdeg.target
                      + pos.indeg.target + neg.indeg.target
                      + friend.of.friend + friend.of.enemy
                      + enemy.of.friend + enemy.of.enemy
                      + enemy.of.ally + ally.of.enemy
                      + logDistance + logCapRat + majorPower + contiguity
                      + logTrade + polityWeakLink + logJointIGO + allies
                      + strata(TIME)
                      , data = conf.events)
summary(conf.model)

Relevant output includes the following.

  n= 260060, number of events= 119922 
                       coef exp(coef)  se(coef)       z Pr(>|z|)    
pos.repetition    -0.216963  0.804960  0.010590 -20.487  < 2e-16 ***
neg.repetition    -0.091944  0.912156  0.012766  -7.202 5.93e-13 ***
pos.reciprocation -0.178862  0.836222  0.009963 -17.953  < 2e-16 ***
neg.reciprocation -0.134526  0.874130  0.011879 -11.325  < 2e-16 ***
pos.outdeg.source  0.478273  1.613286  0.020066  23.835  < 2e-16 ***
neg.outdeg.source  0.401647  1.494284  0.022160  18.125  < 2e-16 ***
pos.indeg.source   0.420691  1.523014  0.021861  19.244  < 2e-16 ***
neg.indeg.source   0.150377  1.162273  0.020838   7.216 5.34e-13 ***
pos.outdeg.target  0.402139  1.495019  0.019216  20.928  < 2e-16 ***
neg.outdeg.target  0.219078  1.244929  0.021127  10.370  < 2e-16 ***
pos.indeg.target   0.508737  1.663188  0.022249  22.865  < 2e-16 ***
neg.indeg.target   0.336267  1.399713  0.021526  15.621  < 2e-16 ***
friend.of.friend   0.167382  1.182205  0.029471   5.679 1.35e-08 ***
friend.of.enemy   -0.344542  0.708545  0.027023 -12.750  < 2e-16 ***
enemy.of.friend   -0.329288  0.719436  0.027685 -11.894  < 2e-16 ***
enemy.of.enemy     0.332441  1.394368  0.026732  12.436  < 2e-16 ***
enemy.of.ally     -0.002047  0.997955  0.004341  -0.472  0.63720    
ally.of.enemy     -0.001478  0.998523  0.004234  -0.349  0.72703    
logDistance       -0.316873  0.728424  0.006785 -46.699  < 2e-16 ***
logCapRat         -0.072439  0.930123  0.004948 -14.639  < 2e-16 ***
majorPower         0.356406  1.428187  0.013350  26.697  < 2e-16 ***
contiguity         0.174466  1.190611  0.012082  14.440  < 2e-16 ***
logTrade           0.150497  1.162412  0.004917  30.608  < 2e-16 ***
polityWeakLink    -0.011944  0.988127  0.004169  -2.865  0.00417 ** 
logJointIGO       -0.121083  0.885960  0.008074 -14.997  < 2e-16 ***
allies             0.121215  1.128867  0.010573  11.464  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

From this analysis we find that actors have an increased rate to initiate conflictive events towards the friends of their friends and towards the enemies of their enemies. We also find that actors have a decreased rate of conflictive interaction with the friends of their enemies and with the enemies of their friends. The findings on these four effects explaining conflictive interaction contradict the predictions of balance theory.

It seems that signed indirect ties rather have a consistent effect on the rate of any interaction (cooperative or conflictive) but the predictions of balance theory on increase or decrease of the rate of positive or negative events are often rejected.

Modeling the conditional event type (conditional probability of cooperation)

Conditional type models for the conditional probability of cooperative interaction, given that there is interaction, can be estimated with logistic regression as illustrated in the following.

# read output from the observation "CONDITIONAL_WEIGHT" 
cond.events <- read.csv("gulf_events_CONDITIONAL_WEIGHT.csv", sep = ";")

# endogenous statistics and the numeric (non-binary) statistics based on exogenous covariates are standardized
cond.events[,c(12:27,36,37,28,29,32,33,34)] <- scale(cond.events[,c(12:27,36,37,28,29,32,33,34)])

# define a binary variable indicating whether the interaction event is cooperative
cond.events$IS_COOP <- 1
cond.events[cond.events$TYPE == "conflict","IS_COOP"] <- 0
## specify and estimate logit model for the probability that the event is positive
cond.t.model <- glm(IS_COOP ~ pos.repetition + neg.repetition
                     + pos.reciprocation + neg.reciprocation
                     + pos.outdeg.source + neg.outdeg.source
                     + pos.indeg.source + neg.indeg.source
                     + pos.outdeg.target + neg.outdeg.target
                     + pos.indeg.target + neg.indeg.target
                     + friend.of.friend + friend.of.enemy
                     + enemy.of.friend + enemy.of.enemy
                     + enemy.of.ally + ally.of.enemy
                     + logDistance + logCapRat + majorPower + contiguity
                     + logTrade + polityWeakLink + logJointIGO + allies
                     , family = "binomial"
                     , data = cond.events)
summary(cond.t.model)

Relevant output includes the following.

                   Estimate Std. Error z value Pr(>|z|)    
(Intercept)       -0.036394   0.011642  -3.126  0.00177 ** 
pos.repetition     0.159822   0.018070   8.845  < 2e-16 ***
neg.repetition    -0.222616   0.020424 -10.900  < 2e-16 ***
pos.reciprocation  0.026295   0.014338   1.834  0.06666 .  
neg.reciprocation -0.195850   0.016517 -11.857  < 2e-16 ***
pos.outdeg.source  0.144170   0.018594   7.754 8.92e-15 ***
neg.outdeg.source -0.153088   0.019136  -8.000 1.24e-15 ***
pos.indeg.source   0.043822   0.021016   2.085  0.03705 *  
neg.indeg.source  -0.004536   0.018020  -0.252  0.80127    
pos.outdeg.target  0.006474   0.015278   0.424  0.67175    
neg.outdeg.target -0.018276   0.017228  -1.061  0.28879    
pos.indeg.target   0.002784   0.022547   0.123  0.90175    
neg.indeg.target  -0.103141   0.021909  -4.708 2.51e-06 ***
friend.of.friend   0.417984   0.026522  15.760  < 2e-16 ***
friend.of.enemy   -0.317827   0.023037 -13.797  < 2e-16 ***
enemy.of.friend   -0.449498   0.023610 -19.039  < 2e-16 ***
enemy.of.enemy     0.358995   0.022037  16.291  < 2e-16 ***
enemy.of.ally      0.016538   0.006722   2.460  0.01389 *  
ally.of.enemy      0.016076   0.006571   2.447  0.01442 *  
logDistance        0.012184   0.009413   1.294  0.19555    
logCapRat          0.030994   0.005609   5.526 3.28e-08 ***
majorPower        -0.373244   0.016132 -23.138  < 2e-16 ***
contiguity        -0.324754   0.015436 -21.039  < 2e-16 ***
logTrade           0.257234   0.007085  36.309  < 2e-16 ***
polityWeakLink    -0.012670   0.005396  -2.348  0.01887 *  
logJointIGO       -0.091696   0.005967 -15.367  < 2e-16 ***
allies             0.422419   0.012244  34.501  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

We find that, given that actors do interact with the friends of their friends, they have an increased probability to do so via cooperative events, rather than conflictive events. Likewise, the conditional probability of cooperative events is higher for enemies of enemies. Conversely, given that actors initiate an event towards an enemy of a friend there is a decreased probability that this event is cooperative (hence, necessarily there is an increased probability that this event is conflictive). We make qualitatively the same finding for the conditional probability of cooperative events towards friends of enemies.

Thus, the conditional type models consistently support the predictions of balance theory.

Modeling the conditional event weight

Rather than modeling the conditional probability that a given event is cooperative, we can also model the conditional distribution of the weight of given events. This approach even seems to be preferable since it distinguishes, for instance, between mildly conflictive and strongly conflictive events. The estimation is done on the same data as for the conditional event type models.

# estimate a linear regression model for the weight of events
cond.w.model <- lm(WEIGHT ~ pos.repetition + neg.repetition
                   + pos.reciprocation + neg.reciprocation
                   + pos.outdeg.source + neg.outdeg.source
                   + pos.indeg.source + neg.indeg.source
                   + pos.outdeg.target + neg.outdeg.target
                   + pos.indeg.target + neg.indeg.target
                   + friend.of.friend + friend.of.enemy
                   + enemy.of.friend + enemy.of.enemy
                   + enemy.of.ally + ally.of.enemy
                   + logDistance + logCapRat + majorPower + contiguity
                   + logTrade + polityWeakLink + logJointIGO + allies
                   , data = cond.events)
summary(cond.w.model)

Relevant output includes the following.

                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       -0.779632   0.025558 -30.504  < 2e-16 ***
pos.repetition     0.512482   0.038174  13.425  < 2e-16 ***
neg.repetition    -0.848337   0.041433 -20.475  < 2e-16 ***
pos.reciprocation  0.076830   0.030022   2.559 0.010493 *  
neg.reciprocation -0.423465   0.032515 -13.024  < 2e-16 ***
pos.outdeg.source  0.126982   0.040045   3.171 0.001520 ** 
neg.outdeg.source -0.146761   0.041271  -3.556 0.000377 ***
pos.indeg.source   0.169977   0.044732   3.800 0.000145 ***
neg.indeg.source  -0.223439   0.037408  -5.973 2.33e-09 ***
pos.outdeg.target -0.108000   0.033063  -3.266 0.001089 ** 
neg.outdeg.target  0.224541   0.037050   6.061 1.36e-09 ***
pos.indeg.target   0.104439   0.048160   2.169 0.030116 *  
neg.indeg.target  -0.284671   0.045934  -6.197 5.75e-10 ***
friend.of.friend   1.294443   0.053867  24.030  < 2e-16 ***
friend.of.enemy   -0.894442   0.046087 -19.408  < 2e-16 ***
enemy.of.friend   -1.182790   0.047570 -24.864  < 2e-16 ***
enemy.of.enemy     0.874123   0.043548  20.073  < 2e-16 ***
enemy.of.ally     -0.075829   0.014256  -5.319 1.04e-07 ***
ally.of.enemy     -0.031757   0.014287  -2.223 0.026230 *  
logDistance        0.336988   0.020636  16.330  < 2e-16 ***
logCapRat          0.006868   0.012340   0.557 0.577847    
majorPower        -0.632944   0.035578 -17.790  < 2e-16 ***
contiguity        -0.529672   0.033799 -15.671  < 2e-16 ***
logTrade           0.569090   0.015361  37.047  < 2e-16 ***
polityWeakLink    -0.159944   0.011846 -13.502  < 2e-16 ***
logJointIGO       -0.129348   0.013200  -9.799  < 2e-16 ***
allies             0.942758   0.026893  35.056  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

We find that the event weight is higher (that is, more cooperative) among friends of friends and among enemies of enemies. Conversely, actors tend to initiate events of lower weight (more conflictive) towards the enemies of their friends and towards the friends of their enemies.

Again, these findings on the conditional event weight consistently support the predictions of balance theory.