predict_edb_info_rule.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. package models
  2. import (
  3. "github.com/shopspring/decimal"
  4. "hongze/hongze_edb_lib/utils"
  5. "time"
  6. )
  7. // GetChartPredictEdbInfoDataListByRule1 根据规则1获取预测数据
  8. func GetChartPredictEdbInfoDataListByRule1(edbInfoId int, dataValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*EdbInfoSearchData, existMap map[string]float64) (newPredictEdbInfoData []*EdbInfoSearchData) {
  9. newPredictEdbInfoData = predictEdbInfoData
  10. //获取后面的预测数据
  11. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  12. predictEdbInfoData = make([]*EdbInfoSearchData, 0)
  13. for k, v := range dayList {
  14. newPredictEdbInfoData = append(newPredictEdbInfoData, &EdbInfoSearchData{
  15. EdbDataId: edbInfoId + 10000000000 + k,
  16. DataTime: v.Format(utils.FormatDate),
  17. Value: dataValue,
  18. })
  19. existMap[v.Format(utils.FormatDate)] = dataValue
  20. }
  21. return
  22. }
  23. // GetChartPredictEdbInfoDataListByRuleTb 根据同比值规则获取预测数据
  24. // 2.1 同比: 在未来某一个时间段内,给定一个固定的同比增速a,用去年同期值X乘以同比增速(1+a),得到预测值Y=X(1+a)
  25. // 例: 今年1-3月值,100,100,120。给定同比增速a=0.1,则明年1-3月预测值为: 100*1.1=110,100*1.1=110,120*1.1=132。
  26. func GetChartPredictEdbInfoDataListByRuleTb(edbInfoId int, tbValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*EdbInfoSearchData, existMap map[string]float64) (newPredictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64) {
  27. newPredictEdbInfoData = predictEdbInfoData
  28. index := len(predictEdbInfoData)
  29. //获取后面的预测数据
  30. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  31. predictEdbInfoData = make([]*EdbInfoSearchData, 0)
  32. for k, currentDate := range dayList {
  33. tmpData := &EdbInfoSearchData{
  34. EdbDataId: edbInfoId + 10000000000 + index + k,
  35. DataTime: currentDate.Format(utils.FormatDate),
  36. //Value: dataValue,
  37. }
  38. var val float64
  39. var calculateStatus bool //计算结果
  40. //currentItem := existMap[av]
  41. //上一年的日期
  42. preDate := currentDate.AddDate(-1, 0, 0)
  43. preDateStr := preDate.Format(utils.FormatDate)
  44. if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到
  45. val = PredictTbzDiv(preValue, tbValue)
  46. calculateStatus = true
  47. } else {
  48. switch frequency {
  49. case "月度":
  50. //向上和向下,各找一个月
  51. nextDateDay := preDate
  52. preDateDay := preDate
  53. for i := 0; i <= 35; i++ {
  54. nextDateDayStr := nextDateDay.Format(utils.FormatDate)
  55. if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
  56. val = PredictTbzDiv(preValue, tbValue)
  57. calculateStatus = true
  58. break
  59. } else {
  60. preDateDayStr := preDateDay.Format(utils.FormatDate)
  61. if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
  62. val = PredictTbzDiv(preValue, tbValue)
  63. calculateStatus = true
  64. break
  65. }
  66. }
  67. nextDateDay = nextDateDay.AddDate(0, 0, 1)
  68. preDateDay = preDateDay.AddDate(0, 0, -1)
  69. }
  70. case "季度", "年度":
  71. if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到
  72. val = PredictTbzDiv(preValue, tbValue)
  73. calculateStatus = true
  74. break
  75. }
  76. default:
  77. nextDateDay := preDate
  78. preDateDay := preDate
  79. for i := 0; i < 35; i++ {
  80. nextDateDayStr := nextDateDay.Format(utils.FormatDate)
  81. if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
  82. val = PredictTbzDiv(preValue, tbValue)
  83. calculateStatus = true
  84. break
  85. } else {
  86. preDateDayStr := preDateDay.Format(utils.FormatDate)
  87. if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
  88. val = PredictTbzDiv(preValue, tbValue)
  89. calculateStatus = true
  90. break
  91. } else {
  92. //fmt.Println("pre not find:", preDateStr, "i:", i)
  93. }
  94. }
  95. nextDateDay = nextDateDay.AddDate(0, 0, 1)
  96. preDateDay = preDateDay.AddDate(0, 0, -1)
  97. }
  98. }
  99. }
  100. if calculateStatus {
  101. tmpData.Value = val
  102. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  103. // 最大最小值
  104. if val < minValue {
  105. minValue = val
  106. }
  107. if val < maxValue {
  108. maxValue = val
  109. }
  110. }
  111. }
  112. return
  113. }
  114. // PredictTbzDiv 同比值计算
  115. // @params a float64 去年同期值
  116. // @params b float64 固定同比增速
  117. func PredictTbzDiv(a, b float64) (result float64) {
  118. if b != 0 {
  119. // 去年同期值
  120. af := decimal.NewFromFloat(a)
  121. // 同比增速
  122. bf := decimal.NewFromFloat(b)
  123. // 默认1
  124. cf := decimal.NewFromFloat(1)
  125. // 总增速
  126. val := bf.Add(cf)
  127. // 计算
  128. result, _ = val.Mul(af).RoundCeil(4).Float64()
  129. } else {
  130. result = 0
  131. }
  132. return
  133. }
  134. // GetChartPredictEdbInfoDataListByRuleTc 根据同差值规则获取预测数据
  135. // 2.2 同差: 在未来某一个时间段内,给定一个固定的同比增加值a,用去年同期值X加上同比增加值A,得到预测值Y=X+a
  136. // 例: 今年1-3月值,100,100,120。给定同比增加值a=10,则明年1-3月预测值为: 100+10=110,100+10=110,120+10=130
  137. func GetChartPredictEdbInfoDataListByRuleTc(edbInfoId int, tcValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*EdbInfoSearchData, existMap map[string]float64) (newPredictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64) {
  138. newPredictEdbInfoData = predictEdbInfoData
  139. index := len(predictEdbInfoData)
  140. //获取后面的预测数据
  141. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  142. predictEdbInfoData = make([]*EdbInfoSearchData, 0)
  143. for k, currentDate := range dayList {
  144. tmpData := &EdbInfoSearchData{
  145. EdbDataId: edbInfoId + 10000000000 + index + k,
  146. DataTime: currentDate.Format(utils.FormatDate),
  147. //Value: dataValue,
  148. }
  149. var val float64
  150. var calculateStatus bool //计算结果
  151. //currentItem := existMap[av]
  152. //上一年的日期
  153. preDate := currentDate.AddDate(-1, 0, 0)
  154. preDateStr := preDate.Format(utils.FormatDate)
  155. if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到
  156. val = PredictTczDiv(preValue, tcValue)
  157. calculateStatus = true
  158. } else {
  159. switch frequency {
  160. case "月度":
  161. //向上和向下,各找一个月
  162. nextDateDay := preDate
  163. preDateDay := preDate
  164. for i := 0; i <= 35; i++ {
  165. nextDateDayStr := nextDateDay.Format(utils.FormatDate)
  166. if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
  167. val = PredictTczDiv(preValue, tcValue)
  168. calculateStatus = true
  169. break
  170. } else {
  171. preDateDayStr := preDateDay.Format(utils.FormatDate)
  172. if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
  173. val = PredictTczDiv(preValue, tcValue)
  174. calculateStatus = true
  175. break
  176. }
  177. }
  178. nextDateDay = nextDateDay.AddDate(0, 0, 1)
  179. preDateDay = preDateDay.AddDate(0, 0, -1)
  180. }
  181. case "季度", "年度":
  182. if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到
  183. val = PredictTczDiv(preValue, tcValue)
  184. calculateStatus = true
  185. break
  186. }
  187. default:
  188. nextDateDay := preDate
  189. preDateDay := preDate
  190. for i := 0; i < 35; i++ {
  191. nextDateDayStr := nextDateDay.Format(utils.FormatDate)
  192. if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
  193. val = PredictTczDiv(preValue, tcValue)
  194. calculateStatus = true
  195. break
  196. } else {
  197. preDateDayStr := preDateDay.Format(utils.FormatDate)
  198. if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
  199. val = PredictTczDiv(preValue, tcValue)
  200. calculateStatus = true
  201. break
  202. } else {
  203. //fmt.Println("pre not find:", preDateStr, "i:", i)
  204. }
  205. }
  206. nextDateDay = nextDateDay.AddDate(0, 0, 1)
  207. preDateDay = preDateDay.AddDate(0, 0, -1)
  208. }
  209. }
  210. }
  211. if calculateStatus {
  212. tmpData.Value = val
  213. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  214. // 最大最小值
  215. if val < minValue {
  216. minValue = val
  217. }
  218. if val < maxValue {
  219. maxValue = val
  220. }
  221. }
  222. }
  223. return
  224. }
  225. // PredictTczDiv 环差值计算
  226. // @params a float64 上一期值
  227. // @params b float64 固定的环比增加值
  228. func PredictTczDiv(a, b float64) (result float64) {
  229. if b != 0 {
  230. // 上一期值
  231. af := decimal.NewFromFloat(a)
  232. // 固定的环比增加值
  233. bf := decimal.NewFromFloat(b)
  234. // 计算
  235. result, _ = af.Add(bf).RoundCeil(4).Float64()
  236. } else {
  237. result = 0
  238. }
  239. return
  240. }
  241. // GetChartPredictEdbInfoDataListByRuleHb 根据环比值规则获取预测数据
  242. // 环比:在未来某一个时间段内,给定一个固定的环比增速a,用上一期值X乘以环比增速(1+a),得到预测值Y=X(1+a)
  243. // 例: 最近1期值为100,给定环比增速a=0.2,则未来3期预测值为: 100*1.2=120,120*1.2=144,144*1.2=172.8
  244. func GetChartPredictEdbInfoDataListByRuleHb(edbInfoId int, hbValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*EdbInfoSearchData, existMap map[string]float64) (newPredictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64) {
  245. newPredictEdbInfoData = predictEdbInfoData
  246. index := len(predictEdbInfoData)
  247. //获取后面的预测数据
  248. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  249. for k, currentDate := range dayList {
  250. tmpK := index + k - 1 //上1期的值
  251. // 环比值计算
  252. val := PredictHbzDiv(newPredictEdbInfoData[tmpK].Value, hbValue)
  253. currentDateStr := currentDate.Format(utils.FormatDate)
  254. newPredictEdbInfoData = append(newPredictEdbInfoData, &EdbInfoSearchData{
  255. EdbDataId: edbInfoId + 10000000000 + index + k,
  256. DataTime: currentDateStr,
  257. Value: val,
  258. })
  259. existMap[currentDateStr] = val
  260. // 最大最小值
  261. if val < minValue {
  262. minValue = val
  263. }
  264. if val < maxValue {
  265. maxValue = val
  266. }
  267. }
  268. return
  269. }
  270. // PredictHbzDiv 环比值计算
  271. // @params a float64 上一期值
  272. // @params b float64 固定的环比增速
  273. func PredictHbzDiv(a, b float64) (result float64) {
  274. if b != 0 {
  275. // 上一期值
  276. af := decimal.NewFromFloat(a)
  277. // 固定的环比增速
  278. bf := decimal.NewFromFloat(b)
  279. // 默认1
  280. cf := decimal.NewFromFloat(1)
  281. // 总增速
  282. val := bf.Add(cf)
  283. // 计算
  284. result, _ = val.Mul(af).RoundCeil(4).Float64()
  285. } else {
  286. result = 0
  287. }
  288. return
  289. }
  290. // GetChartPredictEdbInfoDataListByRuleHc 根据环差值规则获取预测数据
  291. // 2.4 环差:在未来某一个时间段内,给定一个固定的环比增加值a,用上一期值X加上环比增加值a,得到预测值Y=X+a
  292. // 例: 最近1期值为100,给定环比增加值a=10,则未来3期预测值为: 100+10=110,110+10=120,120+10=130
  293. func GetChartPredictEdbInfoDataListByRuleHc(edbInfoId int, hcValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*EdbInfoSearchData, existMap map[string]float64) (newPredictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64) {
  294. newPredictEdbInfoData = predictEdbInfoData
  295. index := len(predictEdbInfoData)
  296. //获取后面的预测数据
  297. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  298. for k, currentDate := range dayList {
  299. tmpK := index + k - 1 //上1期的值
  300. // 环差别值计算
  301. val := PredictHczDiv(newPredictEdbInfoData[tmpK].Value, hcValue)
  302. currentDateStr := currentDate.Format(utils.FormatDate)
  303. newPredictEdbInfoData = append(newPredictEdbInfoData, &EdbInfoSearchData{
  304. EdbDataId: edbInfoId + 10000000000 + index + k,
  305. DataTime: currentDateStr,
  306. Value: val,
  307. })
  308. existMap[currentDateStr] = val
  309. // 最大最小值
  310. if val < minValue {
  311. minValue = val
  312. }
  313. if val < maxValue {
  314. maxValue = val
  315. }
  316. }
  317. return
  318. }
  319. // PredictHczDiv 环差值计算
  320. // @params a float64 上一期值
  321. // @params b float64 固定的环比增加值
  322. func PredictHczDiv(a, b float64) (result float64) {
  323. if b != 0 {
  324. // 上一期值
  325. af := decimal.NewFromFloat(a)
  326. // 固定的环比增加值
  327. bf := decimal.NewFromFloat(b)
  328. // 计算
  329. result, _ = af.Add(bf).RoundCeil(4).Float64()
  330. } else {
  331. result = 0
  332. }
  333. return
  334. }
  335. // GetChartPredictEdbInfoDataListByRuleNMoveMeanValue 根据N期移动均值规则获取预测数据
  336. // 2.5 N期移动均值:在未来某一个时间段内,下一期值等于过去N期值得平均值。
  337. // 例:最近3期值(N=3),为95,98,105则未来第1期值为 1/3*(95+98+105)=99.33, 未来第2期值为 1/3*(98+105+99.33)=100.78依次类推。
  338. func GetChartPredictEdbInfoDataListByRuleNMoveMeanValue(edbInfoId int, nValue int, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*EdbInfoSearchData, existMap map[string]float64) (newPredictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64) {
  339. allDataList := make([]*EdbInfoSearchData, 0)
  340. allDataList = append(allDataList, realPredictEdbInfoData...)
  341. allDataList = append(allDataList, predictEdbInfoData...)
  342. newPredictEdbInfoData = predictEdbInfoData
  343. lenAllData := len(allDataList)
  344. if lenAllData < nValue || lenAllData <= 0 {
  345. return
  346. }
  347. if nValue <= 0 {
  348. return
  349. }
  350. // 分母
  351. decimalN := decimal.NewFromInt(int64(nValue))
  352. //获取后面的预测数据
  353. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  354. for k, currentDate := range dayList {
  355. tmpIndex := lenAllData + k - 1 //上1期的值
  356. // 数据集合中的最后一个数据
  357. tmpDecimalVal := decimal.NewFromFloat(allDataList[tmpIndex].Value)
  358. for tmpK := 2; tmpK <= nValue; tmpK++ {
  359. tmpIndex2 := tmpIndex - tmpK //上N期的值
  360. tmpDecimalVal2 := decimal.NewFromFloat(allDataList[tmpIndex2].Value)
  361. tmpDecimalVal = tmpDecimalVal.Add(tmpDecimalVal2)
  362. }
  363. // N期移动均值计算
  364. val, _ := tmpDecimalVal.Div(decimalN).RoundCeil(4).Float64()
  365. currentDateStr := currentDate.Format(utils.FormatDate)
  366. tmpData := &EdbInfoSearchData{
  367. EdbDataId: edbInfoId + 10000000000 + lenAllData + k,
  368. DataTime: currentDateStr,
  369. Value: val,
  370. }
  371. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  372. allDataList = append(allDataList, tmpData)
  373. existMap[currentDateStr] = val
  374. // 最大最小值
  375. if val < minValue {
  376. minValue = val
  377. }
  378. if val < maxValue {
  379. maxValue = val
  380. }
  381. }
  382. return
  383. }
  384. // GetChartPredictEdbInfoDataListByRuleNLinearRegression 根据N期移动均值规则获取预测数据
  385. // 2.6N期段线性外推值:给出过去N期值所确定的线性回归方程(Y=aX+b)在未来一段时间内的推算值。回归方程虽然比较复杂,但各种编程语言应该都有现成的模块或函数,应该无需自己编写。
  386. // 例1:过去5期值(N=5)分别为:3,5,7,9,11(每两期值之间的时间间隔相等)。那么按照线性回归方程推算,未来三期的预测值是:13,15,17。
  387. //
  388. // 例2:过去6期值(N=6)分别为:3,3,5,7,9,11(每两期值之间的时间间隔相等)。那么按照线性回归方程推算,未来三期的预测值是:12.33,14.05,15.76。例1和例2的区别在于,多加了一期数据,导致回归方程发生改变,从而预测值不同。
  389. func GetChartPredictEdbInfoDataListByRuleNLinearRegression(edbInfoId int, nValue int, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*EdbInfoSearchData, existMap map[string]float64) (newPredictEdbInfoData []*EdbInfoSearchData, minValue, maxValue float64) {
  390. //var errMsg string
  391. //defer func() {
  392. // if errMsg != `` {
  393. // go alarm_msg.SendAlarmMsg("更新上海的token失败;ERR:"+err.Error(), 3)
  394. // }
  395. //}()
  396. allDataList := make([]*EdbInfoSearchData, 0)
  397. allDataList = append(allDataList, realPredictEdbInfoData...)
  398. allDataList = append(allDataList, predictEdbInfoData...)
  399. newPredictEdbInfoData = predictEdbInfoData
  400. lenAllData := len(allDataList)
  401. if lenAllData < nValue || lenAllData <= 0 {
  402. return
  403. }
  404. if nValue <= 0 {
  405. return
  406. }
  407. //获取后面的预测数据
  408. // 获取线性方程公式的a、b的值
  409. coordinateData := make([]Coordinate, 0)
  410. for tmpK := nValue; tmpK > 0; tmpK-- {
  411. tmpIndex2 := lenAllData - tmpK //上N期的值
  412. tmpCoordinate := Coordinate{
  413. X: float64(nValue - tmpK + 1),
  414. Y: allDataList[tmpIndex2].Value,
  415. }
  416. coordinateData = append(coordinateData, tmpCoordinate)
  417. }
  418. a, b := getLinearResult(coordinateData)
  419. //fmt.Println("a:", a, ";======b:", b)
  420. dayList := getPredictEdbDayList(startDate, endDate, frequency)
  421. for k, currentDate := range dayList {
  422. tmpK := nValue + k + 1
  423. aDecimal := decimal.NewFromFloat(a)
  424. xDecimal := decimal.NewFromInt(int64(tmpK))
  425. bDecimal := decimal.NewFromFloat(b)
  426. val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).RoundCeil(4).Float64()
  427. currentDateStr := currentDate.Format(utils.FormatDate)
  428. tmpData := &EdbInfoSearchData{
  429. EdbDataId: edbInfoId + 10000000000 + lenAllData + k,
  430. DataTime: currentDateStr,
  431. Value: val,
  432. }
  433. newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
  434. allDataList = append(allDataList, tmpData)
  435. existMap[currentDateStr] = val
  436. // 最大最小值
  437. if val < minValue {
  438. minValue = val
  439. }
  440. if val < maxValue {
  441. maxValue = val
  442. }
  443. }
  444. return
  445. }
  446. // Series is a container for a series of data
  447. type Series []Coordinate
  448. // Coordinate holds the data in a series
  449. type Coordinate struct {
  450. X, Y float64
  451. }
  452. func getLinearResult(s []Coordinate) (gradient, intercept float64) {
  453. if len(s) == 0 {
  454. return
  455. }
  456. // Placeholder for the math to be done
  457. var sum [5]float64
  458. // Loop over data keeping index in place
  459. i := 0
  460. for ; i < len(s); i++ {
  461. sum[0] += s[i].X
  462. sum[1] += s[i].Y
  463. sum[2] += s[i].X * s[i].X
  464. sum[3] += s[i].X * s[i].Y
  465. sum[4] += s[i].Y * s[i].Y
  466. }
  467. // Find gradient and intercept
  468. f := float64(i)
  469. gradient = (f*sum[3] - sum[0]*sum[1]) / (f*sum[2] - sum[0]*sum[0])
  470. intercept = (sum[1] / f) - (gradient * sum[0] / f)
  471. //fmt.Println("gradient:", gradient, ";intercept:", intercept)
  472. // Create the new regression series
  473. //for j := 0; j < len(s); j++ {
  474. // regressions = append(regressions, Coordinate{
  475. // X: s[j].X,
  476. // Y: s[j].X*gradient + intercept,
  477. // })
  478. //}
  479. return
  480. }