feiyu02
2025-02-12 f0abc5b4a6efc5aa3493a50817d3bc1aa2347322
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
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()
    }
}