poisson-rate-test

Purpose

A Rust library that provides a methods for comparing the rates of poisson data and conducing hypothesis tests about that data.

Specifically, two types of tests are provided as of 1.0, Rate-to-rate comparisons (2 events), and ratio-to-ration comparisons (4 events).

Rate-to-rate

This tests the hypothesis that the number of events A and the number of events B in a given set of data have a rate of the form r_a / r_b >= R, for a constant R against the null hypothesis that the two events occur with the same rate.

Example: Testing the rate of events against a hypothesis

rust use poisson_ratio_test::two_tailed_rates_equal; //make some data that sure looks like it occurs with rate = 0.5; let data = vec![0,1,1,0]; //note, 0,2,0,0 would be the same (2/4). let n1 = data.len() as f64; let sum1 = data.iter().sum::<usize>() as f64; //are these rates equal to my hypothesized rate of 0.5? let expected_n = n1; let expected_sum = 0.5 * n1; let p = two_tailed_rates_equal(sum1, n1, expected_sum, expected_n); assert!(p>0.99); //<--confidently yes

Example, comparing the rate of events under a new condition

```rust use claim::{assertlt,assertgt}; use poissonratiotest::{onetailedratio,twotailedratesequal}; //say we made a change, and observed the new rates let occurancesobserved = vec![0,0,1,0]; //and here's the "usual" data let occurancesusual = vec![1,1,5,3,3,8]; //need the basic n/sum statistics let n1 = occurancesobserved.len() as f64; let n2 = occurancesusual.len() as f64; let sum1 = occurancesobserved.iter().sum::() as f64; let sum2 = occurancesusual.iter().sum::() as f64; //is rate of observed > rate usual? let p = onetailedratio(sum1, n1, sum2, n2, 1.0); assertlt!(p,0.01); //<--confidently no

//Maybe just check both tails to be sure (this tests r observed / r baseline != 1) let p = twotailedratesequal(sum1, n1, sum2, n2); assertlt!(p,0.01); //<--confidently no ```

Example, more data helps:

Here's a long example, see more in the docs

```rust use claim::{assertlt,assertgt}; use poissonratiotest::{onetailedratio,twotailedrates_equal};

//create data where rate1 == 1/2 * rate2 let occurancesone = vec![1,0,1,0,1,0]; let occurancestwo = vec![1,1,1,1,0,2]; let n1 = occurancesone.len() as f64; let n2 = occurancestwo.len() as f64; let sum1 = occurancesone.iter().sum::() as f64; let sum2 = occurancestwo.iter().sum::() as f64;

//test hypothesis that r1/r2 > 1/2 let p = onetailedratio(sum1, n1, sum2, n2, 0.5); asserteq!(p, 0.50); //<-- nope //let's test the neighbordhood around that let p = onetailedratio(sum1, n1, sum2, n2, 0.49999 ); assertgt!(p, 0.49); //<-- still nope

//Two sided test. What is the likelihood of seeing the data we got //given that r1/r2 == 1/2? let phalf = onetailedratio(sum1, n1, sum2, n2, 0.49999); //other side let pdouble = onetailedratio(sum2, n2, sum1, n1, 2.0001); //just about 1.0! assertgt!(2.0*phalf.min(p_double),0.99);

//we know they are not equal, but can we prove it in general? let mut pdouble = twotailedratesequal(sum2, n2, sum1, n1); //note: pdouble is in [.15,.25] assertlt!(pdouble,0.25);//<--looking unlikely... maybe more data is required assertgt!(p_double,0.15);//<--looking unlikely... maybe more data is required

//get more of the same data let trial2one = vec![1,0,1,0,1,0,1,0,1,0,1,0,1,0]; let trial2two = vec![1,1,1,1,0,2,0,2,1,1,0,2,1,1]; let t2n1 = trial2one.len() as f64; let t2n2 = trial2two.len() as f64; let t2sum1 = trial2one.iter().sum::() as f64; let t2sum2 = trial2two.iter().sum::() as f64; pdouble = twotailedratesequal(t2sum2, t2n2, t2sum1, t2n1); assertlt!(pdouble,0.05);//<--That did the trick ```

Comparing ratio of events

Suppose there's two events, a and b. And we have two groups (base and treatment). We changed something in treatment, and want to know if that change affected the ratio of a/b. So, we count up a and b for both baseline and treatment. note the p -vals are estimated from simulation, so they might change a little (as in 0.01 or so) between different runs. Pass in a higher sample count to stabilize, at the expense of cpu cost.

Example: Comparing a new weapon in Hunt Showdown

This is how it's done in kda-tools

```rust use poissonratetest::bootstrap::param::ratioeventsgreaterpval; use claim::{assertlt,assertgt}; //57 matches, 50 kills, 27 deaths without Caldwell Conversion pistol (baseline) let normalmatches = 57; let normalkills = 50; let normaldeaths = 27; //10 matches, 4 kills, 9 deaths with Caldell Conversion pistol (treatment) let ccmatches=10; let cckills=4; let cc_deaths=9;

let pcctreatmentgreater= bootstrap::param::ratioeventsgreaterpval( normalkills,normaldeaths, normalmatches, cckills,ccdeaths, ccmatches, ).unwrap() ; assertgt!(pcctreatmentgreater,0.90); //Hell no that's not greater (cckills/ccdeaths) is much less than normalkills/normaldeaths let pcctreatmentless = bootstrap::param::ratioeventsgreaterpval( cckills,ccdeaths, ccmatches, normalkills,normaldeaths, normalmatches, ).unwrap() ;
assertlt!(pcctreatmentless,0.05); //very high significance / very low p-value ```

```rust use poissonratetest::boostrap::param::ratioeventsequalpvaln; use claim::{assertlt,assertgt}; let basea = vec![0,0,1,0]; let baseb = vec![1,0,1,1]; let treata = vec![1,1,1,2]; let treatb = vec![1,1,1,1]; //Did treatment increase ratio of a/b? let p = bootstrap::param::ratioeventsequalpvaln( basea.iter().sum::(), baseb.iter().sum::(), basea.len() as usize, treata.iter().sum::(), treatb.iter().sum::(), treata.len() as usize, 10000 ); assertlt!(p.unwrap(),0.15); //<--tentatively yes assertgt!(p.unwrap(),0.05);

//just need more data, right? let basea = vec![0,0,1,0, 1,0,0,0]; let baseb = vec![1,0,1,1, 0,1,1,1]; let treata = vec![1,1,1,2, 1,2,1,1]; let treatb = vec![1,1,1,1, 1,1,1,1]; //Did treatment increase ratio of a/b? let p = bootstrap::param::ratioeventsequalpvaln( basea.iter().sum::(), baseb.iter().sum::(), basea.len() as usize, treata.iter().sum::(), treatb.iter().sum::(), treata.len() as usize, 10000 ); assertlt!(p.unwrap(),0.05); //<--confidently yes assertgt!(p.unwrap(),0.01); ```

Ratio to ratio

This tests the hypothesis that two events occur with different ratios in two datasets r1_a/r2_b >= r2_a/r2_b against the null hypothesis that they are equal.

Why

A test statistic of interst in games is the ratio of events (such as Kills / Deaths for various loadouts), or rates of kills / match with and without items.

I use it in kda-tools for hypothesis testing loadouts in Hunt Showdown.