package com.flightfeather.uav.biz.dataprocess
|
|
import com.flightfeather.uav.lightshare.bean.DataVo
|
import com.flightfeather.uav.socket.eunm.FactorType
|
import java.math.BigDecimal
|
import kotlin.math.max
|
import kotlin.math.min
|
import kotlin.math.round
|
import kotlin.math.sqrt
|
|
/**
|
* 预处理数据
|
* 统计数据的"记录数", "均值", "标准差", "最小值", "最大值", "10%分位值", "25%分位值", "50%分位值", "75%分位值", "90%分位值"
|
* @Date 2022.2.5
|
*/
|
class PreData(
|
//统计时间
|
private val time: String?,
|
//需要统计的监测因子
|
private val needFactor: List<FactorType> = listOf(
|
FactorType.NO2,
|
FactorType.CO,
|
FactorType.H2S,
|
FactorType.SO2,
|
FactorType.O3,
|
FactorType.PM25,
|
FactorType.PM10,
|
FactorType.VOC
|
),
|
//是否需要计算分位值
|
private val needQuartile: Boolean = true,
|
) {
|
|
inner class TempData {
|
//数据平方和(用于计算标准差)
|
var sumOfSquares: BigDecimal = BigDecimal.ZERO
|
//数据和
|
var total: BigDecimal = BigDecimal.ZERO
|
|
//计数
|
var count: Int = 0
|
var minV: Double = Double.MAX_VALUE
|
var maxV: Double = Double.MIN_VALUE
|
|
//数据值记录,按照升序排列,用于获取分位值
|
// "10%分位值",
|
// "25%分位值",
|
// "50%分位值",
|
// "75%分位值",
|
// "90%分位值"
|
val dataList = mutableListOf<Double>()
|
}
|
|
inner class ResultData {
|
var count: Int = 0
|
var avg: Double? = null
|
// 标准差
|
var std: Double? = null
|
var min: Double? = null
|
var max: Double? = null
|
var q10: Double? = null
|
var q25: Double? = null
|
var q50: Double? = null
|
var q75: Double? = null
|
var q90: Double? = null
|
}
|
|
//按照每种监测因子记录当前时间下的统计中间数据
|
private val dataMap = mutableMapOf<String?, TempData>()
|
|
fun add(data: DataVo) {
|
data.values?.forEach {
|
if (!dataMap.containsKey(it.factorName)) {
|
dataMap[it.factorName] = TempData()
|
}
|
dataMap[it.factorName]?.apply {
|
sumOfSquares = sumOfSquares.plus(BigDecimal.valueOf(
|
(it.factorData ?: .0) * (it.factorData ?: .0)
|
))
|
total = total.plus(BigDecimal.valueOf(it.factorData ?: .0))
|
count++
|
minV = min(minV, it.factorData?: .0)
|
maxV = max(maxV, it.factorData?: .0)
|
|
if (needQuartile) {
|
dataList.add(it.factorData ?: .0)
|
}
|
}
|
}
|
}
|
|
/**
|
* 输出当前统计时间下的一行统计数据
|
*/
|
fun getOutPutContent(): Array<Any> {
|
//每种监测因子都有对应的一系列统计项
|
val content = mutableListOf<Any>()
|
//第一列是统计时间
|
content.add(time ?: "错误时间")
|
needFactor.forEach {
|
dataMap[it.name]?.let {t ->
|
content.apply {
|
//"记录数",
|
val c = BigDecimal("${t.count}")
|
add(t.count)
|
// "均值",
|
val avg = t.total.div(c)
|
add(avg.toString())
|
// "标准差",
|
add(
|
sqrt(
|
t.sumOfSquares.minus(
|
avg.times(BigDecimal(2)).times(t.total)
|
).plus(
|
avg.times(avg).times(c)
|
).div(c).toDouble()
|
).toString()
|
)
|
// "最小值",
|
add(t.minV)
|
// "最大值",
|
add(t.maxV)
|
//分位值
|
if (needQuartile) {
|
t.dataList.sortBy { d -> d }
|
val size = t.dataList.size
|
// "10%分位值",
|
add(t.dataList[round(size * .1).toInt()])
|
// "25%分位值",
|
add(t.dataList[round(size * .25).toInt()])
|
// "50%分位值",
|
add(t.dataList[round(size * .5).toInt()])
|
// "75%分位值",
|
add(t.dataList[round(size * .75).toInt()])
|
// "90%分位值"
|
add(t.dataList[round(size * .9).toInt()])
|
} else {
|
add("")
|
add("")
|
add("")
|
add("")
|
add("")
|
}
|
}
|
}
|
}
|
|
clear()
|
return content.toTypedArray()
|
}
|
|
/**
|
* 计算数据的各项统计值
|
*/
|
fun calculate(): Map<FactorType, ResultData> {
|
//每种监测因子都有对应的一系列统计项
|
val resMap = mutableMapOf<FactorType, ResultData>()
|
needFactor.forEach {
|
dataMap[it.name]?.let {t ->
|
if (!resMap.containsKey(it)) {
|
resMap[it] = ResultData()
|
}
|
resMap[it]?.apply {
|
//"记录数",
|
val c = BigDecimal("${t.count}")
|
count = t.count
|
// "均值",
|
avg = if (c == BigDecimal.ZERO) .0 else t.total.div(c).toDouble()
|
// "标准差",
|
std = sqrt(
|
t.sumOfSquares.minus(
|
BigDecimal(avg!!).times(BigDecimal(2)).times(t.total)
|
).plus(
|
BigDecimal(avg!!).times(BigDecimal(avg!!)).times(c)
|
).div(c).toDouble()
|
)
|
// "最小值",
|
min = t.minV
|
// "最大值",
|
max = t.maxV
|
//分位值
|
if (needQuartile) {
|
t.dataList.sortBy { d -> d }
|
val size = t.dataList.size
|
// "10%分位值",
|
q10 = t.dataList[round(size * .1).toInt()]
|
// "25%分位值",
|
q25 = t.dataList[round(size * .25).toInt()]
|
// "50%分位值",
|
q50 = t.dataList[round(size * .5).toInt()]
|
// "75%分位值",
|
q75 = t.dataList[round(size * .75).toInt()]
|
// "90%分位值"
|
q90 = t.dataList[round(size * .9).toInt()]
|
}
|
}
|
}
|
}
|
|
clear()
|
return resMap
|
}
|
|
/**
|
* 释放内存
|
*/
|
private fun clear() {
|
dataMap.clear()
|
}
|
}
|