Evaluating association strengths of items
Even in the non-symmetric case you can speed this up by not having the explicit double for loop. Since your case is not even normalized (apparently an animal can appear together with more than one other animal at a time), you do need your df1 as the normalization (instead of just e.g. df2.sum(axis=1). This gives you the matrix of the associations:

assoc_matrix = (df2.T / df1.set_index("Animal").Count).T
print(assoc_matric)
#           Monkey     Tiger       Cat       Dog      Lion
# Monkey  0.461538  0.692308  0.307692  0.692308  0.615385
# Tiger   0.200000  0.150000  0.200000  0.250000  0.250000
# Cat     0.062500  0.312500  0.250000  0.312500  0.000000
# Dog     0.000000  0.133333  0.333333  0.200000  0.466667
# Lion    0.500000  0.388889  0.333333  0.000000  0.333333


(I figured out the needed transposes by trial and error until I got the same values as in your post...)

And then you can use pandas.melt to get it into your format:

assoc_df2 = pd.melt(assoc_matrix.reset_index(), id_vars="index")
assoc_df2.columns = "Animal 1", "Animal 2", "Association Strength"
print(assoc_df2)

#    Animal 1 Animal 2  Association Strength
# 0    Monkey   Monkey              0.461538
# 1     Tiger   Monkey              0.200000
# 2       Cat   Monkey              0.062500
# 3       Dog   Monkey              0.000000
# 4      Lion   Monkey              0.500000
# 5    Monkey    Tiger              0.692308
# 6     Tiger    Tiger              0.150000
# 7       Cat    Tiger              0.312500
# 8       Dog    Tiger              0.133333
# 9      Lion    Tiger              0.388889
# 10   Monkey      Cat              0.307692
# 11    Tiger      Cat              0.200000
# 12      Cat      Cat              0.250000
# 13      Dog      Cat              0.333333
# 14     Lion      Cat              0.333333
# 15   Monkey      Dog              0.692308
# 16    Tiger      Dog              0.250000
# 17      Cat      Dog              0.312500
# 18      Dog      Dog              0.200000
# 19     Lion      Dog              0.000000
# 20   Monkey     Lion              0.615385
# 21    Tiger     Lion              0.250000
# 22      Cat     Lion              0.000000
# 23      Dog     Lion              0.466667
# 24     Lion     Lion              0.333333


Note that the order is different to your solution and this also contains the association of each animal with itself (and it is not one in this example, due to the normalization). You can just filter it out, though, if needed:

assoc_df2 = assoc_df2[assoc_df2["Animal 1"] != assoc_df2["Animal 2"]]


Finally, all of this only works as long as the dataframes still fit into memory, of course.