edb_info.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. package services
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "eta/eta_forum_admin/models"
  6. "eta/eta_forum_admin/utils"
  7. "fmt"
  8. "github.com/shopspring/decimal"
  9. "math"
  10. "sort"
  11. "strings"
  12. "time"
  13. )
  14. // TraceEdbInfoByEdbInfoId 指标追溯
  15. func TraceEdbInfoByEdbInfoId(edbInfoId int) (traceEdbInfo models.TraceEdbInfoResp, err error) {
  16. edbInfo, err := models.GetEdbInfoById(edbInfoId)
  17. if err != nil {
  18. return
  19. }
  20. edbInfoRuleMap := make(map[int]string, 0)
  21. edbMappingMap := make(map[int][]*models.EdbInfoCalculateMappingInfo)
  22. //edbInfoRuleMap[edbInfoId] = getEdbRuleTitle(edbInfo)
  23. traceEdbInfo = models.TraceEdbInfoResp{
  24. //EdbInfoId: edbInfo.EdbInfoId,
  25. EdbInfoId: edbInfoId,
  26. EdbInfoType: edbInfo.EdbInfoType,
  27. EdbName: edbInfo.EdbName,
  28. EdbType: edbInfo.EdbType,
  29. //Source: edbInfo.Source,
  30. UniqueCode: edbInfo.UniqueCode,
  31. ClassifyId: edbInfo.ClassifyId,
  32. IsStop: edbInfo.NoUpdate,
  33. EdbInfo: edbInfo,
  34. }
  35. findIdMap := make(map[int]int)
  36. findIdMap[edbInfoId] = edbInfoId
  37. existMap := make(map[int]models.TraceEdbInfoResp)
  38. traceEdbInfo.Child, err = traceEdbInfoByEdbInfoId(edbInfoId, traceEdbInfo, edbInfoRuleMap, findIdMap, existMap, edbMappingMap)
  39. edbInfoIdList := make([]int, 0)
  40. for _, v := range findIdMap {
  41. edbInfoIdList = append(edbInfoIdList, v)
  42. }
  43. classifyIdList := make([]int, 0)
  44. edbInfoList, err := models.GetEdbInfoByIdList(edbInfoIdList)
  45. if err != nil {
  46. return
  47. }
  48. edbInfoMap := make(map[int]*models.EdbInfo)
  49. for _, tmpEdbInfo := range edbInfoList {
  50. edbInfoMap[tmpEdbInfo.EdbInfoId] = tmpEdbInfo
  51. classifyIdList = append(classifyIdList, tmpEdbInfo.ClassifyId)
  52. }
  53. traceEdbInfo, err = handleTraceEdbInfo(traceEdbInfo, 0, edbInfoMap, edbMappingMap)
  54. // 权限校验
  55. return
  56. }
  57. // TraceEdbInfoByEdbInfoIdList 指标追溯
  58. func TraceEdbInfoByEdbInfoIdList(edbInfoIdList []int) (traceEdbInfoList []models.TraceEdbInfoResp, err error) {
  59. traceEdbInfoList = make([]models.TraceEdbInfoResp, 0)
  60. edbInfoList, err := models.GetEdbInfoByIdList(edbInfoIdList)
  61. if err != nil {
  62. return
  63. }
  64. edbInfoRuleMap := make(map[int]string, 0)
  65. edbMappingMap := make(map[int][]*models.EdbInfoCalculateMappingInfo)
  66. findIdMap := make(map[int]int)
  67. existMap := make(map[int]models.TraceEdbInfoResp)
  68. for _, edbInfo := range edbInfoList {
  69. findIdMap[edbInfo.EdbInfoId] = edbInfo.EdbInfoId
  70. //edbInfoRuleMap[edbInfoId] = getEdbRuleTitle(edbInfo)
  71. traceEdbInfo := models.TraceEdbInfoResp{
  72. //EdbInfoId: edbInfo.EdbInfoId,
  73. EdbInfoId: edbInfo.EdbInfoId,
  74. EdbInfoType: edbInfo.EdbInfoType,
  75. EdbName: edbInfo.EdbName,
  76. EdbType: edbInfo.EdbType,
  77. //Source: edbInfo.Source,
  78. UniqueCode: edbInfo.UniqueCode,
  79. ClassifyId: edbInfo.ClassifyId,
  80. IsStop: edbInfo.NoUpdate,
  81. EdbInfo: edbInfo,
  82. }
  83. traceEdbInfo.Child, err = traceEdbInfoByEdbInfoId(edbInfo.EdbInfoId, traceEdbInfo, edbInfoRuleMap, findIdMap, existMap, edbMappingMap)
  84. traceEdbInfoList = append(traceEdbInfoList, traceEdbInfo)
  85. }
  86. //findEdbInfoIdList := make([]int, 0)
  87. //for _, v := range findIdMap {
  88. // findEdbInfoIdList = append(findEdbInfoIdList, v)
  89. //}
  90. //findEdbInfoList, err := models.GetEdbInfoByIdList(findEdbInfoIdList)
  91. //if err != nil {
  92. // return
  93. //}
  94. //edbInfoMap := make(map[int]*models.EdbInfo)
  95. //for _, tmpEdbInfo := range findEdbInfoList {
  96. // edbInfoMap[tmpEdbInfo.EdbInfoId] = tmpEdbInfo
  97. //}
  98. //for k, traceEdbInfo := range traceEdbInfoList {
  99. // traceEdbInfoList[k], err = handleTraceEdbInfo(traceEdbInfo, 0, edbInfoMap, edbMappingMap)
  100. //}
  101. return
  102. }
  103. // traceEdbInfoByEdbInfoId 指标追溯
  104. func traceEdbInfoByEdbInfoId(edbInfoId int, traceEdbInfo models.TraceEdbInfoResp, edbInfoRuleMap map[int]string, findIdMap map[int]int, existMap map[int]models.TraceEdbInfoResp, edbMappingMap map[int][]*models.EdbInfoCalculateMappingInfo) (child []models.TraceEdbInfoResp, err error) {
  105. traceEdbInfo, ok := existMap[edbInfoId]
  106. if ok {
  107. return
  108. }
  109. child = make([]models.TraceEdbInfoResp, 0)
  110. edbInfoMappingList, e := models.GetEdbInfoCalculateMappingListByEdbInfoId(edbInfoId)
  111. if e != nil {
  112. err = fmt.Errorf("GetEdbInfoCalculateMappingListByEdbInfoId err: %s", e.Error())
  113. return
  114. }
  115. // 指标信息map
  116. edbInfoMap := make(map[int]*models.EdbInfo)
  117. if len(edbInfoMappingList) > 0 {
  118. fromEdbInfoIdList := make([]int, 0)
  119. for _, v := range edbInfoMappingList {
  120. fromEdbInfoIdList = append(fromEdbInfoIdList, v.FromEdbInfoId)
  121. }
  122. edbInfoList, tmpErr := models.GetEdbInfoByIdList(fromEdbInfoIdList)
  123. if tmpErr != nil {
  124. err = fmt.Errorf("traceEdbInfoByEdbInfoId GetEdbInfoByIdList err: %s", tmpErr.Error())
  125. return
  126. }
  127. for _, v := range edbInfoList {
  128. edbInfoMap[v.EdbInfoId] = v
  129. }
  130. }
  131. edbMappingMap[edbInfoId] = edbInfoMappingList
  132. for _, v := range edbInfoMappingList {
  133. tmpEdbInfoId := v.FromEdbInfoId
  134. tmpTraceEdbInfo := models.TraceEdbInfoResp{
  135. EdbInfoId: tmpEdbInfoId,
  136. EdbInfoType: v.FromEdbInfoType,
  137. EdbType: v.FromEdbType,
  138. UniqueCode: v.FromUniqueCode,
  139. ClassifyId: v.FromClassifyId,
  140. IsStop: v.NoUpdate,
  141. EdbInfo: edbInfoMap[v.FromEdbInfoId],
  142. }
  143. // 计算指标/预测指标继续溯源
  144. if edbInfoId != v.FromEdbInfoId && (v.FromEdbType == 2 || v.FromEdbInfoType == 1) {
  145. // 查过了就不查了
  146. if _, ok2 := findIdMap[tmpEdbInfoId]; !ok2 {
  147. tmpTraceEdbInfo.Child, e = traceEdbInfoByEdbInfoId(tmpEdbInfoId, tmpTraceEdbInfo, edbInfoRuleMap, findIdMap, existMap, edbMappingMap)
  148. if e != nil {
  149. err = fmt.Errorf("traceEdbInfoByEdbInfoId err: %s", e.Error())
  150. return
  151. }
  152. }
  153. }
  154. child = append(child, tmpTraceEdbInfo)
  155. findIdMap[tmpEdbInfoId] = tmpEdbInfoId
  156. }
  157. existMap[edbInfoId] = traceEdbInfo
  158. return
  159. }
  160. func handleTraceEdbInfo(traceEdbInfoResp models.TraceEdbInfoResp, parentEdbInfoId int, edbInfoMap map[int]*models.EdbInfo, edbMappingMap map[int][]*models.EdbInfoCalculateMappingInfo) (newTraceEdbInfoResp models.TraceEdbInfoResp, err error) {
  161. edbInfo, ok := edbInfoMap[traceEdbInfoResp.EdbInfoId]
  162. if !ok {
  163. err = errors.New("指标异常")
  164. return
  165. }
  166. var parentEdbInfo *models.EdbInfo
  167. if parentEdbInfoId > 0 {
  168. parentEdbInfo, ok = edbInfoMap[parentEdbInfoId]
  169. if !ok {
  170. err = errors.New("指标异常")
  171. return
  172. }
  173. }
  174. //traceEdbInfoResp.EdbName = edbInfo.EdbName
  175. traceEdbInfoResp.EdbName, traceEdbInfoResp.RuleTitle = getEdbRuleTitle(edbInfo, parentEdbInfo, traceEdbInfoResp.Child, edbInfoMap, edbMappingMap)
  176. if traceEdbInfoResp.Child != nil && len(traceEdbInfoResp.Child) > 0 {
  177. for k, v := range traceEdbInfoResp.Child {
  178. traceEdbInfoResp.Child[k], err = handleTraceEdbInfo(v, traceEdbInfoResp.EdbInfoId, edbInfoMap, edbMappingMap)
  179. if err != nil {
  180. return
  181. }
  182. }
  183. }
  184. newTraceEdbInfoResp = traceEdbInfoResp
  185. return
  186. }
  187. // 获取频度的英文版
  188. func GetFrequencyEn(frequency string) (frequencyEn string) {
  189. switch frequency {
  190. case "日度":
  191. frequencyEn = "day"
  192. return
  193. case "周度":
  194. frequencyEn = "week"
  195. return
  196. case "旬度":
  197. frequencyEn = "ten days"
  198. return
  199. case "月度":
  200. frequencyEn = "month"
  201. return
  202. case "季度":
  203. frequencyEn = "quarter"
  204. return
  205. case "年度":
  206. frequencyEn = "year"
  207. return
  208. }
  209. return
  210. }
  211. func GetLeadUnitEn(unit string) (unitEn string) {
  212. switch unit {
  213. case "天":
  214. unitEn = "day"
  215. return
  216. case "周":
  217. unitEn = "week"
  218. return
  219. case "月":
  220. unitEn = "month"
  221. return
  222. case "季":
  223. unitEn = "quarter"
  224. return
  225. case "年":
  226. unitEn = "year"
  227. return
  228. }
  229. return
  230. }
  231. func GetRefreshEdbInfoFromBase(edbInfoId, source int) (baseEdbInfoArr, calculateInfoArr []*models.EdbInfo, err error) {
  232. calculateList, err := models.GetEdbInfoCalculateMap(edbInfoId, source)
  233. if err != nil && err.Error() != utils.ErrNoRow() {
  234. return
  235. }
  236. for _, item := range calculateList {
  237. if item.EdbInfoId == edbInfoId { // 如果查出来关联的指标就是自己的话,那么就过滤
  238. continue
  239. }
  240. if item.EdbType == 1 {
  241. baseEdbInfoArr = append(baseEdbInfoArr, item)
  242. } else {
  243. calculateInfoArr = append(calculateInfoArr, item)
  244. newBaseEdbInfoArr, newCalculateInfoArr, _ := GetRefreshEdbInfoFromBase(item.EdbInfoId, item.Source)
  245. baseEdbInfoArr = append(baseEdbInfoArr, newBaseEdbInfoArr...)
  246. calculateInfoArr = append(calculateInfoArr, newCalculateInfoArr...)
  247. }
  248. }
  249. return
  250. }
  251. // getEdbRule 获取规则名称
  252. func getEdbRuleTitle(edbInfo, parentEdbInfo *models.EdbInfo, childList []models.TraceEdbInfoResp, edbInfoMap map[int]*models.EdbInfo, edbMappingMap map[int][]*models.EdbInfoCalculateMappingInfo) (edbName, ruleTitle string) {
  253. edbName = edbInfo.EdbName
  254. ruleTitle = `来源于` + edbInfo.SourceName
  255. if parentEdbInfo != nil {
  256. edbMappingList, ok := edbMappingMap[parentEdbInfo.EdbInfoId]
  257. if !ok {
  258. edbMappingList = []*models.EdbInfoCalculateMappingInfo{}
  259. }
  260. // 指标名称
  261. switch parentEdbInfo.Source {
  262. case utils.DATA_SOURCE_CALCULATE, utils.DATA_SOURCE_PREDICT_CALCULATE:
  263. for _, v := range edbMappingList {
  264. if v.FromEdbInfoId == edbInfo.EdbInfoId {
  265. edbName = fmt.Sprintf("%s(%s)", edbInfo.EdbName, v.FromTag)
  266. }
  267. }
  268. case utils.DATA_SOURCE_CALCULATE_ZJPJ, utils.DATA_SOURCE_PREDICT_CALCULATE_ZJPJ, utils.DATA_SOURCE_CALCULATE_LJZTBPJ, utils.DATA_SOURCE_PREDICT_CALCULATE_LJZTBPJ: // 直接拼接 ,累计值同比拼接
  269. for _, v := range edbMappingList {
  270. if v.FromEdbInfoId == edbInfo.EdbInfoId {
  271. tmpName := ``
  272. if v.FromTag == `A` {
  273. tmpName = `拼接日期前`
  274. } else if v.FromTag == `B` {
  275. tmpName = `拼接日期后`
  276. }
  277. edbName = fmt.Sprintf("%s(%s)", edbInfo.EdbName, tmpName)
  278. }
  279. }
  280. case utils.DATA_SOURCE_CALCULATE_NHCC, utils.DATA_SOURCE_PREDICT_CALCULATE_NHCC: //计算指标(拟合残差)
  281. for _, v := range edbMappingList {
  282. //(需对上游指标+自变量,领先10天/因变量)
  283. if v.FromEdbInfoId == edbInfo.EdbInfoId {
  284. tmpName := ``
  285. if v.FromTag == `A` {
  286. tmpName = fmt.Sprintf(`自变量,领先%d天`, v.MoveValue)
  287. } else if v.FromTag == `B` {
  288. tmpName = `因变量`
  289. }
  290. edbName = fmt.Sprintf("%s(%s)", edbInfo.EdbName, tmpName)
  291. }
  292. }
  293. case utils.DATA_SOURCE_CALCULATE_CORRELATION: // 滚动相关性
  294. for _, v := range edbMappingList {
  295. if v.FromEdbInfoId == edbInfo.EdbInfoId {
  296. edbName = fmt.Sprintf("%s(%s)", edbInfo.EdbName, v.FromTag)
  297. }
  298. }
  299. }
  300. }
  301. if edbInfo.EdbType == 1 {
  302. // 基础指标的话,直接返回来源名称
  303. //ruleTitle = `来源于`+edbInfo.SourceName
  304. return
  305. }
  306. // 规则
  307. switch edbInfo.Source {
  308. case utils.DATA_SOURCE_CALCULATE, utils.DATA_SOURCE_PREDICT_CALCULATE:
  309. ruleTitle = "=" + edbInfo.CalculateFormula
  310. case utils.DATA_SOURCE_CALCULATE_LJZZY, utils.DATA_SOURCE_PREDICT_CALCULATE_LJZZY:
  311. ruleTitle = `累计转月值计算`
  312. case utils.DATA_SOURCE_CALCULATE_TBZ, utils.DATA_SOURCE_PREDICT_CALCULATE_TBZ:
  313. ruleTitle = `同比值计算`
  314. case utils.DATA_SOURCE_CALCULATE_TCZ, utils.DATA_SOURCE_PREDICT_CALCULATE_TCZ:
  315. ruleTitle = `同差值计算`
  316. case utils.DATA_SOURCE_CALCULATE_NSZYDPJJS, utils.DATA_SOURCE_PREDICT_CALCULATE_NSZYDPJJS:
  317. ruleTitle = fmt.Sprintf("N数值移动均值计算(N=%s)", edbInfo.CalculateFormula)
  318. case utils.DATA_SOURCE_CALCULATE_HBZ, utils.DATA_SOURCE_PREDICT_CALCULATE_HBZ:
  319. ruleTitle = fmt.Sprintf("N数值环比值计算(N=%s)", edbInfo.CalculateFormula)
  320. case utils.DATA_SOURCE_CALCULATE_HCZ, utils.DATA_SOURCE_PREDICT_CALCULATE_HCZ:
  321. ruleTitle = fmt.Sprintf("N数值环差值计算(N=%s)", edbInfo.CalculateFormula)
  322. case utils.DATA_SOURCE_CALCULATE_TIME_SHIFT, utils.DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT:
  323. moveType := `领先`
  324. if edbInfo.MoveType == 2 {
  325. moveType = "滞后"
  326. }
  327. ruleTitle = fmt.Sprintf("时间移位计算(%s%s%s)", moveType, edbInfo.CalculateFormula, edbInfo.MoveFrequency)
  328. case utils.DATA_SOURCE_CALCULATE_BP, utils.DATA_SOURCE_PREDICT_CALCULATE_BP: // 变频
  329. childFrequency := ``
  330. if len(childList) > 0 {
  331. if childEdbInfo, ok := edbInfoMap[childList[0].EdbInfoId]; ok {
  332. childFrequency = childEdbInfo.Frequency
  333. }
  334. }
  335. ruleTitle = fmt.Sprintf("升频计算(%s转%s)", childFrequency, edbInfo.Frequency)
  336. case utils.DATA_SOURCE_CALCULATE_ZJPJ, utils.DATA_SOURCE_PREDICT_CALCULATE_ZJPJ: // 直接拼接
  337. ruleTitle = fmt.Sprintf("直接拼接计算(%s)", edbInfo.CalculateFormula)
  338. case utils.DATA_SOURCE_CALCULATE_LJZTBPJ, utils.DATA_SOURCE_PREDICT_CALCULATE_LJZTBPJ: // 累计值同比拼
  339. ruleTitle = fmt.Sprintf("累计值同比值拼接计算(%s)", edbInfo.CalculateFormula)
  340. case utils.DATA_SOURCE_PYTHON:
  341. ruleTitle = `代码运算`
  342. case utils.DATA_SOURCE_CALCULATE_CJJX, utils.DATA_SOURCE_PREDICT_CALCULATE_CJJX:
  343. ruleTitle = fmt.Sprintf("超季节性计算(N=%s,%s)", edbInfo.CalculateFormula, edbInfo.Calendar)
  344. case utils.DATA_SOURCE_CALCULATE_NHCC, utils.DATA_SOURCE_PREDICT_CALCULATE_NHCC: //计算指标(拟合残差)
  345. var startDate, endDate string
  346. dateList := strings.Split(edbInfo.CalculateFormula, ",")
  347. if len(dateList) == 2 {
  348. startDate = dateList[0]
  349. endDate = dateList[1]
  350. }
  351. ruleTitle = fmt.Sprintf("拟合残差计算(%s至%s)", startDate, endDate)
  352. case utils.DATA_SOURCE_CALCULATE_ADJUST:
  353. ruleTitle = `数据调整`
  354. case utils.DATA_SOURCE_CALCULATE_NH, utils.DATA_SOURCE_PREDICT_CALCULATE_NH:
  355. ruleTitle = `年化计算`
  356. case utils.DATA_SOURCE_CALCULATE_KSZS, utils.DATA_SOURCE_PREDICT_CALCULATE_KSZS: // 扩散指数->53
  357. type KszsConfig struct {
  358. DateType int `description:"扩散指标日期;1:全部指标日期并集;2:部分指标日期并集"`
  359. CheckList []string `description:"选中的数据,A,B,C"`
  360. }
  361. var config KszsConfig
  362. err := json.Unmarshal([]byte(edbInfo.CalculateFormula), &config)
  363. if err != nil {
  364. return
  365. }
  366. var startDate, endDate time.Time
  367. childEdbInfoIdList := make([]int, 0)
  368. if config.DateType == 1 {
  369. for _, v := range childList {
  370. childEdbInfoIdList = append(childEdbInfoIdList, v.EdbInfoId)
  371. }
  372. } else {
  373. if parentEdbInfo != nil {
  374. edbMappingList, ok := edbMappingMap[parentEdbInfo.EdbInfoId]
  375. if !ok {
  376. edbMappingList = []*models.EdbInfoCalculateMappingInfo{}
  377. }
  378. tagMap := make(map[string]int)
  379. for _, v := range edbMappingList {
  380. tagMap[v.FromTag] = v.FromEdbInfoId
  381. }
  382. for _, v := range config.CheckList {
  383. if tmpEdbInfoId, ok := tagMap[v]; ok {
  384. childEdbInfoIdList = append(childEdbInfoIdList, tmpEdbInfoId)
  385. }
  386. }
  387. }
  388. }
  389. for _, v := range childEdbInfoIdList {
  390. if childEdbInfo, ok := edbInfoMap[v]; ok {
  391. tmpStartDate, tmpErr := time.ParseInLocation(utils.FormatDate, childEdbInfo.StartDate, time.Local)
  392. if tmpErr != nil {
  393. return
  394. }
  395. if startDate.IsZero() || startDate.After(tmpStartDate) {
  396. startDate = tmpStartDate
  397. }
  398. tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, childEdbInfo.EndDate, time.Local)
  399. if tmpErr != nil {
  400. return
  401. }
  402. if endDate.IsZero() || endDate.Before(tmpEndDate) {
  403. endDate = tmpEndDate
  404. }
  405. }
  406. }
  407. ruleTitle = fmt.Sprintf("扩散指数计算(%s至%s)", startDate.Format(utils.FormatDate), endDate.Format(utils.FormatDate))
  408. case utils.DATA_SOURCE_STOCK_PLANT:
  409. ruleTitle = `来源于装置分析`
  410. case utils.DATA_SOURCE_CALCULATE_CORRELATION:
  411. type EdbCalculateFormula struct {
  412. BaseCalculateValue int `description:"基础计算窗口"`
  413. BaseCalculateUnit string `description:"基础计算频度"`
  414. LeadValue int `description:"领先期数"`
  415. LeadUnit string `description:"频度"`
  416. CalculateValue int `description:"计算窗口"`
  417. CalculateUnit string `description:"计算频度"`
  418. }
  419. var correlationConf EdbCalculateFormula
  420. err := json.Unmarshal([]byte(edbInfo.CalculateFormula), &correlationConf)
  421. if err != nil {
  422. return
  423. }
  424. ruleTitle = fmt.Sprintf("滚动相关性(计算窗口%d%s,B领先A%d%s)", correlationConf.CalculateValue, correlationConf.CalculateUnit, correlationConf.LeadValue, correlationConf.LeadUnit)
  425. case utils.DATA_SOURCE_CALCULATE_JP, utils.DATA_SOURCE_PREDICT_CALCULATE_JP:
  426. childFrequency := ``
  427. if len(childList) > 0 {
  428. if childEdbInfo, ok := edbInfoMap[childList[0].EdbInfoId]; ok {
  429. childFrequency = childEdbInfo.Frequency
  430. }
  431. }
  432. ruleTitle = fmt.Sprintf("降频计算(%s转%s,%s)", childFrequency, edbInfo.Frequency, edbInfo.CalculateFormula)
  433. case utils.DATA_SOURCE_CALCULATE_STANDARD_DEVIATION:
  434. ruleTitle = fmt.Sprintf("标准差(滚动%s期)", edbInfo.CalculateFormula)
  435. case utils.DATA_SOURCE_CALCULATE_PERCENTILE, utils.DATA_SOURCE_PREDICT_CALCULATE_PERCENTILE:
  436. type TempCalculate struct {
  437. CalculateValue int `description:"计算窗口"`
  438. CalculateUnit string `description:"计算频度"`
  439. }
  440. cf := TempCalculate{}
  441. if e := json.Unmarshal([]byte(edbInfo.CalculateFormula), &cf); e != nil {
  442. return
  443. }
  444. ruleTitle = fmt.Sprintf("百分位(时间长度%d%s)", cf.CalculateValue, cf.CalculateUnit)
  445. case utils.DATA_SOURCE_CALCULATE_ZSXY, utils.DATA_SOURCE_PREDICT_CALCULATE_ZSXY:
  446. ruleTitle = `指数修匀计算`
  447. }
  448. return
  449. }
  450. // HandleDataByLinearRegressionToList 插值法补充数据(线性方程式)
  451. func HandleDataByLinearRegressionToList (edbInfoDataList []*models.EdbDataList, handleDataMap map[string]float64) (dataTimeList []string,valueList []float64, err error) {
  452. if len(edbInfoDataList) < 2 {
  453. return
  454. }
  455. var startEdbInfoData *models.EdbDataList
  456. for _, v := range edbInfoDataList {
  457. handleDataMap[v.DataTime] = v.Value
  458. dataTimeList = append(dataTimeList, v.DataTime)
  459. // 第一个数据就给过滤了,给后面的试用
  460. if startEdbInfoData == nil {
  461. startEdbInfoData = v
  462. //startEdbInfoData.DataTime = startEdbInfoData.DataTime[:5]+ "01-01"
  463. continue
  464. }
  465. // 获取两条数据之间相差的天数
  466. startDataTime, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
  467. currDataTime, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
  468. betweenHour := int(currDataTime.Sub(startDataTime).Hours())
  469. betweenDay := betweenHour / 24
  470. // 如果相差一天,那么过滤
  471. if betweenDay <= 1 {
  472. startEdbInfoData = v
  473. continue
  474. }
  475. // 生成线性方程式
  476. var a, b float64
  477. {
  478. coordinateData := make([]utils.Coordinate, 0)
  479. tmpCoordinate1 := utils.Coordinate{
  480. X: 1,
  481. Y: startEdbInfoData.Value,
  482. }
  483. coordinateData = append(coordinateData, tmpCoordinate1)
  484. tmpCoordinate2 := utils.Coordinate{
  485. X: float64(betweenDay) + 1,
  486. Y: v.Value,
  487. }
  488. coordinateData = append(coordinateData, tmpCoordinate2)
  489. a, b = utils.GetLinearResult(coordinateData)
  490. if math.IsNaN(a) || math.IsNaN(b) {
  491. err = errors.New("线性方程公式生成失败")
  492. return
  493. }
  494. }
  495. // 生成对应的值
  496. {
  497. for i := 1; i < betweenDay; i++ {
  498. tmpDataTime := startDataTime.AddDate(0, 0, i)
  499. aDecimal := decimal.NewFromFloat(a)
  500. xDecimal := decimal.NewFromInt(int64(i) + 1)
  501. bDecimal := decimal.NewFromFloat(b)
  502. val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
  503. handleDataMap[tmpDataTime.Format(utils.FormatDate)] = val
  504. dataTimeList = append(dataTimeList, tmpDataTime.Format(utils.FormatDate))
  505. valueList = append(valueList, val)
  506. }
  507. }
  508. startEdbInfoData = v
  509. }
  510. return
  511. }
  512. // HandleDataByLinearRegressionToList 保证生成365个数据点的线性插值法
  513. func HandleDataByLinearRegressionToListV2(edbInfoDataList []*models.EdbDataList, handleDataMap map[string]float64) (dataTimeList []string, valueList []float64, err error) {
  514. if len(edbInfoDataList) < 2 {
  515. return
  516. }
  517. // 确保至少有两天数据来生成线性方程
  518. if len(edbInfoDataList) < 2 {
  519. err = errors.New("至少需要两天的数据来执行线性插值")
  520. return
  521. }
  522. // 对数据按日期排序,确保顺序正确
  523. sort.Slice(edbInfoDataList, func(i, j int) bool {
  524. t1, _ := time.ParseInLocation(utils.FormatDate, edbInfoDataList[i].DataTime, time.Local)
  525. t2, _ := time.ParseInLocation(utils.FormatDate, edbInfoDataList[j].DataTime, time.Local)
  526. return t1.Before(t2)
  527. })
  528. startEdbInfoData := edbInfoDataList[0]
  529. endEdbInfoData := edbInfoDataList[len(edbInfoDataList)-1]
  530. // 计算起始和结束日期间实际的天数
  531. startDate, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
  532. endDate, _ := time.ParseInLocation(utils.FormatDate, endEdbInfoData.DataTime, time.Local)
  533. actualDays := endDate.Sub(startDate).Hours() / 24
  534. // 生成365个数据点,首先处理已有数据
  535. for _, v := range edbInfoDataList {
  536. handleDataMap[v.DataTime] = v.Value
  537. dataTimeList = append(dataTimeList, v.DataTime)
  538. valueList = append(valueList, v.Value)
  539. }
  540. // 如果已有数据跨越天数不足365天,则对缺失的日期进行线性插值
  541. if actualDays < 365 {
  542. // 使用已有数据点生成线性方程(这里简化处理,实际可能需更细致处理边界情况)
  543. var a, b float64
  544. coordinateData := []utils.Coordinate{
  545. {X: 1, Y: startEdbInfoData.Value},
  546. {X: float64(len(edbInfoDataList)), Y: endEdbInfoData.Value},
  547. }
  548. a, b = utils.GetLinearResult(coordinateData)
  549. if math.IsNaN(a) || math.IsNaN(b) {
  550. err = errors.New("线性方程公式生成失败")
  551. return
  552. }
  553. // 对剩余日期进行插值
  554. for i := 1; i < 365; i++ {
  555. day := startDate.AddDate(0, 0, i)
  556. if _, exists := handleDataMap[day.Format(utils.FormatDate)]; !exists {
  557. aDecimal := decimal.NewFromFloat(a)
  558. xDecimal := decimal.NewFromInt(int64(i) + 1)
  559. bDecimal := decimal.NewFromFloat(b)
  560. val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
  561. handleDataMap[day.Format(utils.FormatDate)] = val
  562. dataTimeList = append(dataTimeList, day.Format(utils.FormatDate))
  563. valueList = append(valueList, val)
  564. }
  565. }
  566. }
  567. return
  568. }