I have two observed frequency data, let say

f1 = {100, 200, 150, 100, 50};
f2 = {110, 195, 160, 105, 40};

and i want to know whether these random samples belong to the same distribution using KolmogorovSmirnovTest[]. Since KolmogorovSmirnovTest[] takes raw data, i simulate them based on f1 and f2.

data1 = {};
data2 = {};
k = 1;
Do[data1 = Join[data1, Table[k n, {f1[[n]]}]], {n, 1, Length[f1]}]
Do[data2 = Join[data2, Table[k n, {f2[[n]]}]], {n, 1, Length[f2]}]

The test gives the result

KolmogorovSmirnovTest[data1, data2]

Is this correct procedure to perform KS on frequency data? I have changed k with any other number and got the same result. Thank you.

  • 2
    $\begingroup$ is that a question in regard to Mathematica, the software by Wolfram? Or rather a general maths question? If it is the latter, you might want to post on math.stackexchange.com $\endgroup$ Commented Oct 16, 2013 at 7:45
  • 2
    $\begingroup$ Perhaps you can adapt your data to use KolmogorovSmirnovTest[] ? $\endgroup$
    – stathisk
    Commented Oct 16, 2013 at 8:12
  • $\begingroup$ ok. it seems KS is the best test in this case. it's symmetrical. $\endgroup$
    – Deco
    Commented Oct 16, 2013 at 8:21

2 Answers 2


Does re-creating the original data yield the same result?

What you are doing would indeed be a very intuitive way of getting the same result as with the original data. This follows from the definition of the Kolmogorov-Smirnov test statistic which is the maximum difference between the empirical distribution functions $F$ of the two data sets. $F$ is defined as:

$F_n(x)=\frac{\sum _{i=1}^n I_{X_i\leq x}}{n}$

where $X_i$ is the $i$-th data element and $I_{X_i\leq x}$ is the indicator function which is 1 if $X_i\leq x$ is true and 0 otherwise. Crucial here is that in the calculation of $F$ the data elements are ordered. This makes your reconstruction method possible, because there's no difference between the original unordered data set (that you don't know) and your reconstructed ordered data set as far as the KS statistic is concerned.

Let's test this.

Generate three sample test sets, two with an identical distribution and a third with a slightly different distribution:

d1 = RandomVariate[TruncatedDistribution[{0, 6}, PoissonDistribution[3]], 1000];
d2 = RandomVariate[TruncatedDistribution[{0, 6}, PoissonDistribution[3]], 1000];
d3 = RandomVariate[TruncatedDistribution[{0, 6}, PoissonDistribution[3.4]], 1000];

The test results:

KolmogorovSmirnovTest[d1, d2]


KolmogorovSmirnovTest[d1, d3]


Turn the data into frequencies:

f1 = (Sort@Tally[d1])[[All, 2]]
f2 = (Sort@Tally[d2])[[All, 2]]
f3 = (Sort@Tally[d3])[[All, 2]]

Turn this, using your procedure, into the original (but sorted) data:

dd1 = Flatten@MapIndexed[ConstantArray[#2[[1]], #1] &, f1];
dd2 = Flatten@MapIndexed[ConstantArray[#2[[1]], #1] &, f2];
dd3 = Flatten@MapIndexed[ConstantArray[#2[[1]], #1] &, f3];

I used a more functional approach to re-create the data, but in principle it is the same as yours.

As you can see, the test result are the same:

KolmogorovSmirnovTest[dd1, dd2]


KolmogorovSmirnovTest[dd1, dd3]


Two sample Kolmogorov-Smirnov test on discrete data

The above treatment assumed that it is correct to perform the KS test on discrete data sets (with lots of ties). The documentation, however, states that KS is intended for continuous data.

Using the KS function as it is would yield the following on the data you provided:

f1 = {100, 200, 150, 100, 50};
f2 = {110, 195, 160, 105, 40};

dd1 = Flatten@MapIndexed[ConstantArray[#2[[1]], #1] &, f1];
dd2 = Flatten@MapIndexed[ConstantArray[#2[[1]], #1] &, f2];

KolmogorovSmirnovTest[dd1, dd2]


A better test would be a Monte Carlo simulation. KolmogorovSmirnovTest has this built-in:

KolmogorovSmirnovTest[dd1, dd2, Method -> "MonteCarlo"]


What it does is presumably something like the following:

Pool the two data sets. $H_0$ is that the two sets are from the same distribution; this one:

pooled = Join[dd1, dd2]; 

Calculate the KS statistic for the original sets:

uniqueDataValues = Union[pooled];
da1 = #/#[[-1]] &[Accumulate[Count[dd1, #] & /@ uniqueDataValues]];
da2 = #/#[[-1]] &[Accumulate[Count[dd2, #] & /@ uniqueDataValues]];    
ksstat = Max[Abs[da1 - da2]]

Now randomly draw new sets from the pooled set and calculated the new statistic. Count how often its value is greater or equal to the original value. This gives the p-value:

   dr = RandomSample[pooled, Length@pooled];
   uniqueDataValues = Union[dr];
   dr1 = #/#[[-1]] &[Accumulate[Count[Take[dr, Length@dd1], #] & /@ uniqueDataValues]];
   dr2 = #/#[[-1]] &[Accumulate[Count[Drop[dr, Length@dd1], #] & /@ uniqueDataValues]];
   Boole[Max[Abs[dr1 - dr2]] >= ksstat],
 ] // Mean // N


Corresponds nicely to the built-in test value (and the one in Ray's answer). I note that Ray's answer is very slow for large datasets as its complexity is $O[n_1\times n_2]$. The built-in MonteCarlo method seems to be slower as well (for the same amount of samples specified using Method -> {"MonteCarlo", "MonteCarloSamples" -> 100000}).


The K-S test is appropriate here if the five categories are ordered. Then the exact p-value, conditional on the distribution of ties in the pooled data, is .8535 (rounded to 4 places). See here for background and code, and here for a corrected version that fixes a special-case error noted by the OP.


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.