Interactions of order four and higher

Here we explain how to use our rank order method to detect four-way interactions from rank orders of genotypes. We also show how to detect total n-way interactions from rank orders, for arbitrary n. Please let us know (on GitHub or via email) if you wish to see this software extended with some particular functionality. We welcome feedback!

For the tasks just mentioned, the necessary functions are the following:


In [1]:
from four_way_interactions import four_way_from_ranking
from total_n_way_interaction import total_n_way_interaction

Four-way interaction coordinates

To detect whether your rank order implies u-interaction given by an interaction coordinate u, run function four_way_from_ranking on the pair (w, u), where w is the rank order and u is one of the following interaction coordinates. (In this list we abuse the notation and use genotypes instead of their fitnesses.)

u_0011 = 0000 + 0100 + 1000 + 1100 + 0011 + 0111 + 1011 + 1111 -
         0001 - 0101 - 1001 - 1101 - 0010 - 0110 - 1010 - 1110
u_0101 = 0000 + 0010 + 1000 + 1010 + 0101 + 0111 + 1101 + 1111 -
         0001 - 0011 - 1001 - 1011 - 0100 - 0110 - 1100 - 1110
u_0110 = 0000 + 0001 + 1000 + 1001 + 0110 + 0111 + 1110 + 1111 -
         0010 - 0011 - 1010 - 1011 - 0100 - 0101 - 1100 - 1101
u_1001 = 0000 + 0010 + 0100 + 0110 + 1001 + 1011 + 1101 + 1111 -
         0001 - 0011 - 0101 - 0111 - 1000 - 1010 - 1100 - 1110
u_1010 = 0000 + 0001 + 0100 + 0101 + 1010 + 1011 + 1110 + 1111 -
         0010 - 0011 - 0110 - 0111 - 1000 - 1001 - 1100 - 1101
u_1100 = 0000 + 0001 + 0010 + 0011 + 1100 + 1101 + 1110 + 1111 -
         0100 - 0101 - 0110 - 0111 - 1000 - 1001 - 1010 - 1011
u_0111 = 0000 + 1000 + 0011 + 1011 + 0101 + 1101 + 0110 + 1110 -
         0001 - 1001 - 0010 - 1010 - 0100 - 1100 - 0111 - 1111
u_1011 = 0000 + 0100 + 0011 + 0111 + 1001 + 1101 + 1010 + 1110 -
         0001 - 0101 - 0010 - 0110 - 1000 - 1100 - 1011 - 1111
u_1101 = 0000 + 0010 + 0101 + 0111 + 1001 + 1011 + 1100 + 1110 -
         0001 - 0011 - 0100 - 0110 - 1000 - 1010 - 1101 - 1111
u_1110 = 0000 + 0001 + 0110 + 0111 + 1010 + 1011 + 1100 + 1101 -
         0010 - 0011 - 0100 - 0101 - 1000 - 1001 - 1110 - 1111
u_1111 = 0000 + 0011 + 0101 + 0110 + 1001 + 1010 + 1100 + 1111 -
         0001 - 0010 - 0100 - 1000 - 0111 - 1011 - 1101 - 1110

Note that the redundant zeros have to be suppressed in all genotypes and interaction coordinates, as in the example below.

Example: To detect whether the rank order

0000 > 0001 > 0010 > 0011 > 0110 > 0111 > 1000 > 1001 >
1010 > 1011 > 1100 > 1101 > 1110 > 1111 > 0100 > 0101

implies u-interaction, where u is u_0110, run the following:


In [2]:
interaction = four_way_from_ranking([0, 1, 10, 11, 110, 111, 1000, 1001,
                                     1010, 1011, 1100, 1101, 1110, 1111, 100, 101], 110)
print("[Positive interaction, Negative interaction] = " + str(interaction))


[Positive interaction, Negative interaction] = [True, False]

The latter 110 in the four_way_from_ranking call corresponds to u. The output is a pair of truth values corresponding to the positive and negative interaction, respectively. In the example above, the output means that the rank order implies positive interaction.

Total n-way interaction

To detect whether your rank order implies total n-way interaction, run function total_n_way_interaction on the rank order given by a list in binary format.

Example: To detect whether the rank order

00001 > 00010 > 00011 > 00100 > 00101 > 00110 > 00111 > 01000 >
01001 > 01010 > 01011 > 01100 > 01101 > 01110 > 01111 > 10000 >
10001 > 10010 > 10011 > 10100 > 10101 > 10110 > 10111 > 11000 >
11001 > 11010 > 11011 > 11100 > 11101 > 11110 > 11111 > 00000

implies total 5-way interaction, run the following:


In [3]:
interaction = total_n_way_interaction([1, 10, 11, 100, 101, 110, 111, 1000,
                                       1001, 1010, 1011, 1100, 1101, 1110, 1111, 10000,
                                       10001, 10010, 10011, 10100, 10101, 10110, 10111, 11000,
                                       11001, 11010, 11011, 11100, 11101, 11110, 11111, 0])
print("[Positive interaction, Negative interaction] = " + str(interaction))


[Positive interaction, Negative interaction] = [False, True]

The output is a pair of truth values corresponding to the positive and negative interaction, respectively. In the example above, the output means that the rank order implies negative interaction. Both False would mean that the rank order does not imply interaction.

Plasmodium vivax dihydrofolate reducatase (DHFR)

Here we analyze the DHFR data from (Ogbunugafor and Hartl 2016, Table S3). The index i in variable ranking_i corresponds to the drug concentration.


In [4]:
ranking_9 = [1111, 1110, 1010, 100, 1000, 1100, 111, 110, 101, 11, 1001, 10, 1101, 1011, 1, 0]

In [5]:
u_0011 = four_way_from_ranking(ranking_9, 11)
print(u_0011)


[False, False]

In [6]:
u_0101 = four_way_from_ranking(ranking_9, 101)
print(u_0101)


[False, False]

In [7]:
u_0110 = four_way_from_ranking(ranking_9, 110)
print(u_0110)


[False, False]

In [8]:
u_1001 = four_way_from_ranking(ranking_9, 1001)
print(u_1001)


[False, False]

In [9]:
u_1010 = four_way_from_ranking(ranking_9, 1010)
print(u_1010)


[False, False]

In [10]:
u_1100 = four_way_from_ranking(ranking_9, 1100)
print(u_1100)


[False, False]

In [11]:
u_1110 = four_way_from_ranking(ranking_9, 1110)
print(u_1110)


[False, True]

In [12]:
u_1101 = four_way_from_ranking(ranking_9, 1101)
print(u_1101)


[False, True]

In [13]:
u_0111 = four_way_from_ranking(ranking_9, 111)
print(u_0111)


[False, True]

In [14]:
u_1011 = four_way_from_ranking(ranking_9, 1011)
print(u_1011)


[False, False]

In [15]:
u_1111 = four_way_from_ranking(ranking_9, 1111)
print(u_1111)


[False, False]

In [16]:
ranking_8 = [1111, 1110, 1010, 111, 110, 11, 100, 1000, 1100, 10, 101, 1001, 1011, 1101, 1, 0]

In [17]:
u_0011 = four_way_from_ranking(ranking_8, 11)
print(u_0011)


[False, False]

In [18]:
u_0101 = four_way_from_ranking(ranking_8, 101)
print(u_0101)


[False, False]

In [19]:
u_0110 = four_way_from_ranking(ranking_8, 110)
print(u_0110)


[False, False]

In [20]:
u_1001 = four_way_from_ranking(ranking_8, 1001)
print(u_1001)


[False, False]

In [21]:
u_1010 = four_way_from_ranking(ranking_8, 1010)
print(u_1010)


[False, False]

In [22]:
u_1100 = four_way_from_ranking(ranking_8, 1100)
print(u_1100)


[False, False]

In [23]:
u_1110 = four_way_from_ranking(ranking_8, 1110)
print(u_1110)


[False, False]

In [24]:
u_1101 = four_way_from_ranking(ranking_8, 1101)
print(u_1101)


[False, False]

In [25]:
u_0111 = four_way_from_ranking(ranking_8, 111)
print(u_0111)


[False, True]

In [26]:
u_1011 = four_way_from_ranking(ranking_8, 1011)
print(u_1011)


[False, False]

In [27]:
u_1111 = four_way_from_ranking(ranking_8, 1111)
print(u_1111)


[False, False]

In [28]:
ranking_7 = [1111, 111, 1110, 1010, 11, 1011, 110, 1000, 10, 1100, 101, 1001, 1101, 100, 1, 0]

In [29]:
u_0011 = four_way_from_ranking(ranking_7, 11)
print(u_0011)


[False, False]

In [30]:
u_0101 = four_way_from_ranking(ranking_7, 101)
print(u_0101)


[False, False]

In [31]:
u_0110 = four_way_from_ranking(ranking_7, 110)
print(u_0110)


[False, False]

In [32]:
u_1001 = four_way_from_ranking(ranking_7, 1001)
print(u_1001)


[False, False]

In [33]:
u_1010 = four_way_from_ranking(ranking_7, 1010)
print(u_1010)


[False, False]

In [34]:
u_1100 = four_way_from_ranking(ranking_7, 1100)
print(u_1100)


[False, False]

In [35]:
u_1110 = four_way_from_ranking(ranking_7, 1110)
print(u_1110)


[False, False]

In [36]:
u_1101 = four_way_from_ranking(ranking_7, 1101)
print(u_1101)


[False, False]

In [37]:
u_0111 = four_way_from_ranking(ranking_7, 111)
print(u_0111)


[False, False]

In [38]:
u_1011 = four_way_from_ranking(ranking_7, 1011)
print(u_1011)


[False, False]

In [39]:
u_1111 = four_way_from_ranking(ranking_7, 1111)
print(u_1111)


[False, False]