edb_data_residual_analysis.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. package models
  2. import (
  3. "encoding/json"
  4. "eta/eta_index_lib/global"
  5. "eta/eta_index_lib/utils"
  6. "fmt"
  7. "github.com/shopspring/decimal"
  8. "gorm.io/gorm"
  9. "math"
  10. "sort"
  11. "strconv"
  12. "time"
  13. )
  14. type edbDataResidualAnalysis struct {
  15. EdbDataId int `gorm:"column:edb_data_id;type:int(11);primaryKey;not null;"`
  16. EdbInfoId int `gorm:"column:edb_info_id;type:int(11);comment:指标id;default:NULL;"` // 指标id
  17. EdbCode string `gorm:"column:edb_code;type:varchar(190);comment:指标编码;default:NULL;"` // 指标编码
  18. DataTime string `gorm:"column:data_time;type:date;comment:数据日期;default:NULL;"` // 数据日期
  19. Value float64 `gorm:"column:value;type:double;comment:数据值;default:NULL;"` // 数据值
  20. CreateTime time.Time `gorm:"column:create_time;type:datetime;comment:创建时间;default:NULL;" ` // 创建时间
  21. ModifyTime time.Time `gorm:"column:modify_time;type:datetime;comment:修改时间;default:NULL;"` // 修改时间
  22. DataTimeStamp int64 `gorm:"column:data_timestamp;type:bigint(20);comment:数据日期时间戳;default:0;"` // 数据日期时间戳
  23. }
  24. // AfterFind 在该模型上设置钩子函数,把日期转成正确的string,所以查询函数只能用Find函数,First或者Scan是不会触发该函数的来获取数据
  25. func (m *edbDataResidualAnalysis) AfterFind(db *gorm.DB) (err error) {
  26. m.DataTime = utils.GormDateStrToDateStr(m.DataTime)
  27. return
  28. }
  29. // ConvertTimeStr
  30. // @Description: 转成需要输出的格式
  31. // @receiver m
  32. func (m *edbDataResidualAnalysis) ConvertTimeStr() {
  33. m.DataTime = utils.GormDateStrToDateStr(m.DataTime)
  34. return
  35. }
  36. // AddResidualAnalysisData 新增指标数据
  37. func AddResidualAnalysisData(dataList []edbDataResidualAnalysis) (err error) {
  38. err = global.DEFAULT_DB.CreateInBatches(dataList, utils.MultiAddNum).Error
  39. if err != nil {
  40. return err
  41. }
  42. return nil
  43. }
  44. // RefreshAllCalculateResidualAnalysis 刷新残差分析
  45. func RefreshAllCalculateResidualAnalysis(edbInfoId, source, subSource, formulaInt, moveType int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate, moveFrequency string) (err error) {
  46. to := global.DEFAULT_DB
  47. /*to, err := o.Begin()
  48. if err != nil {
  49. return
  50. }
  51. defer func() {
  52. if err != nil {
  53. fmt.Println("RefreshAllCalculateResidualAnalysis,Err:" + err.Error())
  54. _ = to.Rollback()
  55. } else {
  56. _ = to.Commit()
  57. }
  58. }()*/
  59. //只清空残差分析数据自身指标的数据
  60. configMapping, err := GetConfigMappingListByConditionNotBase(edbInfoId)
  61. //if err != nil {
  62. // return err
  63. //}
  64. //
  65. //var edbInfoIdList []int64
  66. //for _, v := range configMapping {
  67. // edbInfoIdList = append(edbInfoIdList, v.EdbInfoId)
  68. //}
  69. //清空原有数据
  70. //sql := ` DELETE FROM edb_data_residual_analysis WHERE edb_info_id in (` + utils.GetOrmInReplace(len(edbInfoIdList)) + `) `
  71. //var params []interface{}
  72. //for _, i := range edbInfoIdList {
  73. // params = append(params, i)
  74. //}
  75. var params []interface{}
  76. sql := ` DELETE FROM edb_data_residual_analysis WHERE edb_info_id = ?`
  77. params = append(params, edbInfoId)
  78. //var params []interface{}
  79. //for _, i := range edbInfoIdList {
  80. // params = append(params, i)
  81. //}
  82. err = to.Exec(sql, params...).Error
  83. if err != nil {
  84. return
  85. }
  86. //计算数据
  87. err = refreshAllCalculateResidualAnalysis(edbInfoId, source, subSource, formulaInt, moveType, fromEdbInfo, edbCode, startDate, endDate, moveFrequency, configMapping)
  88. return
  89. }
  90. // refreshAllCalculateResidualAnalysis 刷新所有残差分析
  91. func refreshAllCalculateResidualAnalysis(edbInfoId, source, subSource, formulaInt, moveType int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate, moveFrequency string, configMapping []CalculateResidualAnalysisConfigMapping) (err error) {
  92. fmt.Println("refreshAllCalculateResidualAnalysis startDate:", startDate)
  93. configMap := make(map[int64]CalculateResidualAnalysisConfigMapping, len(configMapping))
  94. for _, v := range configMapping {
  95. configMap[v.EdbInfoId] = v
  96. }
  97. calculateMappingList, err := GetCalculateMappingListByEdbInfoId(edbInfoId)
  98. if err != nil {
  99. return err
  100. }
  101. //这里顺序和之前的不一致导致的计算错误
  102. var edbInfoIdA, edbInfoIdB int
  103. if configMap[int64(calculateMappingList[0].FromEdbInfoId)].IndexType == 3 {
  104. edbInfoIdA = calculateMappingList[0].FromEdbInfoId
  105. edbInfoIdB = calculateMappingList[1].FromEdbInfoId
  106. } else {
  107. edbInfoIdA = calculateMappingList[1].FromEdbInfoId
  108. edbInfoIdB = calculateMappingList[0].FromEdbInfoId
  109. }
  110. mappingList, err := GetEdbInfoListByIds([]int{edbInfoIdA, edbInfoIdB})
  111. if err != nil {
  112. return err
  113. }
  114. var edbInfoMappingA, edbInfoMappingB *EdbInfoList
  115. for _, v := range mappingList {
  116. if v.Unit == "无" {
  117. v.Unit = ""
  118. }
  119. if v.EdbInfoId == edbInfoIdA {
  120. edbInfoMappingA = v
  121. }
  122. if v.EdbInfoId == edbInfoIdB {
  123. edbInfoMappingB = v
  124. }
  125. }
  126. if edbInfoMappingA == nil {
  127. return fmt.Errorf("指标A不存在")
  128. }
  129. if edbInfoMappingB == nil {
  130. return fmt.Errorf("指标B不存在")
  131. }
  132. // 从配置中取出时间范围
  133. analysisConfig, err := GetResidualAnalysisConfigById(edbInfoId)
  134. if err != nil {
  135. return err
  136. }
  137. configString := analysisConfig.Config
  138. var config ResidualAnalysisConfig
  139. err = json.Unmarshal([]byte(configString), &config)
  140. // 时间处理
  141. switch config.DateType {
  142. case -1:
  143. startDate = config.StartDate
  144. endDate = config.EndDate
  145. case 0:
  146. startDate = config.StartDate
  147. endDate = ""
  148. default:
  149. startDate = utils.GetPreYearTime(config.DateType)
  150. endDate = ""
  151. }
  152. // 原始图表信息
  153. originalEdbList := make([]EdbInfoList, 0)
  154. originalEdbList, fullADataList, fullBDataList, err := fillOriginalChart(config, fromEdbInfo, mappingList, startDate, endDate, edbInfoMappingA, edbInfoMappingB, originalEdbList)
  155. if err != nil {
  156. return err
  157. }
  158. indexADataMap := map[string]*EdbData{}
  159. for _, indexData := range edbInfoMappingA.DataList {
  160. indexADataMap[indexData.DataTime] = indexData
  161. }
  162. // 映射图表信息
  163. mappingEdbList, _, _, _, err := fillMappingChartInfo(config, fromEdbInfo, edbInfoMappingA, edbInfoMappingB, originalEdbList, indexADataMap, startDate, endDate, fullADataList, fullBDataList)
  164. if err != nil {
  165. return err
  166. }
  167. // 残差图表信息
  168. residualEdbList, _, err := fillResidualChartInfo(config, fromEdbInfo, edbInfoMappingA, edbInfoMappingB, mappingEdbList)
  169. // 映射指标 与 残差指标 同步刷新
  170. //for _, mapping := range configMapping {
  171. mapping := configMap[int64(edbInfoId)]
  172. var edbDataResidualAnalysisList []edbDataResidualAnalysis
  173. if mapping.IndexType == 1 {
  174. edbInfo, err := GetEdbInfoById(int(mapping.EdbInfoId))
  175. if err != nil {
  176. return err
  177. }
  178. for _, edbList := range mappingEdbList {
  179. if edbList.EdbInfoId == 0 {
  180. for _, edbData := range edbList.DataList {
  181. value, _ := strconv.ParseFloat(edbData.Value, 64)
  182. edbDataResidualAnalysisList = append(edbDataResidualAnalysisList, edbDataResidualAnalysis{
  183. EdbInfoId: int(mapping.EdbInfoId),
  184. EdbCode: edbInfo.EdbCode,
  185. DataTime: edbData.DataTime,
  186. Value: value,
  187. CreateTime: time.Now(),
  188. ModifyTime: time.Now(),
  189. DataTimeStamp: edbData.DataTimestamp,
  190. })
  191. }
  192. err = AddResidualAnalysisData(edbDataResidualAnalysisList)
  193. if err != nil {
  194. return err
  195. }
  196. break
  197. }
  198. }
  199. } else if mapping.IndexType == 2 {
  200. edbInfo, err := GetEdbInfoById(int(mapping.EdbInfoId))
  201. if err != nil {
  202. return err
  203. }
  204. for _, edbList := range residualEdbList {
  205. if edbList.EdbInfoId == 0 {
  206. for _, edbData := range edbList.DataList {
  207. value, _ := strconv.ParseFloat(edbData.Value, 64)
  208. edbDataResidualAnalysisList = append(edbDataResidualAnalysisList, edbDataResidualAnalysis{
  209. EdbInfoId: int(mapping.EdbInfoId),
  210. EdbCode: edbInfo.EdbCode,
  211. DataTime: edbData.DataTime,
  212. Value: value,
  213. CreateTime: time.Now(),
  214. ModifyTime: time.Now(),
  215. DataTimeStamp: edbData.DataTimestamp,
  216. })
  217. }
  218. err = AddResidualAnalysisData(edbDataResidualAnalysisList)
  219. if err != nil {
  220. return err
  221. }
  222. break
  223. }
  224. }
  225. }
  226. return
  227. }
  228. func fillResidualChartInfo(config ResidualAnalysisConfig, req *EdbInfo, edbInfoMappingA *EdbInfoList, edbInfoMappingB *EdbInfoList, mappingEdbList []EdbInfoList) ([]EdbInfoList, float64, error) {
  229. // 计算公式 映射残差 = 因变量指标 - 映射指标
  230. var edbInfoA, edbInfoB EdbInfoList
  231. if mappingEdbList[0].EdbInfoId == edbInfoMappingA.EdbInfoId {
  232. edbInfoA = mappingEdbList[0]
  233. edbInfoB = mappingEdbList[1]
  234. } else {
  235. edbInfoA = mappingEdbList[1]
  236. edbInfoB = mappingEdbList[0]
  237. }
  238. dataAList := edbInfoA.DataList
  239. edbData := make([]*EdbDataList, len(dataAList))
  240. for i, data := range dataAList {
  241. //f, _ := strconv.ParseFloat(data.Value, 64)
  242. f, _ := decimal.NewFromString(data.Value)
  243. edbData[i] = &EdbDataList{
  244. Value: f.InexactFloat64(),
  245. DataTimestamp: data.DataTimestamp,
  246. DataTime: data.DataTime,
  247. EdbInfoId: data.EdbInfoId,
  248. EdbDataId: data.EdbDataId,
  249. }
  250. }
  251. dataBList := edbInfoB.DataList
  252. // 映射指标开始时间
  253. var startTime string
  254. if len(dataBList) > 0 {
  255. startTime = dataBList[0].DataTime
  256. }
  257. var indexDataBMap = make(map[string]*EdbData)
  258. for _, data := range dataBList {
  259. indexDataBMap[data.DataTime] = data
  260. }
  261. // 求R2
  262. var valueB, sumValueA, averageValueA, residualQuadraticSum, totalQuadraticSum, R2 float64
  263. for _, indexData := range edbData {
  264. // 因变量的值总和
  265. sumValueA += indexData.Value
  266. }
  267. // 因变量平均值
  268. averageValueA = sumValueA / float64(len(edbData))
  269. var indexMax, indexMin float64
  270. var edbDataResp []*EdbDataList
  271. if len(edbData) > 0 {
  272. indexMax = edbData[0].Value
  273. indexMin = edbData[0].Value
  274. for _, indexData := range edbData {
  275. if dataB, ok := indexDataBMap[indexData.DataTime]; ok {
  276. f, _ := strconv.ParseFloat(dataB.Value, 64)
  277. valueB = f
  278. } else {
  279. continue
  280. }
  281. // 总因变量平方和
  282. totalQuadraticSum += math.Pow(indexData.Value-averageValueA, 2)
  283. // 补全残差值
  284. indexData.Value = math.Round((indexData.Value-valueB)*10000) / 10000
  285. // 残差平方和
  286. residualQuadraticSum += math.Pow(indexData.Value, 2)
  287. if indexData.Value > indexMax {
  288. indexMax = indexData.Value
  289. }
  290. if indexData.Value < indexMin {
  291. indexMin = indexData.Value
  292. }
  293. // 获取映射指标之后的数据
  294. if startTime != "" && utils.CompareDate(startTime, indexData.DataTime) {
  295. edbDataResp = append(edbDataResp, indexData)
  296. }
  297. }
  298. }
  299. // 计算R2 公式:R2=1-SSE/SST R2越大,越符合线性 R2 = 1 - 残差平方和/总平方和
  300. R2 = 1 - residualQuadraticSum/totalQuadraticSum
  301. mappingEdb := make([]EdbInfoList, len(mappingEdbList))
  302. copy(mappingEdb, mappingEdbList)
  303. for i, mapping := range mappingEdb {
  304. if mapping.EdbInfoId != edbInfoMappingA.EdbInfoId {
  305. toEdbData := convertEdbDataListToEdbData(edbDataResp)
  306. mappingEdb[i].DataList = toEdbData
  307. mappingEdb[i].EdbName = edbInfoMappingA.EdbName + "映射残差/" + edbInfoMappingB.EdbName
  308. if config.IndexType == 2 {
  309. if config.LeadValue > 0 {
  310. mappingEdb[i].EdbName = edbInfoMappingA.EdbName + "映射残差/" + edbInfoMappingB.EdbName + "(领先" + strconv.Itoa(config.LeadValue) + config.LeadFrequency + ")"
  311. }
  312. }
  313. }
  314. }
  315. //reverse(mappingEdb)
  316. return mappingEdb, R2, nil
  317. }
  318. // 双指针法
  319. func reverse(slice []EdbInfoList) {
  320. left, right := 0, len(slice)-1
  321. for left < right {
  322. // 交换元素
  323. slice[left], slice[right] = slice[right], slice[left]
  324. left++
  325. right--
  326. }
  327. }
  328. func fillMappingChartInfo(config ResidualAnalysisConfig, req *EdbInfo, edbInfoMappingA *EdbInfoList, edbInfoMappingB *EdbInfoList, originalEdbList []EdbInfoList, indexADataMap map[string]*EdbData, startDate string, endDate string, fullADataList []*EdbDataList, fullBDataList []*EdbDataList) ([]EdbInfoList, float64, float64, float64, error) {
  329. // 计算公式:Y=aX+b,Y为映射后的指标,X为自变量指标
  330. // 正序:a=(L2-L1)/(R2-R1) b=L2-R2*a
  331. // 逆序:a=(L2-L1)/(R1-R2) b=L2-R1*a
  332. // L2:左轴下限 R2:右轴上限 L1:左轴上限 R1:右轴下限
  333. var a, b, r float64
  334. // 映射残差 计算a,b
  335. if config.ResidualType == 1 {
  336. if config.IsOrder {
  337. a = (config.LeftIndexMax - config.LeftIndexMin) / (config.RightIndexMin - config.RightIndexMax)
  338. b = config.LeftIndexMax - config.RightIndexMin*a
  339. } else {
  340. a = (config.LeftIndexMax - config.LeftIndexMin) / (config.RightIndexMax - config.RightIndexMin)
  341. b = config.LeftIndexMax - config.RightIndexMax*a
  342. }
  343. }
  344. dataList := edbInfoMappingB.DataList
  345. sort.Sort(ByDataTime(dataList))
  346. for _, indexData := range dataList {
  347. fmt.Printf("%s--%s\n", indexData.Value, indexData.DataTime)
  348. }
  349. fmt.Println("========================================================================================================")
  350. // 指标B数据补充
  351. // 新建一个切片来保存补充的数据
  352. var replenishDataList []*EdbData
  353. for index := 0; index < len(dataList)-1; index++ {
  354. // 获取当前数据和下一个数据
  355. beforeIndexData := dataList[index]
  356. afterIndexData := dataList[index+1]
  357. // 从最早时间开始,补充时间为自然日
  358. for utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
  359. // 创建补充数据
  360. nextDay := utils.GetNextDay(beforeIndexData.DataTime)
  361. toTime := utils.StringToTime(nextDay)
  362. replenishIndexData := EdbData{
  363. DataTime: nextDay, // 计算下一个自然日
  364. DataTimestamp: toTime.UnixMilli(),
  365. Value: beforeIndexData.Value, // 可以选择使用前一天的值,或者其他逻辑来计算值
  366. }
  367. // 将补充数据加入补充数据列表
  368. replenishDataList = append(replenishDataList, &replenishIndexData)
  369. // 更新 beforeIndexData 为新创建的补充数据
  370. beforeIndexData = &replenishIndexData
  371. }
  372. }
  373. // 将补充数据插入原始数据列表
  374. dataList = append(dataList, replenishDataList...)
  375. // 排序
  376. sort.Sort(ByDataTime(dataList))
  377. // 排序
  378. sort.Sort(ByDataTime(dataList))
  379. for _, indexData := range dataList {
  380. fmt.Printf("%s--%s\n", indexData.Value, indexData.DataTime)
  381. }
  382. fmt.Println("========================================================================================================")
  383. // 拟合残差 计算a,b
  384. var coordinateList []utils.Coordinate
  385. var replenishADataList []*EdbDataList
  386. var replenishBDataList []*EdbDataList
  387. if config.ResidualType == 2 {
  388. //
  389. // 因变量指标也转换为日度
  390. for index := 0; index < len(fullADataList)-1; index++ {
  391. // 获取当前数据和下一个数据
  392. beforeIndexData := fullADataList[index]
  393. afterIndexData := fullADataList[index+1]
  394. replenishADataList = append(replenishADataList, beforeIndexData)
  395. // 从最早时间开始,补充时间为自然日
  396. if utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
  397. for {
  398. // 创建补充数据
  399. nextDay := utils.GetNextDay(beforeIndexData.DataTime)
  400. toTime := utils.StringToTime(nextDay)
  401. replenishIndexData := EdbDataList{
  402. DataTime: nextDay, // 计算下一个自然日
  403. DataTimestamp: toTime.UnixMilli(),
  404. Value: beforeIndexData.Value, // 可以选择使用前一天的值,或者其他逻辑来计算值
  405. }
  406. // 将补充数据加入补充数据列表
  407. replenishADataList = append(replenishADataList, &replenishIndexData)
  408. // 更新 beforeIndexData 为新创建的补充数据
  409. beforeIndexData = &replenishIndexData
  410. // 检查是否还需要继续补充数据
  411. if !utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
  412. break
  413. }
  414. }
  415. }
  416. }
  417. replenishADataList = append(replenishADataList, fullADataList[len(fullADataList)-1])
  418. // 自变量指标也转换为日度
  419. for index := 0; index < len(fullBDataList)-1; index++ {
  420. // 获取当前数据和下一个数据
  421. beforeIndexData := fullBDataList[index]
  422. afterIndexData := fullBDataList[index+1]
  423. replenishBDataList = append(replenishBDataList, beforeIndexData)
  424. // 从最早时间开始,补充时间为自然日
  425. if utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
  426. for {
  427. // 创建补充数据
  428. nextDay := utils.GetNextDay(beforeIndexData.DataTime)
  429. toTime := utils.StringToTime(nextDay)
  430. replenishIndexData := EdbDataList{
  431. DataTime: nextDay, // 计算下一个自然日
  432. DataTimestamp: toTime.UnixMilli(),
  433. Value: beforeIndexData.Value, // 可以选择使用前一天的值,或者其他逻辑来计算值
  434. }
  435. // 将补充数据加入补充数据列表
  436. replenishBDataList = append(replenishBDataList, &replenishIndexData)
  437. // 更新 beforeIndexData 为新创建的补充数据
  438. beforeIndexData = &replenishIndexData
  439. // 检查是否还需要继续补充数据
  440. if !utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
  441. break
  442. }
  443. }
  444. }
  445. }
  446. replenishBDataList = append(replenishBDataList, fullBDataList[len(fullBDataList)-1])
  447. // replenishADataList --> map
  448. replenishADataMap := make(map[string]*EdbDataList)
  449. for _, indexData := range replenishADataList {
  450. if (utils.StringToTime(indexData.DataTime).After(utils.StringToTime(startDate)) || utils.StringToTime(indexData.DataTime).Equal(utils.StringToTime(startDate))) && (endDate == "" || utils.StringToTime(indexData.DataTime).Before(utils.StringToTime(endDate))) {
  451. replenishADataMap[indexData.DataTime] = indexData
  452. }
  453. }
  454. for _, indexData := range replenishBDataList {
  455. if _, ok := replenishADataMap[indexData.DataTime]; ok {
  456. coordinate := utils.Coordinate{
  457. X: indexData.Value,
  458. Y: replenishADataMap[indexData.DataTime].Value,
  459. }
  460. coordinateList = append(coordinateList, coordinate)
  461. }
  462. }
  463. a, b = utils.GetLinearResult(coordinateList)
  464. r = utils.ComputeCorrelation(coordinateList)
  465. }
  466. // 填充映射指标值 使得时间长度一致
  467. dataList = FillDataBList(dataList, edbInfoMappingA)
  468. for _, indexData := range dataList {
  469. fmt.Printf("%s--%s\n", indexData.Value, indexData.DataTime)
  470. }
  471. // 根据指标A的时间key,在B的映射指标中筛选出对应的值
  472. var dataBList []*EdbDataList
  473. var indexMax, indexMin string
  474. if len(dataList) > 0 {
  475. indexMax = dataList[0].Value
  476. indexMin = dataList[0].Value
  477. for _, indexData := range dataList {
  478. if _, ok := indexADataMap[indexData.DataTime]; ok {
  479. indexDataCopy := *indexData
  480. // 计算指标B映射值
  481. //f, _ := strconv.ParseFloat(indexData.Value, 64)
  482. f, _ := decimal.NewFromString(indexData.Value)
  483. indexDataCopy.Value = fmt.Sprintf("%f", math.Round((a*f.InexactFloat64()+b)*10000)/10000)
  484. //fmt.Printf("%s--%s%s\n", indexData.Value, indexDataCopy.Value, indexData.DataTime)
  485. // 比较最大值
  486. if indexData.Value > indexMax {
  487. indexMax = indexData.Value
  488. }
  489. // 比较最小值
  490. if indexData.Value < indexMin {
  491. indexMin = indexData.Value
  492. }
  493. // 将副本添加到 dataBList
  494. copyValue, _ := strconv.ParseFloat(indexDataCopy.Value, 64)
  495. dataBList = append(dataBList, &EdbDataList{
  496. DataTime: indexDataCopy.DataTime,
  497. DataTimestamp: indexDataCopy.DataTimestamp,
  498. EdbDataId: indexDataCopy.EdbDataId,
  499. EdbInfoId: indexDataCopy.EdbInfoId,
  500. Value: copyValue,
  501. })
  502. }
  503. }
  504. }
  505. mappingEdbList := make([]EdbInfoList, len(originalEdbList))
  506. copy(mappingEdbList, originalEdbList)
  507. for i, mapping := range mappingEdbList {
  508. if mapping.EdbInfoId != edbInfoMappingA.EdbInfoId {
  509. mappingEdbList[i].EdbInfoId = 0
  510. mappingEdbList[i].EdbCode = ""
  511. mappingEdbList[i].EdbName = edbInfoMappingB.EdbName + "映射" + edbInfoMappingA.EdbName
  512. if config.IndexType == 2 {
  513. if config.LeadValue > 0 {
  514. mappingEdbList[i].EdbName = edbInfoMappingB.EdbName + "映射" + edbInfoMappingA.EdbName + "(领先" + strconv.Itoa(config.LeadValue) + config.LeadFrequency + ")"
  515. }
  516. }
  517. edbData := convertEdbDataListToEdbData(dataBList)
  518. mappingEdbList[i].DataList = edbData
  519. }
  520. }
  521. return mappingEdbList, a, b, r, nil
  522. }
  523. // FillDataBList 填充B的数据 使得与A的时间保持一致
  524. func FillDataBList(dataList []*EdbData, edbInfoMappingA *EdbInfoList) []*EdbData {
  525. dataAList := edbInfoMappingA.DataList
  526. if len(dataList) > 0 && len(dataAList) > 0 {
  527. fmt.Println("len(dataList):", len(dataList), "len(dataAList):", len(dataAList))
  528. for utils.StringToTime(dataList[len(dataList)-1].DataTime).Before(utils.StringToTime(dataAList[len(dataAList)-1].DataTime)) {
  529. // 使用A的时间填充时间差
  530. timeDiff := utils.GetNextDayN(dataList[len(dataList)-1].DataTime, 1)
  531. // 创建新的数据点并填充 前值填充
  532. newDataPoint := &EdbData{
  533. DataTime: timeDiff,
  534. Value: dataList[len(dataList)-1].Value,
  535. DataTimestamp: utils.StringToTime(timeDiff).UnixMilli(),
  536. }
  537. // 将新数据点添加到dataList末尾
  538. dataList = append(dataList, newDataPoint)
  539. }
  540. }
  541. return dataList
  542. }
  543. func fillOriginalChart(config ResidualAnalysisConfig, req *EdbInfo, mappingList []*EdbInfoList, startDate string, endDate string, edbInfoMappingA *EdbInfoList, edbInfoMappingB *EdbInfoList, originalEdbList []EdbInfoList) ([]EdbInfoList, []*EdbDataList, []*EdbDataList, error) {
  544. var fullADataList, fullBDataList []*EdbDataList
  545. for _, v := range mappingList {
  546. var edbInfoMapping EdbInfoList
  547. edbInfoMapping.EdbName = v.EdbName
  548. // 获取图表中的指标数据
  549. dataList, err := GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, startDate, endDate)
  550. if err != nil {
  551. return nil, nil, nil, fmt.Errorf("获取指标数据失败,Err:%s", err.Error())
  552. }
  553. data := convertEdbDataListToEdbData(dataList)
  554. // 重新获取指标数据 产品要求需要和计算指标-拟合残差逻辑保持一致
  555. fullDataList, err := GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, "", "")
  556. if err != nil {
  557. return nil, nil, nil, fmt.Errorf("获取指标数据失败,Err:%s", err.Error())
  558. }
  559. if v.EdbInfoId == edbInfoMappingB.EdbInfoId {
  560. // 领先指标 dataList进行数据处理
  561. if config.IndexType == 2 {
  562. if config.LeadValue < 0 {
  563. return nil, nil, nil, fmt.Errorf("领先值不能小于0")
  564. } else if config.LeadValue > 0 {
  565. edbInfoMapping.EdbName = v.EdbName + "(领先" + strconv.Itoa(config.LeadValue) + config.LeadFrequency + ")"
  566. for _, indexData := range data {
  567. switch config.LeadFrequency {
  568. case "天":
  569. indexData.DataTime = utils.GetNextDayN(indexData.DataTime, config.LeadValue)
  570. case "周":
  571. indexData.DataTime = utils.GetNextDayN(indexData.DataTime, config.LeadValue*7)
  572. case "月":
  573. indexData.DataTime = utils.TimeToString(utils.AddDate(utils.StringToTime(indexData.DataTime), 0, config.LeadValue), utils.YearMonthDay)
  574. case "季":
  575. indexData.DataTime = utils.TimeToString(utils.AddDate(utils.StringToTime(indexData.DataTime), 0, config.LeadValue*3), utils.YearMonthDay)
  576. case "年":
  577. indexData.DataTime = utils.TimeToString(utils.AddDate(utils.StringToTime(indexData.DataTime), config.LeadValue, 0), utils.YearMonthDay)
  578. }
  579. indexData.DataTimestamp = utils.StringToTime(indexData.DataTime).UnixMilli()
  580. }
  581. }
  582. }
  583. edbInfoMappingB.DataList = data
  584. fullBDataList = fullDataList
  585. } else {
  586. edbInfoMappingA.DataList = data
  587. fullADataList = fullDataList
  588. }
  589. edbInfoMapping.EdbInfoId = v.EdbInfoId
  590. edbInfoMapping.EdbCode = v.EdbCode
  591. edbInfoMapping.Unit = v.Unit
  592. edbInfoMapping.Frequency = v.Frequency
  593. edbInfoMapping.Source = v.Source
  594. edbInfoMapping.SourceName = v.SourceName
  595. edbInfoMapping.LatestDate = v.LatestDate
  596. edbInfoMapping.LatestValue = v.LatestValue
  597. edbInfoMapping.DataList = data
  598. originalEdbList = append(originalEdbList, edbInfoMapping)
  599. }
  600. return originalEdbList, fullADataList, fullBDataList, nil
  601. }
  602. func convertEdbDataListToEdbData(edbDataLists []*EdbDataList) []*EdbData {
  603. var edbDataList []*EdbData
  604. for _, edbData := range edbDataLists {
  605. data := &EdbData{
  606. DataTime: edbData.DataTime,
  607. DataTimestamp: edbData.DataTimestamp,
  608. EdbDataId: edbData.EdbDataId,
  609. EdbInfoId: edbData.EdbInfoId,
  610. Value: fmt.Sprintf("%f", edbData.Value),
  611. }
  612. edbDataList = append(edbDataList, data)
  613. }
  614. return edbDataList
  615. }
  616. type ByDataTime []*EdbData
  617. func (a ByDataTime) Len() int {
  618. return len(a)
  619. }
  620. func (a ByDataTime) Swap(i, j int) {
  621. a[i], a[j] = a[j], a[i]
  622. }
  623. func (a ByDataTime) Less(i, j int) bool {
  624. t1 := utils.StringToTime(a[i].DataTime)
  625. t2 := utils.StringToTime(a[j].DataTime)
  626. return t1.Before(t2)
  627. }