# Best algorithm to capture non-randomness in series of numbers

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?

• 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) Commented Jun 27, 2023 at 19:32
• Thanks very much for your response Commented Jun 27, 2023 at 22:06
• Yes I think an implementation of this would be helpfull Commented Jun 27, 2023 at 22:07

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!