Methods

Average Dominance Index (ADI)

_average_dominance_index.average_dominance_index(self) dict

Average Dominance Index (ADI) from an interaction dataframe/matrix.

Parameters

Returns

average_dominance_index_dictdict

Average dominance indices, keys are individual names derived from either the Dataframe or name sequence (user provided, see class module for more details) and values are ADI scores (rounded to 4 decimal places)

See also

https://numpy.org/doc/stable/reference/generated/numpy.nansum.html https://numpy.org/doc/stable/reference/generated/numpy.fill_diagonal.html

Notes

The average dominance index of an individual is the average of all its dominance indices with all its interaction partners. A higher value indicates a higher dominance in the group. (Hemelrijk et al, 2005)

References

  • The Construction of Dominance Order: Comparing Performance of Five Methods Using an Individual Based Model C. K. Hemelrijk, J. Wantia and L. Gygax, Behaviour Vol. 142, No. 8 (Aug., 2005), pp. 1037-1058 doi: 10.1163/156853905774405290

Example:

1 mat = np.array([[0, 6, 9, 8, 5],
2                 [0, 0, 4, 6, 0],
3                 [0, 2, 0, 4, 7],
4                 [1, 0, 5, 0, 3],
5                 [0, 0, 2, 3, 0]], dtype='float32')
6 hier_mat = Hierarchia(mat, name_seq=['a', 'b', 'c','d','e'])
7 average_dominance_indices = hier_mat.average_dominance_index()
8 print(average_dominance_indices)

Result:

{'a': 0.9722, 'b': 0.5556, 'c': 0.3889, 'd': 0.2917, 'e': 0.2407}

David’s Scores

_davids_score.davids_score(self, method: str = 'Pij', normalize: bool = False, order: bool = True) dict

David’s scores from an interaction dataframe/matrix.

Parameters

param method:

str Valid arguments are ‘Dij’ and ‘Pij’. The method stands for the initial matrix state, the ‘Dij’ method use the corrected version for chance for dyadic dominance index (ref. de Vries (2006)). The ‘Pij’ method use the proportion of wins to compute David’s Scores

param normalize:

bool Normalization of the David’s scores using formula of NormDS = (DS+N(N −1)/2)/N (ref. de Vries (2006)) (False)

param order:

bool If True, the resulting dictionary is sorted in descending order by David’s scores (True)

Returns

davids_score_dictdict

David’s scores, keys are individual names derived from either the Dataframe or name sequence (user provided, see class module for more details) and values are David’s scores (rounded to 4 decimal places)

See also

https://numpy.org/doc/stable/reference/generated/numpy.nansum.html https://numpy.org/doc/stable/reference/generated/numpy.fill_diagonal.html

Notes

It is proposed that for ranking objects or players in an incomplete paired-comparison experiment or tournament with at most one comparison per pair, the score of a player, C, be the total number of (a) wins of players defeated by C minus losses of players to whom C lost, plus (b) C’s wins minus C’s losses. A tied match counts as half a win plus half a loss. More general tournaments can be treated similarly. (David, 1987)

References

  • David, H. A. 1987. Ranking from unbalanced paired-comparison data. Biometrika, 74, 432–436.

  • Gammell MP, de Vries H, Jennings DJ, Carlin CM, Hayden TJ (2003). “David’s score: a more appropriate dominance ranking method than Clutton-Brock et al.’s index.” Animal Behaviour, 66, 601-605. doi: 10.1006/anbe.2003.2226.

  • de Vries H, Stevens JMG, Vervaecke H (2006). “Measuring and testing the steepness of dominance hierarchies.” Animal Behaviour, 71, 585-592. doi: 10.1016/j.anbehav.2005.05.015.

Example:

1 mat = np.array([[0, 6, 9, 8, 5],
2                 [0, 0, 4, 6, 0],
3                 [0, 2, 0, 4, 7],
4                 [1, 0, 5, 0, 3],
5                 [0, 0, 2, 3, 0]], dtype='float32')
6 hier_mat = Hierarchia(mat, name_seq=['a', 'b', 'c','d','e'])
7 davids_scores = hier_mat.davids_score()
8 print(davids_scores)

Result:

{'a': 8.4444, 'b': 1.6111, 'c': -2.3333, 'd': -3.6667, 'e': -4.0556}

ELO Rating

_elo.elo(self, start_value: float = 1000, K: float = 100, normal_probability: bool = False) dict

Elo rating from an interaction dataframe.

Parameters

param start_value:

float Parameter of the Elo function that determines the initial scores. It does not have an effect on relative differences after the calculation. (1000)

param K:

float Parameter of the Elo function that acts as a factor and determines the speed at which scores change after an interaction. Optimization might be a good idea but not implemented yet. (100)

param normal_probability:

bool Adjust the calculation of expected win/loss probabilities; default is Logistic, the normal probabilities are calculated using standard normal tables. For normalised probabilities, refer to https://handbook.fide.com (False)

Returns

elo_dictdict

Elo ratings, keys are individual names derived from the Dataframe and values are Elo scores (rounded to 4 decimal places)

See also

https://mathworld.wolfram.com/Erfc.html https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.erfc.html

Notes

From Wikipedia:

The Elo rating system is a method for calculating the relative skill levels of players in zero-sum games such as chess. It is named after its creator Arpad Elo, a Hungarian-American physics professor. The Elo system was originally invented as an improved chess-rating system over the previously used Harkness system, but is also used as a rating system in association football, American football, baseball, basketball, pool, table tennis, Go, board games such as Scrabble and Diplomacy, and esports.

The difference in the ratings between two players serves as a predictor of the outcome of a match. Two players with equal ratings who play against each other are expected to score an equal number of wins. A player whose rating is 100 points greater than their opponent’s is expected to score 64%; if the difference is 200 points, then the expected score for the stronger player is 76%.

References

  • https://en.wikipedia.org/wiki/Elo_rating_system

  • Elo, A. E. 1978. The Rating of Chess Players, Past and Present. New York: Arco.

  • Albers, P. C. H. & de Vries, H. 2001. Elo-rating as a tool in the sequential estimation of dominance strengths. Animal Behaviour, 61, 489-495. (DOI: 10.1006/anbe.2000.1571)

The Hierarchia class should be initiated with a Pandas Dataframe since the method relies on the order of the interactions. _elo.elo() will raise an exception, if Hierarchia class initiated with a matrix.

Example:

1df = pd.DataFrame({'winner': ['c', 'a', 'a', 'b', 'd', 'b', 'a', 'c', 'b'],
2                   'loser': ['a', 'b', 'b', 'a', 'c', 'd', 'b', 'b', 'a']})
3hierarchia = Hierarchia(df, 'winner', 'loser')
4elo_ratings = hierarchia.elo(start_value=1000, K=100, normal_probability=False)
5print(elo_ratings)

Result:

{'a': 971.0724, 'b': 993.3937, 'c': 1040.421, 'd': 995.113}

Randomized ELO Rating

_randomized_elo.randomized_elo(self, start_value: float = 1000, K: float = 100, n: int = 1000, normal_probability: bool = False) dict

Randomized Elo rating from an interaction dataframe/matrix.

Parameters

param start_value:

float Parameter of the Elo function that determines the initial scores. It does not have an effect on relative differences after the calculation. (1000)

param K:

float Parameter of the Elo function that acts as a factor and determines the speed at which scores change after an interaction. Optimization might be a good idea but not implemented yet. (100)

param n:

integer Parameter to adjust number of iterations for random ordering. Higher numbers result in more stable Elo ratings. The number of random orders. (1000)

param normal_probability:

bool Adjust the calculation of expected win/loss probabilities; default is Logistic, the normal probabilities are calculated using standard normal tables. For normalised probabilities, refer to https://handbook.fide.com (False)

Returns

randomized_elo_dictdict

Randomized Elo ratings, keys are individual names derived from either the Dataframe or name sequence (user provided, see class module for more details) and values are Randomized Elo scores (rounded to 4 decimal places)

See also

https://mathworld.wolfram.com/Erfc.html https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.erfc.html

Notes

A practical guide for inferring reliable dominance hierarchies and estimating their uncertainty However, most behavioural studies assume that individual dominance rank is relatively stable over time. We propose an improvement of the original Elo-rating based on randomizing the order in which interactions occurred (n = 1 000 randomizations throughout). Randomising the order that interactions are recorded produces slightly different individual Elo-ratings each time, from which we can calculate a mean individual rank. This method also allows estimating the 95% range of individual ranks when run on a single interaction dataset. (Sánchez-Tójar et al, 2017)

References

  • https://en.wikipedia.org/wiki/Elo_rating_system

  • Elo, A. E. 1978. The Rating of Chess Players, Past and Present. New York: Arco.

  • Sánchez-Tójar, Alfredo & Schroeder, Julia & Farine, Damien. (2017). A practical guide for inferring reliable dominance hierarchies and estimating their uncertainty. bioRxiv. 111146. 10.1101/111146.

Example:

1 mat = np.array([[0, 6, 9, 8, 5],
2                 [0, 0, 4, 6, 0],
3                 [0, 2, 0, 4, 7],
4                 [1, 0, 5, 0, 3],
5                 [0, 0, 2, 3, 0]], dtype='float32')
6 hier_mat = Hierarchia(mat, name_seq=['a', 'b', 'c','d','e'])
7 randomized_elo_ratings = hier_mat.randomized_elo(start_value=1000, K=100, n=2000, normal_probability=True)
8 print(randomized_elo_ratings)

Result (random process):

{'a': 1373.0278, 'b': 1070.3446, 'c': 910.9598, 'd': 857.1167, 'e': 788.5511}

I&SI (1998)

_ISI98.ISI98(self, runs: int = 1000, verbose: bool = False) dict

I&SI 1998 from an interaction dataframe/matrix.

Parameters

param runs:

int Parameter to adjust number of iterations for random ordering. Higher numbers result increase chance of finding the best sequence. Original paper suggests as low as 100 runs but our package use default 1000. (1000)

param verbose:

bool Print initial, intermediate and final inconsistencies, strength of inconsistencies and matrices. Used for detailed output of computational process. (False)

Returns

best_seqdict

Rankings from the I&SI 1998 algorithm, optimality cannot be guaranteed due to random search but given high number of runs, it should be stable. The indices are used as keys and values are the ranks.

See also

https://numpy.org/doc/stable/reference/generated/numpy.triu.html

Notes

Two criteria are used in a prioritized way in reorganizing the dominance matrix to find an order that is most consistent with a linear hierarchy: first, minimization of the numbers of inconsistencies and, second, minimization of the total strength of the inconsistencies. The linear ordering procedure, which involves an iterative algorithm based on a generalized swapping rule, is feasible for matrices of up to 80 individuals. The procedure can be applied to any dominance matrix, since it does not make any assumptions about the form of the probabilities of winning and losing. The only assumption is the existence of a linear or near-linear hierarchy which can be verified by means of a linearity test. (de Vries, 1998)

References

  • de Vries, H. 1998 Finding a dominance order most consistent with a linear hierarchy: a new procedure and review. Animal Behaviour, 55, 827-843

Example:

1 mat = np.array([[0, 6, 9, 8, 5],
2                 [0, 0, 4, 6, 0],
3                 [0, 2, 0, 4, 7],
4                 [1, 0, 5, 0, 3],
5                 [0, 0, 2, 3, 0]], dtype='float32')
6 hier_mat = Hierarchia(mat, name_seq=['a', 'b', 'c','d','e'])
7 ISI98_ranks = hier_mat.ISI98(runs=1000, verbose=True)
8 print(ISI98_ranks)

Result:

Initial Phase
-------------
Initial number of inconsistencies:  1
Initial number of inconsistencies:  1

End of Iterative Phase
-------------
Optimal or near-optimal linear ranking is found!
Best sequence after iterative phase:  ['a', 'b', 'd', 'c', 'e']
Matrix after iterative phase:

[[0 6 8 9 5]
 [0 0 6 4 0]
 [1 0 0 5 3]
 [0 2 4 0 7]
 [0 0 3 2 0]]

Final Phase
-------------
Final number of inconsistencies:  0
Final number of inconsistencies:  0
Best Sequence:  ['a', 'b', 'd', 'c', 'e']
Matrix after final phase:

[[0 6 8 9 5]
 [0 0 6 4 0]
 [1 0 0 5 3]
 [0 2 4 0 7]
 [0 0 3 2 0]]

{'a': 0, 'b': 1, 'd': 2, 'c': 3, 'e': 4}

ADAGIO

_adagio.adagio(self, preprocessing: bool = False, plot_network: bool = False, rank: str = 'topological') dict

ADAGIO from an interaction dataframe/matrix.

Parameters

param preprocessing:

bool preprocessing of the initial matrix according to the original paper [Douglas, 2016]. For a given dominance network, the preprocessed weight of the edge between the individual A that appears dominant and the individual B that appears subordinate is set to the difference in the number of interactions won by A and the number of interactions won by B. (False)

param plot_network:

bool Simple network plot of the derived directed graph network from the dataframe/matrix. (False)

param rank:

str Final ranking algorithm after the ADAGIO iterations. Three options are possible; ‘topological’ that yields topological order of the final matrix. ‘top’ and ‘bottom’ are self-explanatory and can be found at original paper. (topological)

Returns

rank_dictdict

Rankings from the ADAGIO algorithm, ranked based on the ranking parameter chosen. Keys are identification of individuals (see name_seq) and the values are the ranks.

See also

https://networkx.org/documentation/networkx-1.9/reference/generated/networkx.algorithms.components.strongly_connected.strongly_connected_components.html https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.dag.topological_sort.html

Notes

ADAGIO, for assessing the structure of dominance networks. ADAGIO computes dominance hierarchies, in the form of directed acyclic graphs, to represent the dominance relations of a given group of animals. Thus far, most methods for computing dominance ranks assume implicitly that the dominance relation is a total order of the individuals in a group. ADAGIO does not assume or require this to be always true, and is hence more appropriate for analysing dominance hierarchies that are not strongly linear. (Douglas, 2017)

References

  • Douglas, P. H., Ngomo, A. C. N., & Hohmann, G. (2017). A novel approach for dominance assessment in gregarious species: ADAGIO. Animal Behaviour, 123, 21-32.

Example:

1 mat = np.array([[0, 6, 9, 8, 5],
2                 [0, 0, 4, 6, 0],
3                 [0, 2, 0, 4, 7],
4                 [1, 0, 5, 0, 3],
5                 [0, 0, 2, 3, 0]], dtype='float32')
6 hier_mat = Hierarchia(mat, name_seq=['a', 'b', 'c','d','e'])
7 adagio_ranks = hier_mat.adagio(preprocessing=True, plot_network=False, rank='top')
8 print(adagio_ranks)

Result:

{'a': 0, 'b': 1, 'd': 2, 'c': 3, 'e': 4}