Browse Source

拟合残差 a,b,r计算

gmy 3 weeks ago
parent
commit
f9cf4b3281
1 changed files with 117 additions and 27 deletions
  1. 117 27
      services/residual_analysis_service/residual_analysis_service.go

+ 117 - 27
services/residual_analysis_service/residual_analysis_service.go

@@ -58,7 +58,7 @@ func ResidualAnalysisPreview(req residual_analysis_model.ResidualAnalysisReq) (r
 	// 原始图表信息
 	originalEdbList := make([]residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, 0)
 
-	originalEdbList, err = fillOriginalChart(req, mappingList, startDate, endDate, edbInfoMappingA, edbInfoMappingB, originalEdbList)
+	originalEdbList, fullADataList, fullBDataList, err := fillOriginalChart(req, mappingList, startDate, endDate, edbInfoMappingA, edbInfoMappingB, originalEdbList)
 	if err != nil {
 		return residual_analysis_model.ResidualAnalysisResp{}, err
 	}
@@ -84,7 +84,7 @@ func ResidualAnalysisPreview(req residual_analysis_model.ResidualAnalysisReq) (r
 	}
 
 	// 映射图表信息
-	mappingEdbList, a, b, r, err := fillMappingChartInfo(req, edbInfoMappingA, edbInfoMappingB, originalEdbList, indexADataMap)
+	mappingEdbList, a, b, r, err := fillMappingChartInfo(req, edbInfoMappingA, edbInfoMappingB, originalEdbList, indexADataMap, startDate, endDate, fullADataList, fullBDataList)
 	if err != nil {
 		return residual_analysis_model.ResidualAnalysisResp{}, err
 	}
@@ -246,7 +246,7 @@ func fillResidualChartInfo(req residual_analysis_model.ResidualAnalysisReq, edbI
 	return mappingEdb, R2, nil
 }
 
-func fillMappingChartInfo(req residual_analysis_model.ResidualAnalysisReq, edbInfoMappingA *data_manage.ChartEdbInfoMapping, edbInfoMappingB *data_manage.ChartEdbInfoMapping, originalEdbList []residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, indexADataMap map[string]*data_manage.EdbDataList) ([]residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, float64, float64, float64, error) {
+func fillMappingChartInfo(req residual_analysis_model.ResidualAnalysisReq, edbInfoMappingA *data_manage.ChartEdbInfoMapping, edbInfoMappingB *data_manage.ChartEdbInfoMapping, originalEdbList []residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, indexADataMap map[string]*data_manage.EdbDataList, startDate string, endDate string, fullADataList []*data_manage.EdbDataList, fullBDataList []*data_manage.EdbDataList) ([]residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, float64, float64, float64, error) {
 	// 计算公式:Y=aX+b,Y为映射后的指标,X为自变量指标
 	// 正序:a=(L2-L1)/(R2-R1)	b=L2-R2*a
 	// 逆序:a=(L2-L1)/(R1-R2)	b=L2-R1*a
@@ -264,28 +264,12 @@ func fillMappingChartInfo(req residual_analysis_model.ResidualAnalysisReq, edbIn
 		}
 	}
 
+	//dataAList := edbInfoMappingA.DataList.([]*data_manage.EdbDataList)
 	dataList, ok := edbInfoMappingB.DataList.([]*data_manage.EdbDataList)
 	if !ok {
 		return nil, a, b, r, fmt.Errorf("数据类型转换失败")
 	}
 
-	// 拟合残差 计算a,b
-	var coordinateList []utils.Coordinate
-	if req.ResidualType == 2 {
-		for _, indexData := range dataList {
-			if _, ok := indexADataMap[indexData.DataTime]; ok {
-
-				coordinate := utils.Coordinate{
-					X: indexData.Value,
-					Y: indexADataMap[indexData.DataTime].Value,
-				}
-				coordinateList = append(coordinateList, coordinate)
-			}
-		}
-		a, b = utils.GetLinearResult(coordinateList)
-		r = utils.CalculationDecisive(coordinateList)
-	}
-
 	// 指标B数据补充
 	// 新建一个切片来保存补充的数据
 	var replenishDataList []*data_manage.EdbDataList
@@ -317,12 +301,109 @@ func fillMappingChartInfo(req residual_analysis_model.ResidualAnalysisReq, edbIn
 	// 将补充数据插入原始数据列表
 	dataList = append(dataList, replenishDataList...)
 
-	// 填充映射指标值 使得时间长度一致
-	dataList = FillDataBList(dataList, edbInfoMappingA)
-
 	// 排序
 	sort.Sort(ByDataTime(dataList))
 
+	// 拟合残差 计算a,b
+	var coordinateList []utils.Coordinate
+	var replenishADataList []*data_manage.EdbDataList
+	var replenishBDataList []*data_manage.EdbDataList
+	if req.ResidualType == 2 {
+		//
+
+		// 因变量指标也转换为日度
+		for index := 0; index < len(fullADataList)-1; index++ {
+			// 获取当前数据和下一个数据
+			beforeIndexData := fullADataList[index]
+			afterIndexData := fullADataList[index+1]
+
+			replenishADataList = append(replenishADataList, beforeIndexData)
+			// 从最早时间开始,补充时间为自然日
+			if utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
+				for {
+					// 创建补充数据
+					nextDay := utils.GetNextDay(beforeIndexData.DataTime)
+					toTime := utils.StringToTime(nextDay)
+					replenishIndexData := data_manage.EdbDataList{
+						DataTime:      nextDay, // 计算下一个自然日
+						DataTimestamp: toTime.UnixMilli(),
+						Value:         beforeIndexData.Value, // 可以选择使用前一天的值,或者其他逻辑来计算值
+					}
+
+					// 将补充数据加入补充数据列表
+					replenishADataList = append(replenishADataList, &replenishIndexData)
+
+					// 更新 beforeIndexData 为新创建的补充数据
+					beforeIndexData = &replenishIndexData
+
+					// 检查是否还需要继续补充数据
+					if !utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
+						break
+					}
+				}
+			}
+		}
+		replenishADataList = append(replenishADataList, fullADataList[len(fullADataList)-1])
+
+		// 自变量指标也转换为日度
+		for index := 0; index < len(fullBDataList)-1; index++ {
+			// 获取当前数据和下一个数据
+			beforeIndexData := fullBDataList[index]
+			afterIndexData := fullBDataList[index+1]
+
+			replenishBDataList = append(replenishBDataList, beforeIndexData)
+			// 从最早时间开始,补充时间为自然日
+			if utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
+				for {
+					// 创建补充数据
+					nextDay := utils.GetNextDay(beforeIndexData.DataTime)
+					toTime := utils.StringToTime(nextDay)
+					replenishIndexData := data_manage.EdbDataList{
+						DataTime:      nextDay, // 计算下一个自然日
+						DataTimestamp: toTime.UnixMilli(),
+						Value:         beforeIndexData.Value, // 可以选择使用前一天的值,或者其他逻辑来计算值
+					}
+
+					// 将补充数据加入补充数据列表
+					replenishBDataList = append(replenishBDataList, &replenishIndexData)
+
+					// 更新 beforeIndexData 为新创建的补充数据
+					beforeIndexData = &replenishIndexData
+
+					// 检查是否还需要继续补充数据
+					if !utils.IsMoreThanOneDay(beforeIndexData.DataTime, afterIndexData.DataTime) {
+						break
+					}
+				}
+			}
+		}
+		replenishBDataList = append(replenishBDataList, fullBDataList[len(fullBDataList)-1])
+
+		// replenishADataList --> map
+		replenishADataMap := make(map[string]*data_manage.EdbDataList)
+		for _, indexData := range replenishADataList {
+			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))) {
+				replenishADataMap[indexData.DataTime] = indexData
+			}
+		}
+
+		for _, indexData := range replenishBDataList {
+			if _, ok = replenishADataMap[indexData.DataTime]; ok {
+
+				coordinate := utils.Coordinate{
+					X: indexData.Value,
+					Y: replenishADataMap[indexData.DataTime].Value,
+				}
+				coordinateList = append(coordinateList, coordinate)
+			}
+		}
+		a, b = utils.GetLinearResult(coordinateList)
+		r = utils.ComputeCorrelation(coordinateList)
+	}
+
+	// 填充映射指标值 使得时间长度一致
+	dataList = FillDataBList(dataList, edbInfoMappingA)
+
 	// 根据指标A的时间key,在B的映射指标中筛选出对应的值
 	var dataBList []*data_manage.EdbDataList
 
@@ -417,7 +498,9 @@ func (a ByDataTime) Less(i, j int) bool {
 	return t1.Before(t2)
 }
 
-func fillOriginalChart(req residual_analysis_model.ResidualAnalysisReq, mappingList []*data_manage.ChartEdbInfoMapping, startDate string, endDate string, edbInfoMappingA *data_manage.ChartEdbInfoMapping, edbInfoMappingB *data_manage.ChartEdbInfoMapping, originalEdbList []residual_analysis_model.ResidualAnalysisChartEdbInfoMapping) ([]residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, error) {
+func fillOriginalChart(req residual_analysis_model.ResidualAnalysisReq, mappingList []*data_manage.ChartEdbInfoMapping, startDate string, endDate string, edbInfoMappingA *data_manage.ChartEdbInfoMapping, edbInfoMappingB *data_manage.ChartEdbInfoMapping, originalEdbList []residual_analysis_model.ResidualAnalysisChartEdbInfoMapping) ([]residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, []*data_manage.EdbDataList, []*data_manage.EdbDataList, error) {
+
+	var fullADataList, fullBDataList []*data_manage.EdbDataList
 	for _, v := range mappingList {
 		var edbInfoMapping residual_analysis_model.ResidualAnalysisChartEdbInfoMapping
 		edbInfoMapping.EdbInfoType = 1
@@ -430,7 +513,12 @@ func fillOriginalChart(req residual_analysis_model.ResidualAnalysisReq, mappingL
 		// 获取图表中的指标数据
 		dataList, err := data_manage.GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, startDate, endDate)
 		if err != nil {
-			return nil, fmt.Errorf("获取指标数据失败,Err:%s", err.Error())
+			return nil, nil, nil, fmt.Errorf("获取指标数据失败,Err:%s", err.Error())
+		}
+		// 重新获取指标数据 产品要求需要和计算指标-拟合残差逻辑保持一致
+		fullDataList, err := data_manage.GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, "", "")
+		if err != nil {
+			return nil, nil, nil, fmt.Errorf("获取指标数据失败,Err:%s", err.Error())
 		}
 
 		if v.EdbInfoId == req.EdbInfoIdB {
@@ -445,7 +533,7 @@ func fillOriginalChart(req residual_analysis_model.ResidualAnalysisReq, mappingL
 			// 领先指标 dataList进行数据处理
 			if req.IndexType == 2 {
 				if req.LeadValue < 0 {
-					return nil, fmt.Errorf("领先值不能小于0")
+					return nil, nil, nil, fmt.Errorf("领先值不能小于0")
 				} else if req.LeadValue > 0 {
 					edbInfoMapping.EdbName = v.EdbName + "(领先" + strconv.Itoa(req.LeadValue) + req.LeadFrequency + ")"
 					for _, indexData := range dataList {
@@ -467,8 +555,10 @@ func fillOriginalChart(req residual_analysis_model.ResidualAnalysisReq, mappingL
 			}
 
 			edbInfoMappingB.DataList = dataList
+			fullBDataList = fullDataList
 		} else {
 			edbInfoMappingA.DataList = dataList
+			fullADataList = fullDataList
 		}
 		edbInfoMapping.EdbInfoId = v.EdbInfoId
 		edbInfoMapping.EdbCode = v.EdbCode
@@ -484,7 +574,7 @@ func fillOriginalChart(req residual_analysis_model.ResidualAnalysisReq, mappingL
 		edbInfoMapping.DataList = dataList
 		originalEdbList = append(originalEdbList, edbInfoMapping)
 	}
-	return originalEdbList, nil
+	return originalEdbList, fullADataList, fullBDataList, nil
 }
 
 func ContrastPreview(indexCode string) (residual_analysis_model.ResidualAnalysisChartEdbInfoMapping, error) {