0
$\begingroup$

Suppose we have a series of integer numbers which are not truly random (For example, the numbers at a given position in decimal pi representation).

Is there a machine learning algorithm that can capture this?

Thanks for your time.

$\endgroup$
3
  • $\begingroup$ You can use the Runs test. There is an implementation in stats models that you can use directly. If you find this useful let me know and I can extend a full answer with code and implementation. (Long ago I ran this with Excel VBA before using python) $\endgroup$
    – Multivac
    Commented Jun 27, 2023 at 19:32
  • $\begingroup$ Thanks very much for your response $\endgroup$
    – dddr rddd
    Commented Jun 27, 2023 at 22:06
  • $\begingroup$ Yes I think an implementation of this would be helpfull $\endgroup$
    – dddr rddd
    Commented Jun 27, 2023 at 22:07

1 Answer 1

0
$\begingroup$

Here is an example, it converts the series into binary. It needs a threshold that by default is the average.

I ran some tests with both random and not random and It gives the expected results.

from scipy.stats import norm
import numpy as np
import random

class WaldWolfowitzRunsTest:
    def __init__(self, series, threshold=None):
        self.series = series
        self.threshold = threshold

    def _calculate_p_value(self, z_value):
        """
        Calculates the p value given a z value.
        Here we assume using the normal distribution.
        """
        return 2 * norm.sf(abs(z_value))

    def _get_runs_list(self):
        """
        Given the series, create the runs list.
        i.e. label the series and sort the concatenated lists, and then return the list of labels.
        """
        labels = []
        if self.threshold is None:
            threshold = np.mean(self.series)
        else:
            threshold = self.threshold

        for value in self.series:
            if value > threshold:
                labels.append("X")
            else:
                labels.append("Y")

        return labels

    def _calculate_z_score(self, nruns, mean, variance):
        """
        Calculates the z-score.
        """
        return (nruns - mean) / np.sqrt(variance)

    def _calculate_mean(self, n_plus, n_min):
        """
        Calculates the mean, defined as:
        (2 * n_plus * n_min)/N + 1
        """
        numerator = 2 * n_plus * n_min
        denominator = n_plus + n_min
        return numerator / float(denominator) + 1

    def _calculate_variance(self, mean, n):
        """
        Calculates the variance.
        """
        assert n > 1, "The number of elements should be higher than 1"
        return ((mean - 1) * (mean - 2)) / float(n - 1)

    def _calculate_nruns(self, labels):
        """
        Calculate the number of runs.
        A run is defined as the follow-up of the same signs.
        """
        nruns = 0
        last_seen = None

        for label in labels:
            if label != last_seen:
                nruns += 1
            last_seen = label

        return nruns

    def runs_test(self, alpha=0.05):
        """
        Executes the whole Wald-Wolfowitz runs test.
        """
        labels = self._get_runs_list()
        nruns = self._calculate_nruns(labels)
        mean = self._calculate_mean(labels.count("X"), labels.count("Y"))
        variance = self._calculate_variance(mean, len(labels))
        z_score = self._calculate_z_score(nruns, mean, variance)
        p_value = self._calculate_p_value(z_score)

        return p_value >= alpha, p_value



# Example usage
# series = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
series = [random.randint(1, 100) for _ in range(10)]
test = WaldWolfowitzRunsTest(series)
result = test.runs_test()
print("Is random:", result[0])
print("p-value:", result[1])
 

Hope it helps!

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.