All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nield.kotlinstatistics.DoubleStatistics.kt Maven / Gradle / Ivy

The newest version!
package org.nield.kotlinstatistics

import org.apache.commons.math3.stat.StatUtils
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics
import org.nield.kotlinstatistics.range.Range
import org.nield.kotlinstatistics.range.until
import java.math.BigDecimal
import java.util.concurrent.atomic.AtomicBoolean

val DoubleArray.descriptiveStatistics: Descriptives get() = DescriptiveStatistics().apply { forEach { addValue(it) } }.let(::ApacheDescriptives)


fun DoubleArray.geometricMean() = StatUtils.geometricMean(this)
fun DoubleArray.median() = percentile(50.0)
fun DoubleArray.percentile(percentile: Double) = StatUtils.percentile(this, percentile)
fun DoubleArray.variance() = StatUtils.variance(this)
fun DoubleArray.sumOfSquares() = StatUtils.sumSq(this)
fun DoubleArray.standardDeviation() = descriptiveStatistics.standardDeviation
fun DoubleArray.normalize() = StatUtils.normalize(this)
val DoubleArray.kurtosis get() = descriptiveStatistics.kurtosis
val DoubleArray.skewness get() = descriptiveStatistics.skewness



// AGGREGATION OPERATORS

inline fun  Sequence.sumBy(crossinline keySelector: (T) -> K, crossinline doubleSelector: (T) -> Double) =
        groupApply(keySelector, doubleSelector) { it.sum() }

fun  Sequence>.sumBy() =
        groupApply({it.first}, {it.second}) { it.sum() }


inline fun  Iterable.sumBy(crossinline keySelector: (T) -> K, crossinline doubleSelector: (T) -> Double) =
        asSequence().sumBy(keySelector, doubleSelector)

fun  Iterable>.sumBy() = asSequence().sumBy()



inline fun  Sequence.averageBy(crossinline keySelector: (T) -> K, crossinline doubleSelector: (T) -> Double) =
        groupApply(keySelector, doubleSelector) { it.average() }

inline fun  Iterable.averageBy(crossinline keySelector: (T) -> K, crossinline doubleSelector: (T) -> Double) =
        asSequence().groupApply(keySelector, doubleSelector) { it.average() }

fun  Sequence>.averageBy() =
        groupApply({it.first}, {it.second}) { it.average() }

fun  Iterable>.averageBy() = asSequence().averageBy()




fun Sequence.doubleRange() = toList().doubleRange()
fun Iterable.doubleRange() = toList().let { (it.min()?:throw Exception("At least one element must be present"))..(it.max()?:throw Exception("At least one element must be present")) }

inline fun  Sequence.doubleRangeBy(crossinline keySelector: (T) -> K, crossinline doubleSelector: (T) -> Double) =
        groupApply(keySelector, doubleSelector) { it.range() }

inline fun  Iterable.doubleRangeBy(crossinline keySelector: (T) -> K, crossinline doubleSelector: (T) -> Double) =
        asSequence().rangeBy(keySelector, doubleSelector)




// Bin Operators

inline fun  Iterable.binByDouble(binSize: Double,
                                   crossinline valueSelector: (T) -> Double,
                                   rangeStart: Double? = null
): BinModel, Double> = toList().binByDouble(binSize, valueSelector, { it }, rangeStart)

inline fun  Iterable.binByDouble(binSize: Double,
                                          crossinline valueSelector: (T) -> Double,
                                          crossinline groupOp: (List) -> G,
                                          rangeStart: Double? = null
) = toList().binByDouble(binSize, valueSelector, groupOp, rangeStart)


inline fun  Sequence.binByDouble(binSize: Double,
                                       crossinline valueSelector: (T) -> Double,
                                       rangeStart: Double? = null
): BinModel, Double> = toList().binByDouble(binSize, valueSelector, { it }, rangeStart)

inline fun  Sequence.binByDouble(binSize: Double,
                                          crossinline valueSelector: (T) -> Double,
                                          crossinline groupOp: (List) -> G,
                                          rangeStart: Double? = null
) = toList().binByDouble(binSize, valueSelector, groupOp, rangeStart)


inline fun  List.binByDouble(binSize: Double,
                                   crossinline valueSelector: (T) -> Double,
                                   rangeStart: Double? = null
): BinModel, Double> = binByDouble(binSize, valueSelector, { it }, rangeStart)

inline fun  List.binByDouble(binSize: Double,
                                      crossinline valueSelector: (T) -> Double,
                                      crossinline groupOp: (List) -> G,
                                      rangeStart: Double? = null
): BinModel {

    val groupedByC = asSequence().groupBy { BigDecimal.valueOf(valueSelector(it)) }
    val minC = rangeStart?.let(BigDecimal::valueOf)?:groupedByC.keys.min()!!
    val maxC = groupedByC.keys.max()!!

    val bins = mutableListOf>().apply {
        var currentRangeStart = minC
        var currentRangeEnd = minC
        val binSizeBigDecimal = BigDecimal.valueOf(binSize)

        while  (currentRangeEnd < maxC) {
            currentRangeEnd = currentRangeStart + binSizeBigDecimal
            add(currentRangeStart.toDouble() until currentRangeEnd.toDouble())
            currentRangeStart = currentRangeEnd
        }
    }

    return bins.asSequence()
            .map { it to mutableListOf() }
            .map { binWithList ->
                groupedByC.entries.asSequence()
                        .filter { it.key.toDouble() in binWithList.first }
                        .forEach { binWithList.second.addAll(it.value) }
                binWithList
            }.map { Bin(it.first, groupOp(it.second)) }
            .toList()
            .let(::BinModel)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy