I found the following quickly, but I did not compare it with your method - only in weka .
It works on the premise of reinstalling the MI equation so that the number of floating point operations can be minimized:

Let's start with the definition
as the number / frequency of the number of samples / transactions. So, we define the number of elements as n, the number of times x occurs as | x |, the number of times y occurs as | y | and the number of times when they coincide at | x, y |. Then we get
.
Now we can rebuild this by flipping the bottom of the inner division, this will give us (n | x, y |) / (| x || y |). Also, calculate using N = 1 / n, so that we have one operation with less division. This gives us:
%20%3D%20%5Csum%20%5Climits_%7By%20%5Cin%20Y%7D%20%5Csum%20%5Climits_%7Bx%20%5Cin%20X%7D%20N%7Cx%2Cy%7C%20log%20%5Cbigg(%5Cfrac%7Bn%7Cx%2Cy%7C%7D%7B%7Cx%7C%7Cy%7C%7D%20%5Cbigg))
This gives us the following code:
/*** * Computes MI between variables t and a. Assumes that a.length == t.length. * @param a candidate variable a * @param avals number of values a can take (max(a) == avals) * @param t target variable * @param tvals number of values a can take (max(t) == tvals) * @return */ static double computeMI(int[] a, int avals, int[] t, int tvals) { double numinst = a.length; double oneovernuminst = 1/numinst; double sum = 0; // longs are required here because of big multiples in calculation long[][] crosscounts = new long[avals][tvals]; long[] tcounts = new long[tvals]; long[] acounts = new long[avals]; // Compute counts for the two variables for (int i=0;i<a.length;i++) { int av = a[i]; int tv = t[i]; acounts[av]++; tcounts[tv]++; crosscounts[av][tv]++; } for (int tv=0;tv<tvals;tv++) { for (int av=0;av<avals;av++) { if (crosscounts[av][tv] != 0) { // Main fraction: (n|x,y|)/(|x||y|) double sumtmp = (numinst*crosscounts[av][tv])/(acounts[av]*tcounts[tv]); // Log bit (|x,y|/n) and update product sum += oneovernuminst*crosscounts[av][tv]*Math.log(sumtmp)*log2; } } } return sum; }
This code assumes that the values โโof a and t are not sparse (i.e. min (t) = 0 and tvals = max (t)) to be effective. Otherwise (in the comments) large and unnecessary arrays are created.
I believe that this approach is further improved when calculating MI between several variables at once (counting operations can be compressed, especially for the target). The implementation I use is an interface that interacts with WEKA.
Finally, it would be more efficient to even get out of the summation. But I'm not sure if the magazine or the power will take more calculations in the loop. This is done by:
- Apply a * log (b) = log (a ^ b)
- Move the log beyond the summarization using log (a) + log (b) = log (ab)
and gives:
