RandomVariableTest.php 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. <?php
  2. namespace MathPHP\Tests\Statistics;
  3. use MathPHP\Exception;
  4. use MathPHP\Statistics\RandomVariable;
  5. class RandomVariableTest extends \PHPUnit\Framework\TestCase
  6. {
  7. /**
  8. * @test centralMoment
  9. * @dataProvider dataProviderForCentralMoment
  10. * @param array $X
  11. * @param int $n
  12. * @param float $expected
  13. * @throws \Exception
  14. */
  15. public function testCentralMoment(array $X, int $n, float $expected)
  16. {
  17. // When
  18. $centralMoment = RandomVariable::centralMoment($X, $n);
  19. // Then
  20. $this->assertEqualsWithDelta($expected, $centralMoment, 0.0001);
  21. }
  22. /**
  23. * @return array [X, n, moment]
  24. */
  25. public function dataProviderForCentralMoment(): array
  26. {
  27. return [
  28. [ [ 600, 470, 170, 430, 300 ], 1, 0 ],
  29. [ [ 600, 470, 170, 430, 300 ], 2, 21704 ],
  30. [ [ 600, 470, 170, 430, 300 ], 3, -568512 ],
  31. ];
  32. }
  33. /**
  34. * @test centralMoment error if X is empty
  35. * @throws \Exception
  36. */
  37. public function testCentralMomentNullIfXEmpty()
  38. {
  39. // Then
  40. $this->expectException(Exception\BadDataException::class);
  41. // When
  42. RandomVariable::centralMoment(array(), 3);
  43. }
  44. /**
  45. * @test populationSkewness
  46. * @dataProvider dataProviderForPopulationSkewness
  47. * @param array $X
  48. * @param float $expected
  49. * @throws \Exception
  50. */
  51. public function testPopulationSkewness(array $X, float $expected)
  52. {
  53. // When
  54. $populationSkewness = RandomVariable::populationSkewness($X);
  55. // Then
  56. $this->assertEqualsWithDelta($expected, $populationSkewness, 0.000001);
  57. }
  58. /**
  59. * Generated with R (e1071) skewness(data, type=1)
  60. * @return array [X, skewness]
  61. */
  62. public function dataProviderForPopulationSkewness(): array
  63. {
  64. return [
  65. [ [61,61,61,61,61,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,73,73,73,73,73,73,73,73], -0.1081544 ],
  66. [ [2, 3, -1, 3, 4, 5, 0, 2], -0.3677454 ],
  67. [ [1, 2, 3, 4, 5, 6, 8, 8], 0.079248 ],
  68. [ [1, 1, 3, 4, 5, 6, 7, 8], -0.079248 ],
  69. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7], 0.3031933 ],
  70. [ [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8], 0.7745239 ],
  71. [ [1,2,3,4,5,6,7,8], 0 ],
  72. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], 1.605855 ],
  73. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7 ], 0.3031933 ],
  74. [ [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8 ], 0.7745239 ],
  75. [ [2, 3, -1, 3, 4, 5, 0, 2], -0.3677454 ],
  76. [ [-2.83, -0.95, -0.88, 1.21, -1.67, 0.83, -0.27, 1.36, -0.34, 0.48, -2.83, -0.95, -0.88, 1.21, -1.67], -0.1561309 ],
  77. [ [13, 18, 13, 14, 13, 16, 14, 21, 13], 1.230469],
  78. ];
  79. }
  80. /**
  81. * @test populationSkewness error if array is empty
  82. * @throws \Exception
  83. */
  84. public function testPopulationSkewnessNullWhenEmptyArray()
  85. {
  86. // Then
  87. $this->expectException(Exception\BadDataException::class);
  88. // When
  89. RandomVariable::populationSkewness(array());
  90. }
  91. /**
  92. * @test sampleSkewness
  93. * @dataProvider dataProviderForSampleSkewness
  94. * @param array $X
  95. * @param float $expected
  96. * @throws \Exception
  97. */
  98. public function testSampleSkewness(array $X, float $expected)
  99. {
  100. // When
  101. $skewness = RandomVariable::sampleSkewness($X);
  102. // Then
  103. $this->assertEqualsWithDelta($expected, $skewness, 0.000001);
  104. }
  105. /**
  106. * Generated with R (e1071) skewness(data, type=2)
  107. * @return array [X, skewness]
  108. */
  109. public function dataProviderForSampleSkewness(): array
  110. {
  111. return [
  112. [ [61,61,61,61,61,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,73,73,73,73,73,73,73,73], -0.1098084 ],
  113. [ [2, 3, -1, 3, 4, 5, 0, 2], -0.4586591 ],
  114. [ [1, 2, 3, 4, 5, 6, 8, 8], 0.09883962 ],
  115. [ [1, 1, 3, 4, 5, 6, 7, 8], -0.09883962 ],
  116. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7], 0.3595431 ],
  117. [ [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8], 0.8633783 ],
  118. [ [1,2,3,4,5,6,7,8], 0 ],
  119. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], 1.946591 ],
  120. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7 ], 0.3595431 ],
  121. [ [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8 ], 0.8633783 ],
  122. [ [2, 3, -1, 3, 4, 5, 0, 2], -0.4586591 ],
  123. [ [-2.83, -0.95, -0.88, 1.21, -1.67, 0.83, -0.27, 1.36, -0.34, 0.48, -2.83, -0.95, -0.88, 1.21, -1.67], -0.1740425 ],
  124. [ [13, 18, 13, 14, 13, 16, 14, 21, 13], 1.491553],
  125. ];
  126. }
  127. /**
  128. * @test sampleSkewness errpr when array is empty
  129. * @throws \Exception
  130. */
  131. public function testSampleSkewnessNullWhenEmptyArray()
  132. {
  133. // Then
  134. $this->expectException(Exception\BadDataException::class);
  135. // When
  136. RandomVariable::sampleSkewness(array());
  137. }
  138. /**
  139. * @test sampleSkewness error when array has fewer than 3 elements
  140. * @throws \Exception
  141. */
  142. public function testSampleSkewnessNullWhenSmallArray()
  143. {
  144. // Then
  145. $this->expectException(Exception\BadDataException::class);
  146. // When
  147. RandomVariable::sampleSkewness([1, 2]);
  148. }
  149. /**
  150. * @test populationSkewness Nan
  151. * @dataProvider dataProviderForSkewnessNan
  152. * @param array $X
  153. * @throws \Exception
  154. */
  155. public function testPopulationSkewnessNan(array $X)
  156. {
  157. // When
  158. $skewness = RandomVariable::populationSkewness($X);
  159. // Then
  160. $this->assertNan($skewness);
  161. }
  162. /**
  163. * @test sampleSkewness Nan
  164. * @dataProvider dataProviderForSkewnessNan
  165. * @param array $X
  166. * @throws \Exception
  167. */
  168. public function testSampleSkewnessNan(array $X)
  169. {
  170. // When
  171. $skewness = RandomVariable::sampleSkewness($X);
  172. // Then
  173. $this->assertNan($skewness);
  174. }
  175. /**
  176. * @test alternativeSkewness Nan
  177. * @dataProvider dataProviderForSkewnessNan
  178. * @param array $X
  179. * @throws \Exception
  180. */
  181. public function testAlternativeSkewnessNan(array $X)
  182. {
  183. // When
  184. $skewness = RandomVariable::alternativeSkewness($X);
  185. // Then
  186. $this->assertNan($skewness);
  187. }
  188. /**
  189. * Generated with R (e1071) skewness(data, type=2)
  190. * @return array [X, skewness]
  191. */
  192. public function dataProviderForSkewnessNan(): array
  193. {
  194. return [
  195. [[-1, -1, -1]],
  196. [[10, 10, 10]],
  197. [[0, 0, 0]],
  198. [[10, 10, 10, 10]],
  199. ];
  200. }
  201. /**
  202. * @test alternativeSkewness
  203. * @dataProvider dataProviderForAlternativeSkewness
  204. * @param array $X
  205. * @param float $expected
  206. * @throws \Exception
  207. */
  208. public function testAlternativeSkewness(array $X, float $expected)
  209. {
  210. // When
  211. $skewness = RandomVariable::alternativeSkewness($X);
  212. // Then
  213. $this->assertEqualsWithDelta($expected, $skewness, 0.000001);
  214. }
  215. /**
  216. * Generated with online calculator: http://www.endmemo.com/statistics/skewness.php
  217. * @return array [X, skewness]
  218. */
  219. public function dataProviderForAlternativeSkewness(): array
  220. {
  221. return [
  222. [ [61,61,61,61,61,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,73,73,73,73,73,73,73,73], -0.107612 ],
  223. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], 1.514015 ],
  224. [ [5,20,40,80,100], 0.202721 ],
  225. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7], 0.287634 ],
  226. [ [1, 1, 3, 4, 5, 6, 7, 8], -0.07413 ],
  227. [ [1,2,3,4,5,6,7,8], 0 ],
  228. [ [13, 18, 13, 14, 13, 16, 14, 21, 13], 1.160097],
  229. ];
  230. }
  231. /**
  232. * @test alternativeSkewness error when array is empty
  233. * @throws \Exception
  234. */
  235. public function testAlternativeSkewnessErrorWhenEmptyArray()
  236. {
  237. // Then
  238. $this->expectException(Exception\BadDataException::class);
  239. // When
  240. RandomVariable::alternativeSkewness(array());
  241. }
  242. /**
  243. * @test skewness
  244. * @dataProvider dataProviderForSkewness
  245. * @param array $X
  246. * @param string $type
  247. * @param float $expected
  248. * @throws \Exception
  249. */
  250. public function testSkewness(array $X, string $type, float $expected)
  251. {
  252. // When
  253. $skewness = RandomVariable::skewness($X, $type);
  254. // Then
  255. $this->assertEqualsWithDelta($expected, $skewness, 0.000001);
  256. }
  257. /**
  258. * @return array [X, algorithm, skewness]
  259. */
  260. public function dataProviderForSkewness(): array
  261. {
  262. return [
  263. // Population skewness
  264. [ [61,61,61,61,61,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,73,73,73,73,73,73,73,73], RandomVariable::POPULATION_SKEWNESS, -0.1081544 ],
  265. [ [2, 3, -1, 3, 4, 5, 0, 2], RandomVariable::POPULATION_SKEWNESS, -0.3677454 ],
  266. [ [1, 2, 3, 4, 5, 6, 8, 8], RandomVariable::POPULATION_SKEWNESS, 0.079248 ],
  267. [ [1, 1, 3, 4, 5, 6, 7, 8], RandomVariable::POPULATION_SKEWNESS, -0.079248 ],
  268. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7], RandomVariable::POPULATION_SKEWNESS, 0.3031933 ],
  269. [ [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8], RandomVariable::POPULATION_SKEWNESS, 0.7745239 ],
  270. [ [1,2,3,4,5,6,7,8], RandomVariable::POPULATION_SKEWNESS, 0 ],
  271. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], RandomVariable::POPULATION_SKEWNESS, 1.605855 ],
  272. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7 ], RandomVariable::POPULATION_SKEWNESS, 0.3031933 ],
  273. [ [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8 ], RandomVariable::POPULATION_SKEWNESS, 0.7745239 ],
  274. [ [2, 3, -1, 3, 4, 5, 0, 2], RandomVariable::POPULATION_SKEWNESS, -0.3677454 ],
  275. [ [-2.83, -0.95, -0.88, 1.21, -1.67, 0.83, -0.27, 1.36, -0.34, 0.48, -2.83, -0.95, -0.88, 1.21, -1.67], RandomVariable::POPULATION_SKEWNESS, -0.1561309 ],
  276. // Sample skewness
  277. [ [61,61,61,61,61,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,73,73,73,73,73,73,73,73], RandomVariable::SAMPLE_SKEWNESS, -0.1098084 ],
  278. [ [2, 3, -1, 3, 4, 5, 0, 2], RandomVariable::SAMPLE_SKEWNESS, -0.4586591 ],
  279. [ [1, 2, 3, 4, 5, 6, 8, 8], RandomVariable::SAMPLE_SKEWNESS, 0.09883962 ],
  280. [ [1, 1, 3, 4, 5, 6, 7, 8], RandomVariable::SAMPLE_SKEWNESS, -0.09883962 ],
  281. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7], RandomVariable::SAMPLE_SKEWNESS, 0.3595431 ],
  282. [ [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8], RandomVariable::SAMPLE_SKEWNESS, 0.8633783 ],
  283. [ [1,2,3,4,5,6,7,8], RandomVariable::SAMPLE_SKEWNESS, 0 ],
  284. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], RandomVariable::SAMPLE_SKEWNESS, 1.946591 ],
  285. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7 ], RandomVariable::SAMPLE_SKEWNESS, 0.3595431 ],
  286. [ [1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 6, 7, 8 ], RandomVariable::SAMPLE_SKEWNESS, 0.8633783 ],
  287. [ [2, 3, -1, 3, 4, 5, 0, 2], RandomVariable::SAMPLE_SKEWNESS, -0.4586591 ],
  288. [ [-2.83, -0.95, -0.88, 1.21, -1.67, 0.83, -0.27, 1.36, -0.34, 0.48, -2.83, -0.95, -0.88, 1.21, -1.67], RandomVariable::SAMPLE_SKEWNESS, -0.1740425 ],
  289. // Alternative skewness
  290. [ [61,61,61,61,61,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,73,73,73,73,73,73,73,73], RandomVariable::ALTERNATIVE_SKEWNESS, -0.107612 ],
  291. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], RandomVariable::ALTERNATIVE_SKEWNESS, 1.514015 ],
  292. [ [5,20,40,80,100], RandomVariable::ALTERNATIVE_SKEWNESS, 0.202721 ],
  293. [ [3, 4, 5, 2, 3, 4, 5, 6, 4, 7], RandomVariable::ALTERNATIVE_SKEWNESS, 0.287634 ],
  294. [ [1, 1, 3, 4, 5, 6, 7, 8], RandomVariable::ALTERNATIVE_SKEWNESS, -0.07413 ],
  295. [ [1,2,3,4,5,6,7,8], RandomVariable::ALTERNATIVE_SKEWNESS, 0 ],
  296. [ [13, 18, 13, 14, 13, 16, 14, 21, 13], RandomVariable::ALTERNATIVE_SKEWNESS, 1.160097],
  297. ];
  298. }
  299. /**
  300. * @test skewness default type is sample skewness
  301. * @dataProvider dataProviderForSampleSkewness
  302. * @param array $X
  303. * @param float $expected
  304. * @throws \Exception
  305. */
  306. public function testSkewnessDefaultTypeIsSampleSkewness(array $X, float $expected)
  307. {
  308. // When
  309. $skewness = RandomVariable::skewness($X);
  310. // Then
  311. $this->assertEqualsWithDelta($expected, $skewness, 0.000001);
  312. }
  313. /**
  314. * @test skewness error when array is empty
  315. * @throws \Exception
  316. */
  317. public function testSkewnessErrorWhenEmptyArray()
  318. {
  319. // Then
  320. $this->expectException(Exception\BadDataException::class);
  321. // When
  322. RandomVariable::skewness(array());
  323. }
  324. /**
  325. * @test skewness error - unknown type
  326. * @throws \Exception
  327. */
  328. public function testSkewnessTypeError()
  329. {
  330. // Given
  331. $X = [1, 2, 3, 2, 3, 1, 1, 2];
  332. $type = 'unknownType';
  333. // Then
  334. $this->expectException(Exception\IncorrectTypeException::class);
  335. // When
  336. RandomVariable::skewness($X, $type);
  337. }
  338. /**
  339. * @test ses
  340. * @dataProvider dataProviderForSes
  341. * @param int $n
  342. * @param float $expected
  343. * @throws \Exception
  344. */
  345. public function testSes(int $n, float $expected)
  346. {
  347. // When
  348. $ses = RandomVariable::ses($n);
  349. // Then
  350. $this->assertEqualsWithDelta($expected, $ses, 0.001);
  351. }
  352. /**
  353. * @return array [n, ses]
  354. */
  355. public function dataProviderForSes(): array
  356. {
  357. return [
  358. [5, 0.913],
  359. [10, 0.687],
  360. [20, 0.512],
  361. [100, 0.241],
  362. [1000, 0.077],
  363. [10000, 0.024],
  364. ];
  365. }
  366. /**
  367. * @test ses throws a BadDataException if n is < 3
  368. * @dataProvider dataProviderForSesException
  369. * @param int $n
  370. * @throws \Exception
  371. */
  372. public function testSesException(int $n)
  373. {
  374. // Then
  375. $this->expectException(Exception\BadDataException::class);
  376. // When
  377. RandomVariable::ses($n);
  378. }
  379. /**
  380. * @return array [n]
  381. */
  382. public function dataProviderForSesException(): array
  383. {
  384. return [
  385. [-1],
  386. [0],
  387. [1],
  388. [2],
  389. ];
  390. }
  391. /**
  392. * @test sampleKurtosis
  393. * @dataProvider dataProviderForSampleKurtosis
  394. * @param array $X
  395. * @param float $expected
  396. * @throws \Exception
  397. */
  398. public function testSampleKurtosis(array $X, float $expected)
  399. {
  400. // When
  401. $kurtosis = RandomVariable::sampleKurtosis($X);
  402. // Then
  403. $this->assertEqualsWithDelta($expected, $kurtosis, 0.000001);
  404. }
  405. /**
  406. * Generated with R (e1071) kurtosis(data, type=1)
  407. * @return array [X, kurtosis]
  408. */
  409. public function dataProviderForSampleKurtosis(): array
  410. {
  411. return [
  412. [ [ 1987, 1987, 1991, 1992, 1992, 1992, 1992, 1993, 1994, 1994, 1995 ], -0.2320107 ],
  413. [ [ 0, 7, 7, 6, 6, 6, 5, 5, 4, 1 ], -0.273157 ],
  414. [ [ 2, 2, 4, 6, 8, 10, 10 ], -1.574074 ],
  415. [ [ 1242, 1353, 1142 ], -1.5 ],
  416. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], 1.389416 ],
  417. [ [5,20,40,80,100], -1.525992 ],
  418. [ [4, 5, 5, 5, 5, 6], 0 ],
  419. ];
  420. }
  421. /**
  422. * @test sampleKurtosis error when array is empty
  423. * @throws \Exception
  424. */
  425. public function testSampleKurtosisErrorWhenEmptyArray()
  426. {
  427. // Then
  428. $this->expectException(Exception\BadDataException::class);
  429. // When
  430. RandomVariable::sampleKurtosis(array());
  431. }
  432. /**
  433. * @test sampleKurtosis Nan
  434. * @dataProvider dataProviderForSkewnessNan
  435. * @param array $X
  436. * @throws \Exception
  437. */
  438. public function testSampleKurtosisNan(array $X)
  439. {
  440. // When
  441. $kurtosis = RandomVariable::sampleKurtosis($X);
  442. // Then
  443. $this->assertNan($kurtosis);
  444. }
  445. /**
  446. * @test populationKurtosis
  447. * @dataProvider dataProviderForPopulationKurtosis
  448. * @param array $X
  449. * @param float $expected
  450. * @throws \Exception
  451. */
  452. public function testPopulationKurtosis(array $X, float $expected)
  453. {
  454. // When
  455. $kurtosis = RandomVariable::populationKurtosis($X);
  456. // Then
  457. $this->assertEqualsWithDelta($expected, $kurtosis, 0.000001);
  458. }
  459. /**
  460. * Generated with R (e1071) kurtosis(data, type=2)
  461. * @return array [X, kurtosis]
  462. */
  463. public function dataProviderForPopulationKurtosis(): array
  464. {
  465. return [
  466. [ [ 1987, 1987, 1991, 1992, 1992, 1992, 1992, 1993, 1994, 1994, 1995 ],0.4466489 ],
  467. [ [ 0, 7, 7, 6, 6, 6, 5, 5, 4, 1 ], 0.4813832 ],
  468. [ [ 2, 2, 4, 6, 8, 10, 10 ], -1.977778 ],
  469. [ [ 1242, 1353, 1142, 1222 ], 1.397048 ],
  470. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], 3.789364 ],
  471. [ [5,20,40,80,100], -2.103968 ],
  472. [ [4, 5, 5, 5, 5, 6], 2.5 ],
  473. ];
  474. }
  475. /**
  476. * @test populationKurtosis Nan
  477. * @dataProvider dataProviderForPopulationKurtosisNan
  478. * @param array $X
  479. * @throws \Exception
  480. */
  481. public function testPopulationKurtosisNan(array $X)
  482. {
  483. // When
  484. $kurtosis = RandomVariable::populationKurtosis($X);
  485. // Then
  486. $this->assertNan($kurtosis);
  487. }
  488. /**
  489. * Generated with R (e1071) kurtosis(data, type=2)
  490. * @return array [X, skewness]
  491. */
  492. public function dataProviderForPopulationKurtosisNan(): array
  493. {
  494. return [
  495. [[-1, -1, -1, -1]],
  496. [[1, 1, 1, 1]],
  497. [[0, 0, 0, 0]],
  498. [[10, 10, 10, 10]],
  499. ];
  500. }
  501. /**
  502. * @test populationKurtosis error when fewer than four numbers
  503. * @dataProvider dataProviderForPopulationKurtosisErrorFewerThanFourNumbers
  504. * @param array $X
  505. * @throws \Exception
  506. */
  507. public function testPopulationKurtosisErrorFewerThanFourNumbers(array $X)
  508. {
  509. // Then
  510. $this->expectException(Exception\BadDataException::class);
  511. // When
  512. $kurtosis = RandomVariable::populationKurtosis($X);
  513. }
  514. /**
  515. * Generated with R (e1071) kurtosis(data, type=2)
  516. * @return array [X, skewness]
  517. */
  518. public function dataProviderForPopulationKurtosisErrorFewerThanFourNumbers(): array
  519. {
  520. return [
  521. [[1]],
  522. [[2, 2]],
  523. [[3, 3, 3]],
  524. [[0, 0, 0]],
  525. [[10, 10, 10]],
  526. ];
  527. }
  528. /**
  529. * @test kurtosis
  530. * @dataProvider dataProviderForKurtosis
  531. * @param array $X
  532. * @param string $type
  533. * @param float $expected
  534. * @throws \Exception
  535. */
  536. public function testKurtosis(array $X, string $type, float $expected)
  537. {
  538. // When
  539. $kurtosis = RandomVariable::kurtosis($X, $type);
  540. // Then
  541. $this->assertEqualsWithDelta($expected, $kurtosis, 0.000001);
  542. }
  543. /**
  544. * @return array [X, algorithm, kurtosis]
  545. */
  546. public function dataProviderForKurtosis(): array
  547. {
  548. return [
  549. // Population kurtosis
  550. [ [ 1987, 1987, 1991, 1992, 1992, 1992, 1992, 1993, 1994, 1994, 1995 ], RandomVariable::POPULATION_KURTOSIS, 0.4466489 ],
  551. [ [ 0, 7, 7, 6, 6, 6, 5, 5, 4, 1 ], RandomVariable::POPULATION_KURTOSIS, 0.4813832 ],
  552. [ [ 2, 2, 4, 6, 8, 10, 10 ], RandomVariable::POPULATION_KURTOSIS, -1.977778 ],
  553. [ [ 1242, 1353, 1142, 1222 ], RandomVariable::POPULATION_KURTOSIS, 1.397048 ],
  554. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], RandomVariable::POPULATION_KURTOSIS, 3.789364 ],
  555. [ [5,20,40,80,100], RandomVariable::POPULATION_KURTOSIS, -2.103968 ],
  556. [ [4, 5, 5, 5, 5, 6], RandomVariable::POPULATION_KURTOSIS, 2.5 ],
  557. // Sample kurtosis
  558. [ [ 1987, 1987, 1991, 1992, 1992, 1992, 1992, 1993, 1994, 1994, 1995 ], RandomVariable::SAMPLE_KURTOSIS, -0.2320107 ],
  559. [ [ 0, 7, 7, 6, 6, 6, 5, 5, 4, 1 ], RandomVariable::SAMPLE_KURTOSIS, -0.273157 ],
  560. [ [ 2, 2, 4, 6, 8, 10, 10 ], RandomVariable::SAMPLE_KURTOSIS, -1.574074 ],
  561. [ [ 1242, 1353, 1142 ], RandomVariable::SAMPLE_KURTOSIS, -1.5 ],
  562. [ [1, 2, 3, 4, 5, 9, 23, 32, 69], RandomVariable::SAMPLE_KURTOSIS, 1.389416 ],
  563. [ [5,20,40,80,100], RandomVariable::SAMPLE_KURTOSIS, -1.525992 ],
  564. [ [4, 5, 5, 5, 5, 6], RandomVariable::SAMPLE_KURTOSIS, 0 ],
  565. ];
  566. }
  567. /**
  568. * @test kurtosis default type is poluation skewness
  569. * @dataProvider dataProviderForPopulationKurtosis
  570. * @param array $X
  571. * @param float $expected
  572. * @throws \Exception
  573. */
  574. public function testSkewnessDefaultTypeIsPopulationKurtosis(array $X, float $expected)
  575. {
  576. // When
  577. $kurtosis = RandomVariable::kurtosis($X);
  578. // Then
  579. $this->assertEqualsWithDelta($expected, $kurtosis, 0.000001);
  580. }
  581. /**
  582. * @test kurtosis error when array is empty
  583. * @throws \Exception
  584. */
  585. public function testKurtosisErrorWhenEmptyArray()
  586. {
  587. // Then
  588. $this->expectException(Exception\BadDataException::class);
  589. // When
  590. RandomVariable::kurtosis(array());
  591. }
  592. /**
  593. * @test kurtosis error - unknown type
  594. * @throws \Exception
  595. */
  596. public function testKurtosisTypeError()
  597. {
  598. // Given
  599. $X = [1, 2, 3, 2, 3, 1, 1, 2];
  600. $type = 'unknownType';
  601. // Then
  602. $this->expectException(Exception\IncorrectTypeException::class);
  603. // When
  604. RandomVariable::kurtosis($X, $type);
  605. }
  606. /**
  607. * @test isPlatykurtic
  608. * @dataProvider dataProviderForPlatykurtic
  609. * @param array $data
  610. * @throws \Exception
  611. */
  612. public function testIsPlatykurtic(array $data)
  613. {
  614. $this->assertTrue(RandomVariable::isPlatykurtic($data, RandomVariable::SAMPLE_KURTOSIS));
  615. }
  616. /**
  617. * @test isLeptokurtic
  618. * @dataProvider dataProviderForLeptokurtic
  619. * @param array $data
  620. * @throws \Exception
  621. */
  622. public function testIsLeptokurtic(array $data)
  623. {
  624. $this->assertTrue(RandomVariable::isLeptokurtic($data, RandomVariable::SAMPLE_KURTOSIS));
  625. }
  626. /**
  627. * @test isMesokurtic
  628. * @dataProvider dataProviderForMesokurtic
  629. * @param array $data
  630. * @throws \Exception
  631. */
  632. public function testIsMesokurtic(array $data)
  633. {
  634. $this->assertTrue(RandomVariable::isMesokurtic($data, RandomVariable::SAMPLE_KURTOSIS));
  635. }
  636. /**
  637. * @test isPlatykurtic returns false for a leptokurtic data set
  638. * @dataProvider dataProviderForLeptokurtic
  639. * @param array $data
  640. * @throws \Exception
  641. */
  642. public function testIsNotPlatykurtic(array $data)
  643. {
  644. $this->assertFalse(RandomVariable::isPlatykurtic($data));
  645. }
  646. /**
  647. * @test isLeptokurtic returns false for a platykurtic data set
  648. * @dataProvider dataProviderForPlatykurtic
  649. * @param array $data
  650. * @throws \Exception
  651. */
  652. public function testIsNotLeptokurtic(array $data)
  653. {
  654. $this->assertFalse(RandomVariable::isLeptokurtic($data));
  655. }
  656. /**
  657. * @return array [data]
  658. */
  659. public function dataProviderForPlatykurtic(): array
  660. {
  661. return [
  662. [[2, 2, 4, 6, 8, 10, 10]],
  663. ];
  664. }
  665. /**
  666. * @return array [data]
  667. */
  668. public function dataProviderForLeptokurtic(): array
  669. {
  670. return [
  671. [[1, 2, 3, 4, 5, 9, 23, 32, 69]],
  672. ];
  673. }
  674. /**
  675. * @return array [data]
  676. */
  677. public function dataProviderForMesokurtic(): array
  678. {
  679. return [
  680. [[4, 5, 5, 5, 5, 6]],
  681. ];
  682. }
  683. /**
  684. * @test sek
  685. * @dataProvider dataProviderForSek
  686. * @param int $n
  687. * @param float $expected
  688. * @throws \Exception
  689. */
  690. public function testSek(int $n, float $expected)
  691. {
  692. // When
  693. $sek = RandomVariable::sek($n);
  694. // Then
  695. $this->assertEqualsWithDelta($expected, $sek, 0.001);
  696. }
  697. /**
  698. * @return array [n, sek]
  699. */
  700. public function dataProviderForSek(): array
  701. {
  702. return [
  703. [5, 2],
  704. [10, 1.334],
  705. [20, 0.992],
  706. [100, 0.478],
  707. [1000, 0.154],
  708. [10000, 0.048],
  709. ];
  710. }
  711. /**
  712. * @test sek throws a BadDataException if n is < 4
  713. * @dataProvider dataProviderForSekException
  714. * @param int $n
  715. * @throws \Exception
  716. */
  717. public function testSekException(int $n)
  718. {
  719. // Then
  720. $this->expectException(Exception\BadDataException::class);
  721. // When
  722. RandomVariable::sek($n);
  723. }
  724. /**
  725. * @return array [n]
  726. */
  727. public function dataProviderForSekException(): array
  728. {
  729. return [
  730. [-1],
  731. [0],
  732. [1],
  733. [2],
  734. [3],
  735. ];
  736. }
  737. /**
  738. * @test standardErrorOfTheMean
  739. * @dataProvider dataProviderForStandardErrorOfTheMean
  740. * @param array $X
  741. * @param float $expected
  742. * @throws \Exception
  743. */
  744. public function testStandardErrorOfTheMean(array $X, float $expected)
  745. {
  746. // When
  747. $sem = RandomVariable::standardErrorOfTheMean($X);
  748. // Then
  749. $this->assertEqualsWithDelta($expected, $sem, 0.0001);
  750. }
  751. /**
  752. * @test standardErrorOfTheMean
  753. * @dataProvider dataProviderForStandardErrorOfTheMean
  754. * @param array $X
  755. * @param float $expected
  756. * @throws \Exception
  757. */
  758. public function testSem(array $X, float $expected)
  759. {
  760. // When
  761. $sem = RandomVariable::sem($X);
  762. // Then
  763. $this->assertEqualsWithDelta($expected, $sem, 0.0001);
  764. }
  765. /**
  766. * @return array [X, sem]
  767. */
  768. public function dataProviderForStandardErrorOfTheMean(): array
  769. {
  770. return [
  771. [ [1,2,3,4,5,5,6,7], 0.7180703308172536 ],
  772. [ [34,6,23,12,25,64,32,75], 8.509317372319423 ],
  773. [ [1.5,1.3,2.532,0.43,0.042,5.9,0.9942,1.549], 0.645903079859 ],
  774. [ [453543,235235,656,342,2235,6436,234,9239,3535,8392,3492,5933,244], 37584.225394 ],
  775. ];
  776. }
  777. /**
  778. * @test standardErrorOfTheMean error when array is empty
  779. * @throws \Exception
  780. */
  781. public function testStandardErrorOfTheMeanNullWhenEmptyArray()
  782. {
  783. // Then
  784. $this->expectException(Exception\BadDataException::class);
  785. // When
  786. RandomVariable::standardErrorOfTheMean(array());
  787. }
  788. /**
  789. * @test confidenceInterval
  790. * @dataProvider dataProviderForConfidenceInterval
  791. * @param number $μ
  792. * @param number $n
  793. * @param float $σ
  794. * @param float $cl
  795. * @param array $expected
  796. * @throws \Exception
  797. */
  798. public function testConfidenceInterval($μ, $n, float $σ, float $cl, array $expected)
  799. {
  800. // When
  801. $ci = RandomVariable::confidenceInterval($μ, $n, $σ, $cl);
  802. // Then
  803. $this->assertEqualsWithDelta($expected, $ci, 0.1);
  804. }
  805. /**
  806. * @return array [μ, n, σ, cl, ci]
  807. */
  808. public function dataProviderForConfidenceInterval(): array
  809. {
  810. return [
  811. [90, 9, 36, 80, ['ci' => 15.38, 'lower_bound' => 74.62, 'upper_bound' => 105.38]],
  812. [90, 9, 36, 85, ['ci' => 17.27, 'lower_bound' => 72.73, 'upper_bound' => 107.27]],
  813. [90, 9, 36, 90, ['ci' => 19.74, 'lower_bound' => 70.26, 'upper_bound' => 109.74]],
  814. [90, 9, 36, 95, ['ci' => 23.52, 'lower_bound' => 66.48, 'upper_bound' => 113.52]],
  815. [90, 9, 36, 99, ['ci' => 30.91, 'lower_bound' => 59.09, 'upper_bound' => 120.91]],
  816. [90, 9, 36, 99.5, ['ci' => 33.68, 'lower_bound' => 56.32, 'upper_bound' => 123.68]],
  817. [90, 9, 36, 99.9, ['ci' => 39.49, 'lower_bound' => 50.51, 'upper_bound' => 129.49]],
  818. [90, 0, 36, 99.9, ['ci' => null, 'lower_bound' => null, 'upper_bound' => null]],
  819. ];
  820. }
  821. /**
  822. * @test sumOfSquares
  823. * @dataProvider dataProviderForSumOfSquares
  824. * @param array $numbers
  825. * @param number $expected
  826. * @throws \Exception
  827. */
  828. public function testSumOfSquares(array $numbers, $expected)
  829. {
  830. // When
  831. $sos = RandomVariable::sumOfSquares($numbers);
  832. // Then
  833. $this->assertEqualsWithDelta($expected, $sos, 0.001);
  834. }
  835. /**
  836. * @return array
  837. */
  838. public function dataProviderForSumOfSquares(): array
  839. {
  840. return [
  841. [ [3, 6, 7, 11, 12, 13, 17], 817],
  842. [ [6, 11, 12, 14, 15, 20, 21], 1563],
  843. [ [1, 2, 3, 6, 7, 11, 12], 364],
  844. [ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0], 285],
  845. [ [34, 253, 754, 2342, 75, 23, 876, 4, 1, -34, -345, 754, -377, 3, 0], 7723027],
  846. ];
  847. }
  848. /**
  849. * @test sumOfSquares error when the array is empty
  850. * @throws \Exception
  851. */
  852. public function testSumOfSquaresNullWhenEmptyArray()
  853. {
  854. // Then
  855. $this->expectException(Exception\BadDataException::class);
  856. // When
  857. RandomVariable::sumOfSquares(array());
  858. }
  859. /**
  860. * @test sumOfSquaresDeviations
  861. * @dataProvider dataProviderForSumOfSquaresDeviations
  862. * @param array $numbers
  863. * @param float $expected
  864. * @throws \Exception
  865. */
  866. public function testSumOfSquaresDeviations(array $numbers, float $expected)
  867. {
  868. // When
  869. $sosDeviations = RandomVariable::sumOfSquaresDeviations($numbers);
  870. // Then
  871. $this->assertEqualsWithDelta($expected, $sosDeviations, 0.001);
  872. }
  873. /**
  874. * @return array [numbers, sos]
  875. */
  876. public function dataProviderForSumOfSquaresDeviations(): array
  877. {
  878. return [
  879. [ [3, 6, 7, 11, 12, 13, 17], 136.8571],
  880. [ [6, 11, 12, 14, 15, 20, 21], 162.8571],
  881. [ [1, 2, 3, 6, 7, 11, 12], 112],
  882. [ [1, 2, 3, 4, 5, 6, 7, 8, 9, 0], 82.5],
  883. [ [34, 253, 754, 2342, 75, 23, 876, 4, 1, -34, -345, 754, -377, 3, 0], 6453975.7333],
  884. ];
  885. }
  886. /**
  887. * @test sumOfSquaresDeviations is null when the array is empty
  888. * @throws \Exception
  889. */
  890. public function testSumOfSquaresDeviationsNullWhenEmptyArray()
  891. {
  892. // Then
  893. $this->expectException(Exception\BadDataException::class);
  894. // When
  895. RandomVariable::sumOfSquaresDeviations(array());
  896. }
  897. }