Roc 2 years ago
parent
commit
556359380b

+ 11 - 1
controllers/base_from_calculate.go

@@ -543,7 +543,7 @@ func (this *CalculateController) BatchSave() {
 		}
 	}
 
-	notNeedFromEdbSourceList := []int{utils.DATA_SOURCE_CALCULATE_KSZS} // 不需要传入来源指标id的 指标类型
+	notNeedFromEdbSourceList := []int{utils.DATA_SOURCE_CALCULATE_KSZS, utils.DATA_SOURCE_CALCULATE_CORRELATION} // 不需要传入来源指标id的 指标类型
 	if fromEdbInfoId <= 0 && !utils.InArrayByInt(notNeedFromEdbSourceList, req.Source) {
 		br.Msg = "请选择指标"
 		return
@@ -767,6 +767,16 @@ func (this *CalculateController) BatchSave() {
 		}
 		sourName = utils.DATA_SOURCE_NAME_CALCULATE_KSZS
 		edbInfo, err = models.AddCalculateKszs(&req, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_CORRELATION:
+		//关联的指标信息
+		if len(req.EdbInfoIdArr) < 2 {
+			br.Msg = "指标数量不能小于2个,请重新选择"
+			br.ErrMsg = "指标数量不能小于2个,请重新选择"
+			br.IsSendEmail = false
+			return
+		}
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_CORRELATION
+		edbInfo, err = models.AddCalculateKszs(&req, edbCode, uniqueCode, sysUserId, sysUserName)
 	default:
 		br.Msg = "无效计算方式"
 		br.ErrMsg = "无效计算方式,source:" + strconv.Itoa(req.Source)

+ 1 - 1
models/edb_data_calculate_cjjx.go

@@ -254,7 +254,7 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
 
 	// 通过插值法补全所有数据(包含周末)
 	handleDataMap := make(map[string]float64)
-	err = HandleDataByLinearRegression(dataList, handleDataMap)
+	_, err = HandleDataByLinearRegression(dataList, handleDataMap)
 	if err != nil {
 		return
 	}

+ 549 - 0
models/edb_data_calculate_correlation.go

@@ -0,0 +1,549 @@
+package models
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// AddCalculateCorrelation 扩散指数
+func AddCalculateCorrelation(req *EdbInfoCalculateBatchSaveReq, edbCode, uniqueCode string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("AddCalculateCorrelation,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId > 0 {
+		err = errors.New("无法新增")
+		return
+	}
+
+	edbInfo = new(EdbInfo)
+	edbInfo.Source = utils.DATA_SOURCE_CALCULATE_CORRELATION
+	edbInfo.SourceName = utils.DATA_SOURCE_NAME_CALCULATE_CORRELATION
+	edbInfo.EdbCode = edbCode
+	edbInfo.EdbName = req.EdbName
+	edbInfo.EdbNameSource = req.EdbName
+	edbInfo.Frequency = req.Frequency
+	edbInfo.Unit = req.Unit
+	edbInfo.ClassifyId = req.ClassifyId
+	edbInfo.SysUserId = sysUserId
+	edbInfo.SysUserRealName = sysUserRealName
+	edbInfo.CreateTime = time.Now()
+	edbInfo.ModifyTime = time.Now()
+	edbInfo.UniqueCode = uniqueCode
+	edbInfo.CalculateFormula = req.Formula
+	edbInfo.EdbType = 2
+	newEdbInfoId, tmpErr := to.Insert(edbInfo)
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	edbInfo.EdbInfoId = int(newEdbInfoId)
+
+	//关联关系
+	tagMap := make(map[string]int)
+	relationEdbInfoList := make([]*EdbInfo, 0)
+	calculateMappingItemList := make([]*EdbInfoCalculateMapping, 0)
+	for _, v := range req.EdbInfoIdArr {
+		tmpEdbInfo, tmpErr := GetEdbInfoById(v.EdbInfoId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		relationEdbInfoList = append(relationEdbInfoList, tmpEdbInfo)
+
+		calculateMappingItem := new(EdbInfoCalculateMapping)
+		calculateMappingItem.CreateTime = time.Now()
+		calculateMappingItem.ModifyTime = time.Now()
+		calculateMappingItem.Sort = 1
+		calculateMappingItem.EdbCode = edbCode
+		calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+		calculateMappingItem.FromEdbInfoId = tmpEdbInfo.EdbInfoId
+		calculateMappingItem.FromEdbCode = tmpEdbInfo.EdbCode
+		calculateMappingItem.FromEdbName = tmpEdbInfo.EdbName
+		calculateMappingItem.FromSource = tmpEdbInfo.Source
+		calculateMappingItem.FromSourceName = tmpEdbInfo.SourceName
+		calculateMappingItem.FromTag = v.FromTag
+		calculateMappingItem.Source = edbInfo.Source
+		calculateMappingItem.SourceName = edbInfo.SourceName
+		calculateMappingItemList = append(calculateMappingItemList, calculateMappingItem)
+
+		tagMap[v.FromTag] = v.EdbInfoId
+	}
+	_, err = to.InsertMulti(len(calculateMappingItemList), calculateMappingItemList)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	err = refreshAllCalculateCorrelation(to, edbInfo.EdbInfoId, edbInfo.Source, relationEdbInfoList, edbInfo.EdbCode, edbInfo.CalculateFormula, tagMap)
+
+	return
+}
+
+// EditCalculateCorrelation 修改扩散指数数据
+func EditCalculateCorrelation(edbInfo *EdbInfo, req *EdbInfoCalculateBatchEditReq) (err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("EditCalculateCorrelation,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//修改指标信息
+	edbInfo.EdbName = req.EdbName
+	edbInfo.EdbNameSource = req.EdbName
+	edbInfo.Frequency = req.Frequency
+	edbInfo.Unit = req.Unit
+	edbInfo.ClassifyId = req.ClassifyId
+	edbInfo.CalculateFormula = req.Formula
+	edbInfo.ModifyTime = time.Now()
+	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime")
+	if err != nil {
+		return
+	}
+
+	//删除,计算指标关联的,基础指标的关联关系
+	sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+	if err != nil {
+		err = errors.New("删除计算指标关联关系失败,Err:" + err.Error())
+		return
+	}
+	//清空原有数据
+	tableName := GetEdbDataTableName(edbInfo.Source)
+	sql = ` DELETE FROM ` + tableName + ` WHERE edb_info_id = ? `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+	if err != nil {
+		return
+	}
+
+	//关联关系
+	tagMap := make(map[string]int)
+	relationEdbInfoList := make([]*EdbInfo, 0)
+	calculateMappingItemList := make([]*EdbInfoCalculateMapping, 0)
+	for _, v := range req.EdbInfoIdArr {
+		tmpEdbInfo, tmpErr := GetEdbInfoById(v.EdbInfoId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		relationEdbInfoList = append(relationEdbInfoList, tmpEdbInfo)
+
+		calculateMappingItem := new(EdbInfoCalculateMapping)
+		calculateMappingItem.CreateTime = time.Now()
+		calculateMappingItem.ModifyTime = time.Now()
+		calculateMappingItem.Sort = 1
+		calculateMappingItem.EdbCode = edbInfo.EdbCode
+		calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+		calculateMappingItem.FromEdbInfoId = tmpEdbInfo.EdbInfoId
+		calculateMappingItem.FromEdbCode = tmpEdbInfo.EdbCode
+		calculateMappingItem.FromEdbName = tmpEdbInfo.EdbName
+		calculateMappingItem.FromSource = tmpEdbInfo.Source
+		calculateMappingItem.FromSourceName = tmpEdbInfo.SourceName
+		calculateMappingItem.FromTag = v.FromTag
+		calculateMappingItem.Source = edbInfo.Source
+		calculateMappingItem.SourceName = edbInfo.SourceName
+		calculateMappingItemList = append(calculateMappingItemList, calculateMappingItem)
+
+		tagMap[v.FromTag] = v.EdbInfoId
+	}
+	_, err = to.InsertMulti(len(calculateMappingItemList), calculateMappingItemList)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	err = refreshAllCalculateCorrelation(to, edbInfo.EdbInfoId, edbInfo.Source, relationEdbInfoList, edbInfo.EdbCode, edbInfo.CalculateFormula, tagMap)
+
+	return
+}
+
+func RefreshAllCalculateCorrelation(edbInfo *EdbInfo) (err error) {
+	edbInfoCalculateDetailList, err := GetEdbInfoCalculateDetailList(edbInfo.EdbInfoId)
+	if err != nil {
+		return
+	}
+	tagMap := make(map[string]int)
+	relationEdbInfoList := make([]*EdbInfo, 0)
+	for _, v := range edbInfoCalculateDetailList {
+		tagMap[v.FromTag] = v.FromEdbInfoId
+		fromEdbInfo, _ := GetEdbInfoById(v.FromEdbInfoId)
+		relationEdbInfoList = append(relationEdbInfoList, fromEdbInfo)
+	}
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllCalculateCorrelation,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 计算数据
+	err = refreshAllCalculateCorrelation(to, edbInfo.EdbInfoId, edbInfo.Source, relationEdbInfoList, edbInfo.EdbCode, edbInfo.CalculateFormula, tagMap)
+
+	return
+}
+
+// CorrelationConfig 扩散指数配置
+type CorrelationConfig struct {
+	DateType  int      `description:"扩散指标日期;1:全部指标日期并集;2:部分指标日期并集"`
+	CheckList []string `description:"选中的数据,A,B,C"`
+}
+
+// refreshAllCalculateCorrelation 刷新扩散指数数据
+func refreshAllCalculateCorrelation(to orm.TxOrmer, edbInfoId, source int, relationEdbInfoList []*EdbInfo, edbCode, calculateFormula string, tagMap map[string]int) (err error) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	tableName := GetEdbDataTableName(utils.DATA_SOURCE_CALCULATE_CORRELATION)
+
+	// 获取扩散指标关联的指标id
+	checkEdbInfoIdMap := make(map[int]int)
+	{
+		var config CorrelationConfig
+		err = json.Unmarshal([]byte(calculateFormula), &config)
+		if err != nil {
+			return
+		}
+		if config.DateType == 1 {
+			for _, tmpEdbInfoId := range tagMap {
+				checkEdbInfoIdMap[tmpEdbInfoId] = tmpEdbInfoId
+			}
+		} else {
+			for _, v := range config.CheckList {
+				if tmpEdbInfoId, ok := tagMap[v]; ok {
+					checkEdbInfoIdMap[tmpEdbInfoId] = tmpEdbInfoId
+				}
+			}
+		}
+	}
+
+	//获取扩散指数指标所有数据
+	existDataList, err := GetAllEdbDataListByTo(to, edbInfoId, source)
+	if err != nil {
+		return
+	}
+	//计算指标的map
+	existDataMap := make(map[string]*EdbData, 0)
+	removeDateMap := make(map[string]string)
+	for _, v := range existDataList {
+		existDataMap[v.DataTime] = v
+		removeDateMap[v.DataTime] = ``
+	}
+
+	//获取来源指标的数据
+	relationEdbDataMap := make(map[int]map[string]float64)
+	// 获取选择指标的 需要数据的 开始日期和结束日期
+	var startDate, endDate time.Time
+	for _, v := range relationEdbInfoList {
+		var condition string
+		var pars []interface{}
+		condition += " AND edb_info_id=? "
+		pars = append(pars, v.EdbInfoId)
+		tmpDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, v.Source, 1)
+		if tmpErr != nil {
+			err = tmpErr
+			return err
+		}
+		if tmpDataList != nil {
+			if _, ok2 := checkEdbInfoIdMap[v.EdbInfoId]; ok2 {
+				lenTmpDataList := len(tmpDataList)
+				if lenTmpDataList > 0 {
+					tmpStartTime, _ := time.ParseInLocation(utils.FormatDate, tmpDataList[0].DataTime, time.Local)
+					tmpEndTime, _ := time.ParseInLocation(utils.FormatDate, tmpDataList[lenTmpDataList-1].DataTime, time.Local)
+
+					if startDate.IsZero() || tmpStartTime.Before(startDate) {
+						startDate = tmpStartTime
+					}
+
+					if tmpEndTime.IsZero() || tmpEndTime.After(endDate) {
+						endDate = tmpEndTime
+					}
+				}
+			}
+			// 用上期的数据补充当期的数据处理
+			handleDataMap := make(map[string]float64)
+			err = HandleDataByPreviousData(tmpDataList, handleDataMap)
+			if err != nil {
+				return
+			}
+			relationEdbDataMap[v.EdbInfoId] = handleDataMap
+		}
+	}
+
+	addSql := ` INSERT INTO ` + tableName + ` (edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+
+	for currDate := startDate.AddDate(0, 0, 1); !currDate.After(endDate); currDate = currDate.AddDate(0, 0, 1) {
+		currDateStr := currDate.Format(utils.FormatDate)
+
+		//环差指数列表
+		tmpValList := make([]float64, 0)
+		for _, dataMap := range relationEdbDataMap {
+			currVal, ok := dataMap[currDateStr]
+			if !ok {
+				continue
+			}
+
+			perVal, ok := dataMap[currDate.AddDate(0, 0, -1).Format(utils.FormatDate)]
+			if !ok {
+				continue
+			}
+
+			var tmpVal float64
+			if currVal > perVal {
+				tmpVal = 1
+			} else if currVal == perVal {
+				tmpVal = 0.5
+			} else {
+				tmpVal = 0
+			}
+			tmpValList = append(tmpValList, tmpVal)
+		}
+
+		lenTmpValList := len(tmpValList)
+		if lenTmpValList <= 0 {
+			continue
+		}
+
+		currValDeci := decimal.NewFromFloat(0)
+		for _, tmpVal := range tmpValList {
+			currValDeci = currValDeci.Add(decimal.NewFromFloat(tmpVal))
+		}
+		currVal, _ := currValDeci.Div(decimal.NewFromInt(int64(lenTmpValList))).Round(4).Float64()
+
+		// 判断扩散指数指标是否存在数据
+		if existData, ok := existDataMap[currDateStr]; ok {
+			// 处理扩散指数数据的值
+			existValStr := existData.Value
+			existValDeci, tmpErr := decimal.NewFromString(existValStr)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existVal, _ := existValDeci.Round(4).Float64()
+			// 判断扩散指数数据的值 与 当前计算出来的结果, 如果两个数据结果不相等的话,那么就修改咯
+			if existVal != currVal {
+				err = ModifyEdbDataById(source, existData.EdbDataId, fmt.Sprint(currVal))
+				if err != nil {
+					return err
+				}
+			}
+		} else {
+			// 直接入库
+			timestamp := currDate.UnixNano() / 1e6
+			timestampStr := fmt.Sprintf("%d", timestamp)
+			addSql += GetAddSql(edbInfoIdStr, edbCode, currDateStr, timestampStr, fmt.Sprint(currVal))
+			isAdd = true
+		}
+
+		delete(removeDateMap, currDateStr)
+	}
+
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+	}
+
+	// 移除不存在的日期数据
+	if len(removeDateMap) > 0 {
+		removeDateList := make([]string, 0) //需要移除的日期
+		for k := range removeDateMap {
+			removeDateList = append(removeDateList, k)
+		}
+		removeDateStr := strings.Join(removeDateList, `","`)
+		removeDateStr = `"` + removeDateStr + `"`
+		sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (%s) `, tableName, removeDateStr)
+		_, err = to.Raw(sql, edbInfoId).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除扩散指数指标数据失败,Err:" + err.Error())
+			return
+		}
+	}
+
+	return
+}
+
+// GetRollingCorrelationChartDataByEdbInfo 滚动相关性计算
+func GetRollingCorrelationChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB *EdbInfo, leadValue int, leadUnit string, calculateValue int, calculateUnit string, startDate, endDate string) (dateData map[string]float64, err error) {
+	yData := make([]float64, 0)
+
+	baseEdbInfo := edbInfoMappingA
+	changeEdbInfo := edbInfoMappingB
+
+	// 获取时间基准指标在时间区间内的值
+	aDataList := make([]*EdbInfoSearchData, 0)
+	switch baseEdbInfo.EdbInfoType {
+	case 0:
+		var condition string
+		var pars []interface{}
+		condition += " AND edb_info_id=? "
+		pars = append(pars, baseEdbInfo.EdbInfoId)
+
+		//获取来源指标的数据
+		aDataList, err = GetEdbDataListAll(condition, pars, baseEdbInfo.Source, 1)
+	case 1:
+		aDataList, err = GetPredictEdbDataListAllByStartDate(baseEdbInfo, 1, "")
+	default:
+		err = errors.New(fmt.Sprint("获取失败,指标base类型异常", baseEdbInfo.EdbInfoType))
+	}
+
+	// 获取变频指标所有日期的值, 插值法完善数据
+	bDataList := make([]*EdbInfoSearchData, 0)
+	switch changeEdbInfo.EdbInfoType {
+	case 0:
+		var condition string
+		var pars []interface{}
+		condition += " AND edb_info_id=? "
+		pars = append(pars, changeEdbInfo.EdbInfoId)
+
+		//获取来源指标的数据
+		bDataList, err = GetEdbDataListAll(condition, pars, changeEdbInfo.Source, 1)
+	case 1:
+		bDataList, err = GetPredictEdbDataListAllByStartDate(changeEdbInfo, 1, "")
+	default:
+		err = errors.New(fmt.Sprint("获取失败,指标change类型异常", baseEdbInfo.EdbInfoType))
+		return
+	}
+
+	// 数据平移变频指标领先/滞后的日期(单位天)
+	frequencyDaysMap := map[string]int{
+		"天": 1, "周": 7, "月": 30, "季": 90, "年": 365,
+	}
+	// 2023-03-17 时间序列始终以指标A为基准, 始终是B进行平移
+	//baseDataList := make([]*data_manage.EdbDataList, 0)
+	baseDataMap := make(map[string]float64)
+	changeDataList := make([]*EdbInfoSearchData, 0)
+	changeDataMap := make(map[string]float64)
+
+	// A指标不管三七二十一,先变个频再说
+	{
+		_, e := HandleDataByLinearRegression(aDataList, baseDataMap)
+		if e != nil {
+			err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
+			return
+		}
+		//baseDataList = tmpNewChangeDataList
+	}
+	// A指标不管三七二十一,先变个频再说
+	{
+		tmpNewChangeDataList, e := HandleDataByLinearRegression(bDataList, changeDataMap)
+		if e != nil {
+			err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
+			return
+		}
+		changeDataList = tmpNewChangeDataList
+
+		// 平移下日期
+		moveUnitDays := frequencyDaysMap[leadUnit]
+		_, changeDataMap = MoveDataDaysToNewDataList(changeDataList, leadValue*moveUnitDays)
+	}
+
+	// 计算计算时,需要多少个日期内数据
+	calculateDay := frequencyDaysMap[calculateUnit] * calculateValue
+
+	// 计算 每个日期的相关性值
+	{
+		startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		endDateTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+
+		for currDay := startDateTime; !currDay.After(endDateTime); currDay = currDay.AddDate(0, 0, 1) {
+			coordinateData := make([]utils.Coordinate, 0)
+			// 取出对应的基准日期的值
+			for i := 0; i < calculateDay; i++ {
+				iDay := currDay.AddDate(0, 0, i).Format(utils.FormatDate)
+				tmpCoordinate := utils.Coordinate{
+					X: baseDataMap[iDay],
+					Y: changeDataMap[iDay],
+				}
+				coordinateData = append(coordinateData, tmpCoordinate)
+			}
+
+			// 公式计算出领先/滞后频度对应点的相关性系数
+			var ratio float64
+			if len(coordinateData) > 0 {
+				ratio = utils.ComputeCorrelation(coordinateData)
+			}
+			yData = append(yData, ratio)
+			dateData[currDay.AddDate(0, 0, calculateDay).Format(utils.FormatDate)] = ratio
+		}
+	}
+	return
+}
+
+// MoveDataDaysToNewDataList 平移指标数据生成新的数据序列
+func MoveDataDaysToNewDataList(dataList []*EdbInfoSearchData, moveDay int) (newDataList []EdbInfoSearchData, dateDataMap map[string]float64) {
+	dateMap := make(map[time.Time]float64)
+	var minDate, maxDate time.Time
+	dateDataMap = make(map[string]float64)
+
+	for _, v := range dataList {
+		currDate, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
+		if minDate.IsZero() || currDate.Before(minDate) {
+			minDate = currDate
+		}
+		if maxDate.IsZero() || currDate.After(maxDate) {
+			maxDate = currDate
+		}
+		dateMap[currDate] = v.Value
+	}
+
+	// 处理领先、滞后数据
+	newDateMap := make(map[time.Time]float64)
+	for currDate, value := range dateMap {
+		newDate := currDate.AddDate(0, 0, moveDay)
+		newDateMap[newDate] = value
+	}
+	minDate = minDate.AddDate(0, 0, moveDay)
+	maxDate = maxDate.AddDate(0, 0, moveDay)
+
+	// 获取日期相差日
+	dayNum := utils.GetTimeSubDay(minDate, maxDate)
+
+	for i := 0; i <= dayNum; i++ {
+		currDate := minDate.AddDate(0, 0, i)
+		tmpValue, ok := newDateMap[currDate]
+		if !ok {
+			//找不到数据,那么就用前面的数据吧
+			if len(newDataList)-1 < 0 {
+				tmpValue = 0
+			} else {
+				tmpValue = newDataList[len(newDataList)-1].Value
+			}
+		}
+		tmpData := EdbInfoSearchData{
+			DataTime: currDate.Format(utils.FormatDate),
+			Value:    tmpValue,
+		}
+		dateDataMap[tmpData.DataTime] = tmpData.Value
+		newDataList = append(newDataList, tmpData)
+	}
+	return
+}

+ 1 - 1
models/edb_data_calculate_nh.go

@@ -232,7 +232,7 @@ func refreshAllCalculateNh(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 
 	// 插值法数据处理
 	handleDataMap := make(map[string]float64)
-	err = HandleDataByLinearRegression(fromDataList, handleDataMap)
+	_, err = HandleDataByLinearRegression(fromDataList, handleDataMap)
 	if err != nil {
 		return
 	}

+ 15 - 1
models/handle_data.go

@@ -9,7 +9,7 @@ import (
 )
 
 // HandleDataByLinearRegression 插值法补充数据(线性方程式)
-func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDataMap map[string]float64) (err error) {
+func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDataMap map[string]float64) (newList []*EdbInfoSearchData, err error) {
 	if len(edbInfoDataList) < 2 {
 		return
 	}
@@ -21,6 +21,11 @@ func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDa
 		// 第一个数据就给过滤了,给后面的试用
 		if startEdbInfoData == nil {
 			startEdbInfoData = v
+			newList = append(newList, &EdbInfoSearchData{
+				EdbDataId: v.EdbDataId,
+				DataTime:  v.DataTime,
+				Value:     v.Value,
+			})
 			continue
 		}
 
@@ -33,6 +38,11 @@ func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDa
 		// 如果相差一天,那么过滤
 		if betweenDay <= 1 {
 			startEdbInfoData = v
+			newList = append(newList, &EdbInfoSearchData{
+				EdbDataId: v.EdbDataId,
+				DataTime:  v.DataTime,
+				Value:     v.Value,
+			})
 			continue
 		}
 
@@ -68,6 +78,10 @@ func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDa
 
 				val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
 				handleDataMap[tmpDataTime.Format(utils.FormatDate)] = val
+				newList = append(newList, &EdbInfoSearchData{
+					DataTime: tmpDataTime.Format(utils.FormatDate),
+					Value:    val,
+				})
 			}
 		}
 

+ 1 - 1
models/predict_edb_data_calculate_nh.go

@@ -216,7 +216,7 @@ func refreshAllPredictCalculateNh(to orm.TxOrmer, edbInfoId, source int, fromEdb
 	}
 	// 插值法数据处理
 	handleDataMap := make(map[string]float64)
-	err = HandleDataByLinearRegression(fromDataList, handleDataMap)
+	_, err = HandleDataByLinearRegression(fromDataList, handleDataMap)
 	if err != nil {
 		return
 	}

+ 2 - 2
models/predict_edb_info_rule.go

@@ -690,7 +690,7 @@ func GetChartPredictEdbInfoDataListByRuleSeason(edbInfoId int, yearsList []int,
 
 	// 插值法数据处理
 	handleDataMap := make(map[string]float64)
-	err = HandleDataByLinearRegression(allDataList, handleDataMap)
+	_, err = HandleDataByLinearRegression(allDataList, handleDataMap)
 	if err != nil {
 		return
 	}
@@ -828,7 +828,7 @@ func GetChartPredictEdbInfoDataListByRuleSeason(edbInfoId int, yearsList []int,
 		existMap[currentDateStr] = val
 
 		// 继续使用插值法补充新预测日期的数据之间的值
-		err = HandleDataByLinearRegression([]*EdbInfoSearchData{
+		_, err = HandleDataByLinearRegression([]*EdbInfoSearchData{
 			lastDayData, tmpData,
 		}, handleDataMap)
 		if err != nil {

+ 65 - 0
utils/calculate.go

@@ -1,5 +1,10 @@
 package utils
 
+import (
+	"github.com/shopspring/decimal"
+	"math"
+)
+
 // Series is a container for a series of data
 type Series []Coordinate
 
@@ -43,3 +48,63 @@ func GetLinearResult(s []Coordinate) (gradient, intercept float64) {
 
 	return
 }
+
+// ComputeCorrelation 通过一组数据获取相关系数R
+// 计算步骤
+// 1.分别计算两个序列的平均值Mx和My
+// 2.分别计算两个序列的标准偏差SDx和SDy	=> √{1/(n-1)*SUM[(Xi-Mx)²]}
+// 3.计算相关系数	=> SUM[(Xi-Mx)*(Yi-My)]/[(N-1)(SDx*SDy)]
+func ComputeCorrelation(sList []Coordinate) (r float64) {
+	var xBar, yBar float64
+	lenSList := len(sList)
+	// 必须两组数据及两组以上的数据才能计算
+	if lenSList < 2 {
+		return
+	}
+	decimalX := decimal.NewFromFloat(0)
+	decimalY := decimal.NewFromFloat(0)
+
+	// 计算两组数据X、Y的平均值
+	for _, coordinate := range sList {
+		decimalX = decimalX.Add(decimal.NewFromFloat(coordinate.X))
+		decimalY = decimalY.Add(decimal.NewFromFloat(coordinate.Y))
+	}
+	xBar, _ = decimalX.Div(decimal.NewFromInt(int64(lenSList))).Round(4).Float64()
+	yBar, _ = decimalY.Div(decimal.NewFromInt(int64(lenSList))).Round(4).Float64()
+	//fmt.Println(xBar)
+	//fmt.Println(yBar)
+
+	varXDeci := decimal.NewFromFloat(0)
+	varYDeci := decimal.NewFromFloat(0)
+	ssrDeci := decimal.NewFromFloat(0)
+
+	for _, coordinate := range sList {
+		// 分别计算X、Y的实际数据与平均值的差值
+		diffXXbarDeci := decimal.NewFromFloat(coordinate.X).Sub(decimal.NewFromFloat(xBar))
+		diffYYbarDeci := decimal.NewFromFloat(coordinate.Y).Sub(decimal.NewFromFloat(yBar))
+		ssrDeci = ssrDeci.Add(diffXXbarDeci.Mul(diffYYbarDeci))
+		//fmt.Println("i:", i, ";diffXXbar:", diffXXbarDeci.String(), ";diffYYbar:", diffYYbarDeci.String(), ";ssr:", ssrDeci.String())
+		varXDeci = varXDeci.Add(diffXXbarDeci.Mul(diffXXbarDeci))
+		varYDeci = varYDeci.Add(diffYYbarDeci.Mul(diffYYbarDeci))
+		//varY += diffYYbar ** 2
+	}
+	sqrtVal, _ := varXDeci.Mul(varYDeci).Round(4).Float64()
+	//fmt.Println("sqrtVal:", sqrtVal)
+	sst := math.Sqrt(sqrtVal) // 平方根
+	//fmt.Println("sst:", sst)
+	// 如果计算出来的平方根是0,那么就直接返回,因为0不能作为除数
+	if sst == 0 {
+		return
+	}
+	r, _ = ssrDeci.Div(decimal.NewFromFloat(sst)).Round(4).Float64()
+
+	return
+}
+
+// CalculationDecisive 通过一组数据获取决定系数R2
+func CalculationDecisive(sList []Coordinate) (r2 float64) {
+	r := ComputeCorrelation(sList)
+	r2, _ = decimal.NewFromFloat(r).Mul(decimal.NewFromFloat(r)).Round(4).Float64()
+
+	return
+}

+ 55 - 50
utils/constants.go

@@ -29,56 +29,56 @@ const (
 
 // 数据来源渠道
 const (
-	DATA_SOURCE_THS                         = iota + 1 //同花顺
-	DATA_SOURCE_WIND                                   //wind
-	DATA_SOURCE_PB                                     //彭博
-	DATA_SOURCE_CALCULATE                              //指标运算
-	DATA_SOURCE_CALCULATE_LJZZY                        //累计值转月
-	DATA_SOURCE_CALCULATE_TBZ                          //同比值
-	DATA_SOURCE_CALCULATE_TCZ                          //同差值
-	DATA_SOURCE_CALCULATE_NSZYDPJJS                    //N数值移动平均计算
-	DATA_SOURCE_MANUAL                                 //手工指标
-	DATA_SOURCE_LZ                                     //隆众
-	DATA_SOURCE_YS                                     //有色
-	DATA_SOURCE_CALCULATE_HBZ                          //环比值->12
-	DATA_SOURCE_CALCULATE_HCZ                          //环差值->13
-	DATA_SOURCE_CALCULATE_BP                           //变频->14
-	DATA_SOURCE_GL                                     //钢联->15
-	DATA_SOURCE_ZZ                                     //郑商所->16
-	DATA_SOURCE_DL                                     //大商所->17
-	DATA_SOURCE_SH                                     //上期所->18
-	DATA_SOURCE_CFFEX                                  //中金所->19
-	DATA_SOURCE_SHFE                                   //上期能源->20
-	DATA_SOURCE_GIE                                    //欧洲天然气->21
-	DATA_SOURCE_CALCULATE_TIME_SHIFT                   //时间移位->22
-	DATA_SOURCE_CALCULATE_ZJPJ                         //直接拼接->23
-	DATA_SOURCE_CALCULATE_LJZTBPJ                      //累计值同比拼接->24
-	DATA_SOURCE_LT                                     //路透->25
-	DATA_SOURCE_COAL                                   //煤炭网->26
-	DATA_SOURCE_PYTHON                                 //python代码->27
-	DATA_SOURCE_PB_FINANCE                             //彭博财务数据->28
-	DATA_SOURCE_GOOGLE_TRAVEL                          //谷歌出行数据->29
-	DATA_SOURCE_PREDICT                                //普通预测指标->30
-	DATA_SOURCE_PREDICT_CALCULATE                      //预测指标运算->31
-	DATA_SOURCE_PREDICT_CALCULATE_TBZ                  //预测指标 - 同比值->32
-	DATA_SOURCE_PREDICT_CALCULATE_TCZ                  //预测指标 - 同差值->33
-	DATA_SOURCE_MYSTEEL_CHEMICAL                       //钢联化工->34
-	DATA_SOURCE_CALCULATE_CJJX                         //超季节性->35
-	DATA_SOURCE_EIA_STEO                               //eia steo报告->36
-	DATA_SOURCE_CALCULATE_NHCC                         //计算指标(拟合残差)->37
-	DATA_SOURCE_COM_TRADE                              //联合国商品贸易数据->38
-	DATA_SOURCE_PREDICT_CALCULATE_NSZYDPJJS            //预测指标 - N数值移动平均计算 -> 39
-	DATA_SOURCE_CALCULATE_ADJUST                       //数据调整->40
-	DATA_SOURCE_SCI                                    //卓创数据(红桃三)->41
-	DATA_SOURCE_PREDICT_CALCULATE_LJZZY                //预测指标 - 累计值转月->42
-	DATA_SOURCE_PREDICT_CALCULATE_HBZ                  //预测指标 - 环比值->43
-	DATA_SOURCE_PREDICT_CALCULATE_HCZ                  //预测指标 - 环差值->44
-	DATA_SOURCE_PREDICT_CALCULATE_BP                   //预测指标 - 变频->45
-	DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT           //预测指标 - 时间移位->46
-	DATA_SOURCE_PREDICT_CALCULATE_ZJPJ                 //预测指标 - 直接拼接->47
-	DATA_SOURCE_PREDICT_CALCULATE_LJZTBPJ              //预测指标 - 累计值同比拼接->48
-	DATA_SOURCE_PREDICT_CALCULATE_CJJX                 //预测指标 - 超季节性->49
-	DATA_SOURCE_PREDICT_CALCULATE_NHCC                 //预测指标 - 计算指标(拟合残差)->50
+	DATA_SOURCE_THS                          = iota + 1 //同花顺
+	DATA_SOURCE_WIND                                    //wind
+	DATA_SOURCE_PB                                      //彭博
+	DATA_SOURCE_CALCULATE                               //指标运算
+	DATA_SOURCE_CALCULATE_LJZZY                         //累计值转月
+	DATA_SOURCE_CALCULATE_TBZ                           //同比值
+	DATA_SOURCE_CALCULATE_TCZ                           //同差值
+	DATA_SOURCE_CALCULATE_NSZYDPJJS                     //N数值移动平均计算
+	DATA_SOURCE_MANUAL                                  //手工指标
+	DATA_SOURCE_LZ                                      //隆众
+	DATA_SOURCE_YS                                      //有色
+	DATA_SOURCE_CALCULATE_HBZ                           //环比值->12
+	DATA_SOURCE_CALCULATE_HCZ                           //环差值->13
+	DATA_SOURCE_CALCULATE_BP                            //变频->14
+	DATA_SOURCE_GL                                      //钢联->15
+	DATA_SOURCE_ZZ                                      //郑商所->16
+	DATA_SOURCE_DL                                      //大商所->17
+	DATA_SOURCE_SH                                      //上期所->18
+	DATA_SOURCE_CFFEX                                   //中金所->19
+	DATA_SOURCE_SHFE                                    //上期能源->20
+	DATA_SOURCE_GIE                                     //欧洲天然气->21
+	DATA_SOURCE_CALCULATE_TIME_SHIFT                    //时间移位->22
+	DATA_SOURCE_CALCULATE_ZJPJ                          //直接拼接->23
+	DATA_SOURCE_CALCULATE_LJZTBPJ                       //累计值同比拼接->24
+	DATA_SOURCE_LT                                      //路透->25
+	DATA_SOURCE_COAL                                    //煤炭网->26
+	DATA_SOURCE_PYTHON                                  //python代码->27
+	DATA_SOURCE_PB_FINANCE                              //彭博财务数据->28
+	DATA_SOURCE_GOOGLE_TRAVEL                           //谷歌出行数据->29
+	DATA_SOURCE_PREDICT                                 //普通预测指标->30
+	DATA_SOURCE_PREDICT_CALCULATE                       //预测指标运算->31
+	DATA_SOURCE_PREDICT_CALCULATE_TBZ                   //预测指标 - 同比值->32
+	DATA_SOURCE_PREDICT_CALCULATE_TCZ                   //预测指标 - 同差值->33
+	DATA_SOURCE_MYSTEEL_CHEMICAL                        //钢联化工->34
+	DATA_SOURCE_CALCULATE_CJJX                          //超季节性->35
+	DATA_SOURCE_EIA_STEO                                //eia steo报告->36
+	DATA_SOURCE_CALCULATE_NHCC                          //计算指标(拟合残差)->37
+	DATA_SOURCE_COM_TRADE                               //联合国商品贸易数据->38
+	DATA_SOURCE_PREDICT_CALCULATE_NSZYDPJJS             //预测指标 - N数值移动平均计算 -> 39
+	DATA_SOURCE_CALCULATE_ADJUST                        //数据调整->40
+	DATA_SOURCE_SCI                                     //卓创数据(红桃三)->41
+	DATA_SOURCE_PREDICT_CALCULATE_LJZZY                 //预测指标 - 累计值转月->42
+	DATA_SOURCE_PREDICT_CALCULATE_HBZ                   //预测指标 - 环比值->43
+	DATA_SOURCE_PREDICT_CALCULATE_HCZ                   //预测指标 - 环差值->44
+	DATA_SOURCE_PREDICT_CALCULATE_BP                    //预测指标 - 变频->45
+	DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT            //预测指标 - 时间移位->46
+	DATA_SOURCE_PREDICT_CALCULATE_ZJPJ                  //预测指标 - 直接拼接->47
+	DATA_SOURCE_PREDICT_CALCULATE_LJZTBPJ               //预测指标 - 累计值同比拼接->48
+	DATA_SOURCE_PREDICT_CALCULATE_CJJX                  //预测指标 - 超季节性->49
+	DATA_SOURCE_PREDICT_CALCULATE_NHCC                  //预测指标 - 计算指标(拟合残差)->50
 	DATA_SOURCE_CALCULATE_JP                            //降频->51
 	DATA_SOURCE_CALCULATE_NH                            //年化->52
 	DATA_SOURCE_CALCULATE_KSZS                          //扩散指数->53
@@ -86,6 +86,8 @@ const (
 	DATA_SOURCE_PREDICT_CALCULATE_NH                    //预测指标 - 计算指标(年化)->55
 	DATA_SOURCE_PREDICT_CALCULATE_KSZS                  //预测指标 - 计算指标(扩散指数)->56
 	DATA_SOURCE_BAIINFO                                 //百川盈孚 ->57
+	DATA_SOURCE_STOCK_PLANT                             //存量装置 ->58
+	DATA_SOURCE_CALCULATE_CORRELATION                   //相关性计算->59
 )
 
 // 指标来源的中文展示
@@ -146,6 +148,9 @@ const (
 	DATA_SOURCE_NAME_PREDICT_CALCULATE_JP         = `预测降频`              //预测指标 - 计算指标(降频)->54
 	DATA_SOURCE_NAME_PREDICT_CALCULATE_NH         = `预测年化`              //预测指标 - 计算指标(年化)->55
 	DATA_SOURCE_NAME_PREDICT_CALCULATE_KSZS       = `预测扩散指数`            //预测指标 - 计算指标(扩散指数)->56
+	DATA_SOURCE_NAME_BAIINFO                      = `百川盈孚`              //百川盈孚 ->57
+	DATA_SOURCE_NAME_STOCK_PLANT                  = `存量装置`              //存量装置 ->58
+	DATA_SOURCE_NAME_CALCULATE_CORRELATION        = `相关性计算`             //相关性计算->59
 )
 
 // 基础数据初始化日期