Skip to content

Commit 4bf11af

Browse files
committed
Experiment: added HMM model based on two normal distributions with 0 inflation
1 parent 5d647af commit 4bf11af

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package org.jetbrains.bio.statistics.distribution
2+
3+
import org.apache.commons.math3.distribution.AbstractIntegerDistribution
4+
import org.apache.commons.math3.distribution.NormalDistribution
5+
import org.apache.commons.math3.random.RandomGenerator
6+
import org.apache.commons.math3.random.Well19937c
7+
import org.jetbrains.bio.statistics.standardDeviation
8+
import java.util.*
9+
import java.util.stream.DoubleStream
10+
import kotlin.math.*
11+
12+
class NormalIntDistribution(
13+
val mean: Double,
14+
val variance: Double,
15+
rng: RandomGenerator = Well19937c(),
16+
) : AbstractIntegerDistribution(rng) {
17+
18+
init {
19+
require(variance > 0) {
20+
"Variance $variance should be > 0"
21+
}
22+
require(mean >= 0) {
23+
"Mean $mean should be >= 0"
24+
}
25+
}
26+
27+
private val backNormalDistribution = NormalDistribution(mean, sqrt(variance))
28+
29+
override fun probability(k: Int): Double {
30+
if (k < 0 || k == Integer.MAX_VALUE) {
31+
return 0.0
32+
}
33+
return backNormalDistribution.probability(k.toDouble(), k.toDouble() + 1)
34+
}
35+
36+
override fun logProbability(k: Int): Double {
37+
if (k < 0 || k == Integer.MAX_VALUE) {
38+
return Double.NEGATIVE_INFINITY
39+
}
40+
return ln(backNormalDistribution.probability(k.toDouble(), k.toDouble() + 1))
41+
}
42+
43+
override fun cumulativeProbability(k: Int): Double {
44+
if (k == Integer.MAX_VALUE) {
45+
return 1.0
46+
}
47+
return backNormalDistribution.cumulativeProbability(k.toDouble() + 1)
48+
}
49+
50+
override fun getNumericalMean(): Double {
51+
return mean
52+
}
53+
54+
override fun getNumericalVariance(): Double {
55+
return variance * variance
56+
}
57+
58+
override fun getSupportLowerBound(): Int {
59+
return Integer.MIN_VALUE
60+
}
61+
62+
override fun getSupportUpperBound(): Int {
63+
return Integer.MAX_VALUE
64+
}
65+
66+
override fun isSupportConnected(): Boolean {
67+
return true
68+
}
69+
70+
override fun sample(): Int {
71+
return backNormalDistribution.sample().toInt()
72+
}
73+
74+
override fun toString(): String {
75+
return "NormalDistribution(mean=$mean, sd=$variance)"
76+
}
77+
78+
companion object {
79+
80+
/**
81+
* Uses defaults from *Constants*.
82+
* @see [of]
83+
*/
84+
@Throws(IllegalArgumentException::class)
85+
fun of(values: DoubleArray): NormalIntDistribution {
86+
return of(DoubleStream.of(*values).mapToInt { x -> x.toInt() }.toArray())
87+
}
88+
89+
/**
90+
* Creates Negative binomial distribution from MLE of parameters.
91+
*
92+
* @param values sample to estimate parameters from.
93+
* @return Negative binomial distribution.
94+
*/
95+
fun of(values: IntArray): NormalIntDistribution {
96+
val weights = DoubleArray(values.size)
97+
Arrays.fill(weights, 1.0)
98+
99+
val mean = values.average()
100+
val sd = values.standardDeviation()
101+
102+
return NormalIntDistribution(mean, sd * sd)
103+
}
104+
}
105+
}
106+

0 commit comments

Comments
 (0)