SignificanceTest.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. <?php
  2. namespace MathPHP\Tests\Statistics;
  3. use MathPHP\Statistics\Average;
  4. use MathPHP\Statistics\Descriptive;
  5. use MathPHP\Statistics\Significance;
  6. use MathPHP\Exception;
  7. class SignificanceTest extends \PHPUnit\Framework\TestCase
  8. {
  9. /**
  10. * @test zScore table value
  11. * @dataProvider dataProviderForZScore
  12. * @param float $μ
  13. * @param float $σ
  14. * @param float $M
  15. * @param float $expected
  16. */
  17. public function testZScore(float $μ, float $σ, float $M, float $expected)
  18. {
  19. // When
  20. $z = Significance::zScore($M, $μ, $σ, Significance::Z_TABLE_VALUE);
  21. // Then
  22. $this->assertEqualsWithDelta($expected, $z, 0.001);
  23. }
  24. /**
  25. * @return array [μ, σ, M, z]
  26. */
  27. public function dataProviderForZScore(): array
  28. {
  29. return [
  30. [1, 1, 1, 0],
  31. [1, 1, 2, 1],
  32. [4, 0.5, 5.5, 3.0],
  33. [4, 0.5, 3, -2.0],
  34. [3.6, 0.4, 3.3, -0.75],
  35. [943, 36.8, 1032.44, 2.43],
  36. [943, 36.8, 803.2, -3.80],
  37. ];
  38. }
  39. /**
  40. * @test zScore raw value
  41. * @dataProvider dataProviderForZScoreRaw
  42. * @param float $μ
  43. * @param float $σ
  44. * @param float $M
  45. * @param float $expected
  46. */
  47. public function testZScoreRaw(float $μ, float $σ, float $M, float $expected)
  48. {
  49. // When
  50. $z = Significance::zScore($M, $μ, $σ, Significance::Z_RAW_VALUE);
  51. // Then
  52. $this->assertEqualsWithDelta($expected, $z, 0.01);
  53. }
  54. /**
  55. * @return array [μ, σ, M, z]
  56. */
  57. public function dataProviderForZScoreRaw(): array
  58. {
  59. return [
  60. [1, 1, 1, 0],
  61. [1, 1, 2, 1],
  62. [4, 0.5, 5.5, 3.0],
  63. [4, 0.5, 3, -2.0],
  64. [3.6, 0.4, 3.3, -0.75],
  65. [943, 36.8, 1032.44, 2.43],
  66. [943, 36.8, 803.2, -3.80434783],
  67. ];
  68. }
  69. /**
  70. * @test sem
  71. * @dataProvider dataProviderForSem
  72. * @param float $σ
  73. * @param int $n
  74. * @param float $expected
  75. */
  76. public function testSem(float $σ, int $n, float $expected)
  77. {
  78. // When
  79. $sem = Significance::sem($σ, $n);
  80. // Then
  81. $this->assertEqualsWithDelta($expected, $sem, 0.0001);
  82. }
  83. /**
  84. * @return array [σ, n, sem]
  85. */
  86. public function dataProviderForSem(): array
  87. {
  88. return [
  89. [5, 100, 0.5],
  90. [6, 200, 0.4242640687119],
  91. [5, 35, 0.8451542547285],
  92. ];
  93. }
  94. /**
  95. * @test zTestOneSample
  96. * @dataProvider dataProviderForZTestOneSample
  97. * @param float $Hₐ
  98. * @param int $n
  99. * @param float $H₀
  100. * @param float $σ
  101. * @param array $expected
  102. */
  103. public function testZTestOneSample(float $Hₐ, int $n, float $H₀, float $σ, array $expected)
  104. {
  105. // When
  106. $zTest = Significance::zTest($Hₐ, $n, $H₀, $σ);
  107. // Then
  108. $this->assertEqualsWithDelta($expected, $zTest, 0.001);
  109. }
  110. /**
  111. * @return array [Hₐ, n, H₀, σ, ztest]
  112. * Test data created from these sites:
  113. * - http://www.socscistatistics.com/tests/ztest_sample_mean/Default2.aspx
  114. * - https://www.easycalculation.com/statistics/p-value-for-z-score.php
  115. */
  116. public function dataProviderForZTestOneSample(): array
  117. {
  118. return [
  119. [96, 55, 100, 12, ['z' => -2.4720661623652, 'p1' => 0.00676, 'p2' => 0.013436]],
  120. [83, 40, 80, 5, ['z' => 3.79473, 'p1' => 0.0001, 'p2' => 0.0001]],
  121. [20, 200, 19.2, 6, ['z' => 1.88562, 'p1' => 0.02938, 'p2' => 0.0593]],
  122. [22.875, 35, 19.5, 5, ['z' => 3.99335, 'p1' => 0.0001, 'p2' => 0.0001]],
  123. [112, 30, 100, 15, ['z' => 4.38178, 'p1' => 0.0000, 'p2' => 0.0000]],
  124. [18.9, 200, 21, 5, ['z' => -5.9397, 'p1' => 0.0000, 'p2' => 0.0000]],
  125. [6.7, 29, 5, 7.1, ['z' => 1.28941, 'p1' => 0.0986, 'p2' => 0.1973]],
  126. [80.94, 25, 85, 11.6, ['z' => -1.75, 'p1' => 0.0401, 'p2' => 0.080118]],
  127. ];
  128. }
  129. /**
  130. * @test zTestTwoSample
  131. * @dataProvider dataProviderForZTestTwoSample
  132. * @param float $μ₁
  133. * @param float $μ₂
  134. * @param int $n₁
  135. * @param int $n₂
  136. * @param float $σ₁
  137. * @param float $σ₂
  138. * @param float $Δ
  139. * @param array $expected
  140. */
  141. public function testZTestTwoSample(float $μ₁, float $μ₂, int $n₁, int $n₂, float $σ₁, float $σ₂, float $Δ, array $expected)
  142. {
  143. // When
  144. $zTest = Significance::zTestTwoSample($μ₁, $μ₂, $n₁, $n₂, $σ₁, $σ₂, $Δ);
  145. // Then
  146. $this->assertEqualsWithDelta($expected, $zTest, 0.001);
  147. }
  148. /**
  149. * @return array [μ₁, μ₂, n₁, n₂, σ₁, σ₂, Δ, ztest]
  150. * Test data created using this online calculator: http://www.mathcracker.com/z-test-for-two-means.php
  151. */
  152. public function dataProviderForZTestTwoSample(): array
  153. {
  154. return [
  155. [28, 33, 75, 50, 14.1, 9.5, 0, ['z' => -2.36868418147285, 'p1' => 0.00893, 'p2' => 0.0179]],
  156. [9.78, 15.10, 900, 1000, 4.05, 4.28, 0, ['z' => -27.83, 'p1' => 0.0, 'p2' => 0.0]], // Test data: http://www.stat.ucla.edu/~cochran/stat10/winter/lectures/lect21.html
  157. [150.0648965, 126.7361145, 68, 292, 233.8012747, 199.3031358, 0, ['z' => 0.761, 'p1' => 0.22335, 'p2' => 0.4467]], // Github issue 175 test data
  158. [3100, 2750, 75, 75, 420, 425, 0, ['z' => 5.073, 'p1' => 0.0000, 'p2' => 0.0000]],
  159. [34.5, 34.9, 80, 90, 0.4, 0.8, 0, ['z' => -4.191, 'p1' => 0.0, 'p2' => 0.0]],
  160. [12.2, 9.2, 1000, 1000, 10.2, 9.9, 0, ['z' => 6.674, 'p1' => 0.0, 'p2' => 0.0]],
  161. ];
  162. }
  163. /**
  164. * @test tScore
  165. * @dataProvider dataProviderForTScore
  166. * @param float $Hₐ
  167. * @param float $s
  168. * @param int $n
  169. * @param float $H₀
  170. * @param float $expected
  171. */
  172. public function testTScore(float $Hₐ, float $s, int $n, float $H₀, float $expected)
  173. {
  174. // When
  175. $t = Significance::tScore($Hₐ, $s, $n, $H₀);
  176. // Then
  177. $this->assertEqualsWithDelta($expected, $t, 0.001);
  178. }
  179. /**
  180. * @return array [Hₐ, s, n, H₀, t]
  181. */
  182. public function dataProviderForTScore(): array
  183. {
  184. return [
  185. [130.1, 21.21, 100, 120, 4.762],
  186. [280, 50, 15, 300, -1.549],
  187. ];
  188. }
  189. /**
  190. * @test tTest one sample
  191. * @dataProvider dataProviderForTTestOneSample
  192. * @param array $a
  193. * @param float $H₀
  194. * @param array $expected
  195. * @throws Exception\BadParameterException
  196. */
  197. public function testTTestWithOneSampleData(array $a, float $H₀, array $expected)
  198. {
  199. // When
  200. $tTest = Significance::tTest($a, $H₀);
  201. // Then
  202. $this->assertEqualsWithDelta($expected['t'], $tTest['t'], 0.00001);
  203. $this->assertEqualsWithDelta($expected['df'], $tTest['df'], 0.00001);
  204. $this->assertEqualsWithDelta($expected['p1'], $tTest['p1'], 0.0001);
  205. $this->assertEqualsWithDelta($expected['p2'], $tTest['p2'], 0.00001);
  206. $this->assertEqualsWithDelta($expected['mean'], $tTest['mean'], 0.00001);
  207. $this->assertEqualsWithDelta($expected['sd'], $tTest['sd'], 0.00001);
  208. }
  209. /**
  210. * @test tTestOneSample
  211. * @dataProvider dataProviderForTTestOneSample
  212. * @param array $a
  213. * @param float $H₀
  214. * @param array $expected
  215. */
  216. public function testTTestOneSample(array $a, float $H₀, array $expected)
  217. {
  218. // When
  219. $tTest = Significance::tTestOneSample($a, $H₀);
  220. // Then
  221. $this->assertEqualsWithDelta($expected['t'], $tTest['t'], 0.00001);
  222. $this->assertEqualsWithDelta($expected['df'], $tTest['df'], 0.00001);
  223. $this->assertEqualsWithDelta($expected['p1'], $tTest['p1'], 0.0001);
  224. $this->assertEqualsWithDelta($expected['p2'], $tTest['p2'], 0.00001);
  225. $this->assertEqualsWithDelta($expected['mean'], $tTest['mean'], 0.00001);
  226. $this->assertEqualsWithDelta($expected['sd'], $tTest['sd'], 0.00001);
  227. }
  228. /**
  229. * @test tTestOneSampleFromSummaryData
  230. * @dataProvider dataProviderForTTestOneSample
  231. * @param array $a
  232. * @param float $H₀
  233. * @param array $expected
  234. */
  235. public function testTTestOneSampleFromSummaryData(array $a, float $H₀, array $expected)
  236. {
  237. // Given
  238. $Hₐ = Average::mean($a);
  239. $s = Descriptive::standardDeviation($a, Descriptive::SAMPLE);
  240. $n = count($a);
  241. // When
  242. $tTest = Significance::tTestOneSampleFromSummaryData($Hₐ, $s, $n, $H₀);
  243. // Then
  244. $this->assertEqualsWithDelta($expected['t'], $tTest['t'], 0.00001);
  245. $this->assertEqualsWithDelta($expected['df'], $tTest['df'], 0.00001);
  246. $this->assertEqualsWithDelta($expected['p1'], $tTest['p1'], 0.0001);
  247. $this->assertEqualsWithDelta($expected['p2'], $tTest['p2'], 0.00001);
  248. $this->assertEqualsWithDelta($expected['mean'], $tTest['mean'], 0.00001);
  249. $this->assertEqualsWithDelta($expected['sd'], $tTest['sd'], 0.00001);
  250. }
  251. /**
  252. * @return array [a, H₀, expected]
  253. * t, df, p2 generated with R t.test(x, mu=H₀)
  254. * p1 generated with calculators http://www.socscistatistics.com/pvalues/tdistribution.aspx and https://www.danielsoper.com/statcalc/calculator.aspx?id=8
  255. */
  256. public function dataProviderForTTestOneSample(): array
  257. {
  258. return [
  259. [
  260. [65, 78, 88, 55, 48, 95, 66, 57, 79, 81],
  261. 75,
  262. ['t' => -0.7830291, 'df' => 9, 'p1' => 0.226868, 'p2' => 0.4537205, 'mean' => 71.2, 'sd' => 15.34637],
  263. ],
  264. [
  265. [1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 9, 9, 11],
  266. 4,
  267. ['t' => 3.367538, 'df' => 24, 'p1' => 0.001277, 'p2' => 0.002553184, 'mean' => 5.52, 'sd' => 2.256841],
  268. ],
  269. [
  270. [1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 9, 9, 11],
  271. 5,
  272. ['t' => 1.152053, 'df' => 24, 'p1' => 0.130314, 'p2' => 0.2606466, 'mean' => 5.52, 'sd' => 2.256841],
  273. ],
  274. [
  275. [1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 9, 9, 11],
  276. 5.5,
  277. ['t' => 0.04430971, 'df' => 24, 'p1' => 0.482516, 'p2' => 0.9650241, 'mean' => 5.52, 'sd' => 2.256841],
  278. ],
  279. [
  280. [1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 9, 9, 11],
  281. 5.52,
  282. ['t' => 0, 'df' => 24, 'p1' => 0.5, 'p2' => 1, 'mean' => 5.52, 'sd' => 2.256841],
  283. ],
  284. [
  285. [1, 2, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 9, 9, 11],
  286. 6,
  287. ['t' => -1.063433, 'df' => 24, 'p1' => 0.149084, 'p2' => 0.298169, 'mean' => 5.52, 'sd' => 2.256841],
  288. ],
  289. [
  290. [5, 5.5, 4.5, 5, 5, 6, 5, 5, 4.5, 5, 5, 4.5, 4.5, 5.5, 4, 5, 5, 5.5, 4.5, 5.5, 5, 5.5],
  291. 4.7,
  292. ['t' => 3.039737, 'df' => 21, 'p1' => 0.003115, 'p2' => 0.006228674, 'mean' => 5, 'sd' => 0.46291],
  293. ],
  294. [
  295. [5, 5.5, 4.5, 5, 5, 6, 5, 5, 4.5, 5, 5, 4.5, 4.5, 5.5, 4, 5, 5, 5.5, 4.5, 5.5, 5, 5.5],
  296. 4.8,
  297. ['t' => 2.026491, 'df' => 21, 'p1' => 0.027806, 'p2' => 0.05560202, 'mean' => 5, 'sd' => 0.46291],
  298. ],
  299. [
  300. [5, 5.5, 4.5, 5, 5, 6, 5, 5, 4.5, 5, 5, 4.5, 4.5, 5.5, 4, 5, 5, 5.5, 4.5, 5.5, 5, 5.5],
  301. 4.9,
  302. ['t' => 1.013246, 'df' => 21, 'p1' => 0.161248, 'p2' => 0.3224757, 'mean' => 5, 'sd' => 0.46291],
  303. ],
  304. [
  305. [5, 5.5, 4.5, 5, 5, 6, 5, 5, 4.5, 5, 5, 4.5, 4.5, 5.5, 4, 5, 5, 5.5, 4.5, 5.5, 5, 5.5],
  306. 4.99,
  307. ['t' => 0.1013246, 'df' => 21, 'p1' => 0.460137, 'p2' => 0.920254, 'mean' => 5, 'sd' => 0.46291],
  308. ],
  309. [
  310. [5, 5.5, 4.5, 5, 5, 6, 5, 5, 4.5, 5, 5, 4.5, 4.5, 5.5, 4, 5, 5, 5.5, 4.5, 5.5, 5, 5.5],
  311. 5,
  312. ['t' => 0, 'df' => 21, 'p1' => 0.5, 'p2' => 1, 'mean' => 5, 'sd' => 0.46291],
  313. ],
  314. [
  315. [5, 5.5, 4.5, 5, 5, 6, 5, 5, 4.5, 5, 5, 4.5, 4.5, 5.5, 4, 5, 5, 5.5, 4.5, 5.5, 5, 5.5],
  316. 5.01,
  317. ['t' => -0.1013246, 'df' => 21, 'p1' => 0.46013665, 'p2' => 0.920254, 'mean' => 5, 'sd' => 0.46291],
  318. ],
  319. [
  320. [5, 5.5, 4.5, 5, 5, 6, 5, 5, 4.5, 5, 5, 4.5, 4.5, 5.5, 4, 5, 5, 5.5, 4.5, 5.5, 5, 5.5],
  321. 5.1,
  322. ['t' => -1.013246, 'df' => 21, 'p1' => 0.16124847, 'p2' => 0.3224757, 'mean' => 5, 'sd' => 0.46291],
  323. ],
  324. [
  325. [128, 118, 144, 133, 132, 111, 149, 139, 136, 126, 127, 115, 142, 140, 131, 132, 122, 119, 129, 128],
  326. 120,
  327. ['t' => 4.512404, 'df' => 19, 'p1' => 0.00011919, 'p2' => 0.0002383806, 'mean' => 130.05, 'sd' => 9.960316],
  328. ],
  329. [
  330. [128, 118, 144, 133, 132, 111, 149, 139, 136, 126, 127, 115, 142, 140, 143, 132, 122, 119, 129, 128],
  331. 120,
  332. ['t' => 4.591373, 'df' => 19, 'p1' => 0.00009966, 'p2' => 0.0001993183, 'mean' => 130.65, 'sd' => 10.37342],
  333. ],
  334. ];
  335. }
  336. /**
  337. * @test testTestFromSummaryData more tests
  338. * @dataProvider dataProviderForTTestOneSampleFromSummaryData
  339. * @param float $Hₐ
  340. * @param float $s
  341. * @param int $n
  342. * @param float $H₀
  343. * @param array $expected
  344. */
  345. public function testTTestOneSampleFromSummaryData2(float $Hₐ, float $s, int $n, float $H₀, array $expected)
  346. {
  347. // When
  348. $tTest = Significance::tTestOneSampleFromSummaryData($Hₐ, $s, $n, $H₀);
  349. // Then
  350. $this->assertEqualsWithDelta($expected, $tTest, 0.001);
  351. }
  352. /**
  353. * @return array [Hₐ, s, n, H₀, ttest]
  354. */
  355. public function dataProviderForTTestOneSampleFromSummaryData(): array
  356. {
  357. return [
  358. [130.1, 21.21, 100, 120, ['t' => 4.762, 'df' => 99, 'p1' => 0, 'p2' => 0, 'mean' => 130.1, 'sd' => 21.21]],
  359. [280, 50, 15, 300, ['t' => -1.549, 'df' => 14, 'p1' => 0.0718, 'p2' => 0.1437, 'mean' => 280, 'sd' => 50]],
  360. [130.5, 32.4, 30, 142.1, ['t' => -1.9609820, 'df' => 29, 'p1' => 0.02977385, 'p2' => 0.05954770, 'mean' => 130.5, 'sd' => 32.4]],
  361. [25.12, 2.91, 18, 24.64, ['t' => 0.69981702, 'df' => 17, 'p1' => 0.24675380, 'p2' => 0.4935, 'mean' => 25.12, 'sd' => 2.91]]
  362. ];
  363. }
  364. /**
  365. * @test tTest for two samples
  366. * @dataProvider dataProviderFortTestTwoSampleDataSet
  367. * @param array $x₁
  368. * @param array $x₂
  369. * @param float $μ₁ Sample mean of population 1
  370. * @param float $μ₂ Sample mean of population 2
  371. * @param int $n₁ Sample size of population 1
  372. * @param int $n₂ Sample size of population 1
  373. * @param float $σ₁ Standard deviation of sample mean 1
  374. * @param float $σ₂ Standard deviation of sample mean 2
  375. * @param array $expected
  376. * @throws Exception\BadParameterException
  377. */
  378. public function testtTestWithTwoSamples(array $x₁, array $x₂, float $μ₁, float $μ₂, int $n₁, int $n₂, float $σ₁, float $σ₂, array $expected)
  379. {
  380. // When
  381. $tTest = Significance::tTest($x₁, $x₂);
  382. // Then
  383. $this->assertEqualsWithDelta($expected['t'], $tTest['t'], 0.00001);
  384. $this->assertEqualsWithDelta($expected['df'], $tTest['df'], 0.00001);
  385. $this->assertEqualsWithDelta($expected['p1'], $tTest['p1'], 0.0001);
  386. $this->assertEqualsWithDelta($expected['p2'], $tTest['p2'], 0.00001);
  387. $this->assertEqualsWithDelta($μ₁, $tTest['mean1'], 0.00001);
  388. $this->assertEqualsWithDelta($μ₂, $tTest['mean2'], 0.00001);
  389. $this->assertEqualsWithDelta($σ₁, $tTest['sd1'], 0.00001);
  390. $this->assertEqualsWithDelta($σ₂, $tTest['sd2'], 0.00001);
  391. }
  392. /**
  393. * @test tTestTwoSample
  394. * @dataProvider dataProviderFortTestTwoSampleDataSet
  395. * @param array $x₁
  396. * @param array $x₂
  397. * @param float $μ₁ Sample mean of population 1
  398. * @param float $μ₂ Sample mean of population 2
  399. * @param int $n₁ Sample size of population 1
  400. * @param int $n₂ Sample size of population 1
  401. * @param float $σ₁ Standard deviation of sample mean 1
  402. * @param float $σ₂ Standard deviation of sample mean 2
  403. * @param array $expected
  404. */
  405. public function testtTestTwoSample(array $x₁, array $x₂, float $μ₁, float $μ₂, int $n₁, int $n₂, float $σ₁, float $σ₂, array $expected)
  406. {
  407. // When
  408. $tTest = Significance::tTestTwoSample($x₁, $x₂);
  409. // Then
  410. $this->assertEqualsWithDelta($expected['t'], $tTest['t'], 0.00001);
  411. $this->assertEqualsWithDelta($expected['df'], $tTest['df'], 0.00001);
  412. $this->assertEqualsWithDelta($expected['p1'], $tTest['p1'], 0.0001);
  413. $this->assertEqualsWithDelta($expected['p2'], $tTest['p2'], 0.00001);
  414. $this->assertEqualsWithDelta($μ₁, $tTest['mean1'], 0.00001);
  415. $this->assertEqualsWithDelta($μ₂, $tTest['mean2'], 0.00001);
  416. $this->assertEqualsWithDelta($σ₁, $tTest['sd1'], 0.00001);
  417. $this->assertEqualsWithDelta($σ₂, $tTest['sd2'], 0.00001);
  418. }
  419. /**
  420. * @test tTestTwoSampleFromSummaryData
  421. * @dataProvider dataProviderFortTestTwoSampleDataSet
  422. * @param array $x₁
  423. * @param array $x₂
  424. * @param float $μ₁ Sample mean of population 1
  425. * @param float $μ₂ Sample mean of population 2
  426. * @param int $n₁ Sample size of population 1
  427. * @param int $n₂ Sample size of population 1
  428. * @param float $σ₁ Standard deviation of sample mean 1
  429. * @param float $σ₂ Standard deviation of sample mean 2
  430. * @param array $expected
  431. */
  432. public function testtTestTwoSampleFromSummaryData(array $x₁, array $x₂, float $μ₁, float $μ₂, int $n₁, int $n₂, float $σ₁, float $σ₂, array $expected)
  433. {
  434. // When
  435. $tTest = Significance::tTestTwoSampleFromSummaryData($μ₁, $μ₂, $n₁, $n₂, $σ₁, $σ₂);
  436. // Then
  437. $this->assertEqualsWithDelta($expected['t'], $tTest['t'], 0.00001);
  438. $this->assertEqualsWithDelta($expected['df'], $tTest['df'], 0.00001);
  439. $this->assertEqualsWithDelta($expected['p1'], $tTest['p1'], 0.0001);
  440. $this->assertEqualsWithDelta($expected['p2'], $tTest['p2'], 0.00001);
  441. $this->assertEqualsWithDelta($μ₁, $tTest['mean1'], 0.00001);
  442. $this->assertEqualsWithDelta($μ₂, $tTest['mean2'], 0.00001);
  443. $this->assertEqualsWithDelta($σ₁, $tTest['sd1'], 0.00001);
  444. $this->assertEqualsWithDelta($σ₂, $tTest['sd2'], 0.00001);
  445. }
  446. /**
  447. * @return array [x₁, x₂, μ₁, μ₂, n₁, n₂, σ₁, σ₂, expected]
  448. * t, df, p2 generated with R t.test(x, y)
  449. * p1 generated with calculator http://www.socscistatistics.com/pvalues/tdistribution.aspx
  450. */
  451. public function dataProviderFortTestTwoSampleDataSet(): array
  452. {
  453. return [
  454. [
  455. [42.1, 41.3, 42.4, 43.2, 41.8, 41.0, 41.8, 42.8, 42.3, 42.7],
  456. [42.7, 43.8, 42.5, 43.1, 44.0, 43.6, 43.3, 43.5, 41.7, 44.1],
  457. 42.14, 43.23, 10, 10, 0.6834553, 0.7498889,
  458. ['t' => -3.397231, 'df' => 17.8473, 'p1' => 0.001622, 'p2' => 0.003242249],
  459. ],
  460. [
  461. [30, 31, 32],
  462. [29, 30, 31],
  463. 31, 30, 3, 3, 1, 1,
  464. ['t' => 1.224745, 'df' => 4, 'p1' => 0.14394, 'p2' => 0.2878641],
  465. ],
  466. [
  467. [30.02, 29.99, 30.11, 29.97, 30.01, 29.99],
  468. [29.89, 29.93, 29.72, 29.98, 30.02, 29.98],
  469. 30.015, 29.92, 6, 6, 0.04969909, 0.1078888,
  470. ['t' => 1.959006, 'df' => 7.03056, 'p1' => 0.045387, 'p2' => 0.09077332],
  471. ],
  472. [
  473. [4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 9, 9, 10, 12],
  474. [4, 4, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 11, 13],
  475. 7.222222, 7.352941, 18, 17, 1.926764, 2.316818,
  476. ['t' => -0.1809288, 'df' => 31.20011, 'p1' => 0.428769, 'p2' => 0.8575937],
  477. ],
  478. // Equal variances; equal sizes - Wikipedia https://en.wikipedia.org/wiki/Welch%27s_t-test
  479. [
  480. [27.5, 21.0, 19.0, 23.6, 17.0, 17.9, 16.9, 20.1, 21.9, 22.6, 23.1, 19.6, 19.0, 21.7, 21.4],
  481. [27.1, 22.0, 20.8, 23.4, 23.4, 23.5, 25.8, 22.0, 24.8, 20.2, 21.9, 22.1, 22.9, 20.5, 24.4],
  482. 20.82, 22.98667, 15, 15, 2.804894, 1.952605,
  483. ['t' => -2.455356, 'df' => 24.98853, 'p1' => 0.010698, 'p2' => 0.021378],
  484. ],
  485. // Unequal variances; unequal sizes - Wikipedia https://en.wikipedia.org/wiki/Welch%27s_t-test
  486. [
  487. [17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2, 14.7, 21.8],
  488. [21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8],
  489. 20.61, 22.135, 10, 20, 3.006826, 0.9477258,
  490. ['t' => -1.565434, 'df' => 9.904741, 'p1' => 0.074471, 'p2' => 0.1488417],
  491. ],
  492. // Unequal variances; unequal sizes - Wikipedia https://en.wikipedia.org/wiki/Welch%27s_t-test
  493. [
  494. [19.8, 20.4, 19.6, 17.8, 18.5, 18.9, 18.3, 18.9, 19.5, 22.0],
  495. [28.2, 26.6, 20.1, 23.3, 25.2, 22.1, 17.7, 27.6, 20.6, 13.7, 23.2, 17.5, 20.6, 18.0, 23.9, 21.6, 24.3, 20.4, 24.0, 13.2],
  496. 19.37, 21.59, 10, 20, 1.203744, 4.137111,
  497. ['t' => -2.219241, 'df' => 24.49622, 'p1' => 0.017995, 'p2' => 0.03597227],
  498. ],
  499. [
  500. [35, 40, 12, 15, 21, 14, 46, 10, 28, 48, 16, 30, 32, 48, 31, 22, 12, 39, 19, 25],
  501. [2, 27, 38, 31, 1, 19, 1, 34, 3, 1, 2, 3, 2, 1, 2, 1, 3, 29, 37, 2],
  502. 27.15, 11.95, 20, 20, 12.508, 14.61245,
  503. ['t' => 3.534054, 'df' => 37.11672, 'p1' => 0.000558, 'p2' => 0.0011156],
  504. ],
  505. // Large unequal sample sizes
  506. [
  507. [17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2, 14.7, 21.8, 17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2, 14.7, 21.8, 17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2, 14.7, 21.8, 17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2, 14.7, 21.8, 17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2, 14.7, 21.8, 17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2, 14.7, 21.8, 17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2],
  508. [21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8, 21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8],
  509. 20.67941, 22.135, 68, 300, 2.820266, 0.9252723,
  510. ['t' => -4.205026, 'df' => 70.29978, 'p1' => 0.000076, 'p2' => 7.568864e-05],
  511. ],
  512. ];
  513. }
  514. /**
  515. * @test tTestTwoSampleFromSummaryData regressions
  516. * @dataProvider dataProviderForTTestTwoSampleFromSummaryData
  517. * @param float $μ₁ Sample mean of population 1
  518. * @param float $μ₂ Sample mean of population 2
  519. * @param int $n₁ Sample size of population 1
  520. * @param int $n₂ Sample size of population 1
  521. * @param float $σ₁ Standard deviation of sample mean 1
  522. * @param float $σ₂ Standard deviation of sample mean 2
  523. * @param array $expected
  524. */
  525. public function testTTestTwoSampleFromSummaryDataRegression(float $μ₁, float $μ₂, int $n₁, int $n₂, float $σ₁, float $σ₂, array $expected)
  526. {
  527. // When
  528. $tTest = Significance::tTestTwoSampleFromSummaryData($μ₁, $μ₂, $n₁, $n₂, $σ₁, $σ₂);
  529. // Then
  530. $this->assertEqualsWithDelta($expected['t'], $tTest['t'], 0.0001);
  531. $this->assertEqualsWithDelta($expected['df'], $tTest['df'], 0.00001);
  532. $this->assertEqualsWithDelta($expected['p1'], $tTest['p1'], 0.0001);
  533. $this->assertEqualsWithDelta($expected['p2'], $tTest['p2'], 0.0001);
  534. $this->assertEqualsWithDelta($μ₁, $tTest['mean1'], 0.00001);
  535. $this->assertEqualsWithDelta($μ₂, $tTest['mean2'], 0.00001);
  536. $this->assertEqualsWithDelta($σ₁, $tTest['sd1'], 0.00001);
  537. $this->assertEqualsWithDelta($σ₂, $tTest['sd2'], 0.00001);
  538. }
  539. /**
  540. * @return array [μ₁, μ₂, n₁, n₂, σ₁, σ₂, expected]
  541. */
  542. public function dataProviderForTTestTwoSampleFromSummaryData(): array
  543. {
  544. return [
  545. // Regression issue 265 - data generated with http://www.usablestats.com/calcs/2samplet&summary=1
  546. [
  547. 32, 30, 134, 210, 21, 18,
  548. ['t' => 0.9097, 'df' => 251.72638768068, 'p1' => 0.1819, 'p2' => 0.3638 ],
  549. ],
  550. ];
  551. }
  552. /**
  553. * @test tTest throws an Exception\BadParameterException if the second argument is neither a number nor a string
  554. */
  555. public function testTTestBadParameterException()
  556. {
  557. // Given
  558. $a = [1, 2, 3];
  559. $b = 'string';
  560. // Then
  561. $this->expectException(Exception\BadParameterException::class);
  562. // When
  563. $tTest = Significance::tTest($a, $b);
  564. }
  565. /**
  566. * @test chiSquaredTest
  567. * @dataProvider dataProviderForChiSquaredTest
  568. * @param array $observed
  569. * @param array $expected
  570. * @param float $χ²
  571. * @param float $p
  572. * @throws \Exception
  573. */
  574. public function testChiSquaredTest(array $observed, array $expected, float $χ², float $p)
  575. {
  576. // When
  577. $chi = Significance::chiSquaredTest($observed, $expected);
  578. // Then
  579. $this->assertEqualsWithDelta($χ², $chi['chi-square'], 0.0001);
  580. $this->assertEqualsWithDelta($p, $chi['p'], 0.0001);
  581. }
  582. /**
  583. * @return array [observed, expected, χ², p]
  584. */
  585. public function dataProviderForChiSquaredTest(): array
  586. {
  587. return [
  588. // Example data from Statistics (Freedman, Pisani, Purves)
  589. [
  590. [4, 6, 17, 16, 8, 9],
  591. [10, 10, 10, 10, 10, 10],
  592. 14.2, 0.014388,
  593. ],
  594. [
  595. [5, 7, 17, 16, 8, 7],
  596. [10, 10, 10, 10, 10, 10],
  597. 13.2, 0.0216,
  598. ],
  599. [
  600. [9, 11, 10, 8, 12, 10],
  601. [10, 10, 10, 10, 10, 10],
  602. 1.0, 0.962566,
  603. ],
  604. [
  605. [90, 110, 100, 80, 120, 100],
  606. [100, 100, 100, 100, 100, 100],
  607. 10.0, 0.075235,
  608. ],
  609. [
  610. [10287, 10056, 9708, 10080, 9935, 9934],
  611. [10000, 10000, 10000, 10000, 10000, 10000],
  612. 18.575, 0.0023,
  613. ],
  614. ];
  615. }
  616. /**
  617. * @test chiSquaredTest BadDataException
  618. */
  619. public function testChiSquaredTestExceptionCountsDiffer()
  620. {
  621. // Given
  622. $observed = [1, 2, 3, 4];
  623. $expected = [1, 2, 3];
  624. // Then
  625. $this->expectException(Exception\BadDataException::class);
  626. // When
  627. Significance::chiSquaredTest($observed, $expected);
  628. }
  629. /**
  630. * @test Issue 458 regression test - Division-by-zero error in t-test
  631. * https://github.com/markrogoyski/math-php/issues/458
  632. */
  633. public function testIssue458(): void
  634. {
  635. // Given
  636. $values = [];
  637. for ($i = 0; $i < 95; $i++) {
  638. $values[] = 1;
  639. }
  640. for ($i = 0; $i < 5; $i++) {
  641. $values[] = 0.5;
  642. }
  643. for ($i = 0; $i < 12; $i++) {
  644. $values[] = 0;
  645. }
  646. // When
  647. $tTest = Significance::tTest($values, 0.569);
  648. // Then t-test completed without division-by-zero error
  649. $this->expectNotToPerformAssertions();
  650. }
  651. }