edb_info_calculate.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. package data
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "eta_gn/eta_api/models/data_manage"
  6. "eta_gn/eta_api/utils"
  7. "fmt"
  8. "github.com/shopspring/decimal"
  9. "math"
  10. "sort"
  11. "strings"
  12. "time"
  13. )
  14. func CheckFormula(formula string) map[string]string {
  15. mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN", "EXP"}
  16. str := strings.ToUpper(formula)
  17. for _, v := range mathFormula {
  18. str = strings.Replace(str, v, "", -1)
  19. }
  20. str = strings.Replace(str, "(", "", -1)
  21. str = strings.Replace(str, ")", "", -1)
  22. byteMap := make(map[string]string)
  23. for i := 0; i < len(str); i++ {
  24. byteInt := str[i]
  25. if byteInt >= 65 && byteInt <= 90 {
  26. byteStr := string(byteInt)
  27. if _, ok := byteMap[byteStr]; !ok {
  28. byteMap[byteStr] = byteStr
  29. }
  30. }
  31. }
  32. return byteMap
  33. }
  34. type FormulaListItem struct {
  35. Formula string `json:"f"`
  36. Date string `json:"d"`
  37. }
  38. func CheckFormulaJson(formula string) (formulaSlice []string, err error) {
  39. list := make([]FormulaListItem, 0)
  40. err = json.Unmarshal([]byte(formula), &list)
  41. if err != nil {
  42. err = fmt.Errorf("公式串解析失败: json.Unmarshal Err: %v", err)
  43. return
  44. }
  45. formulaSlice = make([]string, 0)
  46. for _, v := range list {
  47. formulaSlice = append(formulaSlice, v.Formula)
  48. }
  49. return
  50. }
  51. type CalculateItems struct {
  52. EdbInfoId int
  53. DataMap map[string]float64
  54. }
  55. func handleDataByLinearRegression(edbInfoDataList []*data_manage.EdbDataList, handleDataMap map[string]float64) (err error) {
  56. if len(edbInfoDataList) < 2 {
  57. return
  58. }
  59. var startEdbInfoData *data_manage.EdbDataList
  60. for _, v := range edbInfoDataList {
  61. handleDataMap[v.DataTime] = v.Value
  62. if startEdbInfoData == nil {
  63. startEdbInfoData = v
  64. continue
  65. }
  66. startDataTime, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
  67. currDataTime, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
  68. betweenHour := int(currDataTime.Sub(startDataTime).Hours())
  69. betweenDay := betweenHour / 24
  70. if betweenDay <= 1 {
  71. startEdbInfoData = v
  72. continue
  73. }
  74. var a, b float64
  75. {
  76. coordinateData := make([]utils.Coordinate, 0)
  77. tmpCoordinate1 := utils.Coordinate{
  78. X: 1,
  79. Y: startEdbInfoData.Value,
  80. }
  81. coordinateData = append(coordinateData, tmpCoordinate1)
  82. tmpCoordinate2 := utils.Coordinate{
  83. X: float64(betweenDay) + 1,
  84. Y: v.Value,
  85. }
  86. coordinateData = append(coordinateData, tmpCoordinate2)
  87. a, b = utils.GetLinearResult(coordinateData)
  88. if math.IsNaN(a) || math.IsNaN(b) {
  89. err = errors.New("线性方程公式生成失败")
  90. return
  91. }
  92. }
  93. {
  94. for i := 1; i < betweenDay; i++ {
  95. tmpDataTime := startDataTime.AddDate(0, 0, i)
  96. aDecimal := decimal.NewFromFloat(a)
  97. xDecimal := decimal.NewFromInt(int64(i) + 1)
  98. bDecimal := decimal.NewFromFloat(b)
  99. val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
  100. handleDataMap[tmpDataTime.Format(utils.FormatDate)] = val
  101. }
  102. }
  103. startEdbInfoData = v
  104. }
  105. return
  106. }
  107. func HandleDataByLinearRegression(edbInfoDataList []*data_manage.EdbDataList, handleDataMap map[string]float64) (err error) {
  108. return handleDataByLinearRegression(edbInfoDataList, handleDataMap)
  109. }
  110. func CallCalculateComputeCorrelation(data *data_manage.EdbInfoCalculateBatchSaveReqByEdbLib, lang string) (val string, err error, errMsg string) {
  111. errMsg = "计算失败"
  112. reqJson, err := json.Marshal(data)
  113. if err != nil {
  114. errMsg = "计算相关系数参数解析异常!"
  115. err = errors.New("参数解析失败,Err:" + err.Error())
  116. return
  117. }
  118. respItem, err := CalculateComputeCorrelation(string(reqJson), lang)
  119. if err != nil {
  120. return
  121. }
  122. if respItem.Ret == 200 {
  123. val = respItem.Data
  124. }
  125. return
  126. }
  127. func HandleDataByLinearRegressionToList(edbInfoDataList []*data_manage.EdbDataList, handleDataMap map[string]float64) (dataTimeList []string, valueList []float64, err error) {
  128. if len(edbInfoDataList) < 2 {
  129. return
  130. }
  131. var startEdbInfoData *data_manage.EdbDataList
  132. for _, v := range edbInfoDataList {
  133. handleDataMap[v.DataTime] = v.Value
  134. dataTimeList = append(dataTimeList, v.DataTime)
  135. if startEdbInfoData == nil {
  136. startEdbInfoData = v
  137. continue
  138. }
  139. startDataTime, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
  140. currDataTime, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
  141. betweenHour := int(currDataTime.Sub(startDataTime).Hours())
  142. betweenDay := betweenHour / 24
  143. if betweenDay <= 1 {
  144. startEdbInfoData = v
  145. continue
  146. }
  147. var a, b float64
  148. {
  149. coordinateData := make([]utils.Coordinate, 0)
  150. tmpCoordinate1 := utils.Coordinate{
  151. X: 1,
  152. Y: startEdbInfoData.Value,
  153. }
  154. coordinateData = append(coordinateData, tmpCoordinate1)
  155. tmpCoordinate2 := utils.Coordinate{
  156. X: float64(betweenDay) + 1,
  157. Y: v.Value,
  158. }
  159. coordinateData = append(coordinateData, tmpCoordinate2)
  160. a, b = utils.GetLinearResult(coordinateData)
  161. if math.IsNaN(a) || math.IsNaN(b) {
  162. err = errors.New("线性方程公式生成失败")
  163. return
  164. }
  165. }
  166. {
  167. for i := 1; i < betweenDay; i++ {
  168. tmpDataTime := startDataTime.AddDate(0, 0, i)
  169. aDecimal := decimal.NewFromFloat(a)
  170. xDecimal := decimal.NewFromInt(int64(i) + 1)
  171. bDecimal := decimal.NewFromFloat(b)
  172. val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
  173. handleDataMap[tmpDataTime.Format(utils.FormatDate)] = val
  174. dataTimeList = append(dataTimeList, tmpDataTime.Format(utils.FormatDate))
  175. valueList = append(valueList, val)
  176. }
  177. }
  178. startEdbInfoData = v
  179. }
  180. return
  181. }
  182. func HandleDataByLinearRegressionToListV2(edbInfoDataList []*data_manage.EdbDataList, handleDataMap map[string]float64) (dataTimeList []string, valueList []float64, err error) {
  183. if len(edbInfoDataList) < 2 {
  184. return
  185. }
  186. if len(edbInfoDataList) < 2 {
  187. err = errors.New("至少需要两天的数据来执行线性插值")
  188. return
  189. }
  190. sort.Slice(edbInfoDataList, func(i, j int) bool {
  191. t1, _ := time.ParseInLocation(utils.FormatDate, edbInfoDataList[i].DataTime, time.Local)
  192. t2, _ := time.ParseInLocation(utils.FormatDate, edbInfoDataList[j].DataTime, time.Local)
  193. return t1.Before(t2)
  194. })
  195. startEdbInfoData := edbInfoDataList[0]
  196. endEdbInfoData := edbInfoDataList[len(edbInfoDataList)-1]
  197. startDate, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
  198. endDate, _ := time.ParseInLocation(utils.FormatDate, endEdbInfoData.DataTime, time.Local)
  199. actualDays := endDate.Sub(startDate).Hours() / 24
  200. for _, v := range edbInfoDataList {
  201. handleDataMap[v.DataTime] = v.Value
  202. dataTimeList = append(dataTimeList, v.DataTime)
  203. valueList = append(valueList, v.Value)
  204. }
  205. if actualDays < 365 {
  206. var a, b float64
  207. coordinateData := []utils.Coordinate{
  208. {X: 1, Y: startEdbInfoData.Value},
  209. {X: float64(len(edbInfoDataList)), Y: endEdbInfoData.Value},
  210. }
  211. a, b = utils.GetLinearResult(coordinateData)
  212. if math.IsNaN(a) || math.IsNaN(b) {
  213. err = errors.New("线性方程公式生成失败")
  214. return
  215. }
  216. for i := 1; i < 365; i++ {
  217. day := startDate.AddDate(0, 0, i)
  218. if _, exists := handleDataMap[day.Format(utils.FormatDate)]; !exists {
  219. aDecimal := decimal.NewFromFloat(a)
  220. xDecimal := decimal.NewFromInt(int64(i) + 1)
  221. bDecimal := decimal.NewFromFloat(b)
  222. val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
  223. handleDataMap[day.Format(utils.FormatDate)] = val
  224. dataTimeList = append(dataTimeList, day.Format(utils.FormatDate))
  225. valueList = append(valueList, val)
  226. }
  227. }
  228. }
  229. return
  230. }
  231. func HandleDataByLinearRegressionToListV3(edbInfoDataList []*data_manage.EdbDataList, handleDataMap map[string]float64) (newEdbInfoDataList []*data_manage.EdbDataList, dataTimeList []string, valueList []float64, err error) {
  232. if len(edbInfoDataList) < 2 {
  233. return
  234. }
  235. var startEdbInfoData *data_manage.EdbDataList
  236. for _, v := range edbInfoDataList {
  237. handleDataMap[v.DataTime] = v.Value
  238. newEdbInfoDataList = append(newEdbInfoDataList, v)
  239. dataTimeList = append(dataTimeList, v.DataTime)
  240. if startEdbInfoData == nil {
  241. startEdbInfoData = v
  242. continue
  243. }
  244. startDataTime, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
  245. currDataTime, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
  246. betweenHour := int(currDataTime.Sub(startDataTime).Hours())
  247. betweenDay := betweenHour / 24
  248. if betweenDay <= 1 {
  249. startEdbInfoData = v
  250. continue
  251. }
  252. var a, b float64
  253. {
  254. coordinateData := make([]utils.Coordinate, 0)
  255. tmpCoordinate1 := utils.Coordinate{
  256. X: 1,
  257. Y: startEdbInfoData.Value,
  258. }
  259. coordinateData = append(coordinateData, tmpCoordinate1)
  260. tmpCoordinate2 := utils.Coordinate{
  261. X: float64(betweenDay) + 1,
  262. Y: v.Value,
  263. }
  264. coordinateData = append(coordinateData, tmpCoordinate2)
  265. a, b = utils.GetLinearResult(coordinateData)
  266. if math.IsNaN(a) || math.IsNaN(b) {
  267. err = errors.New("线性方程公式生成失败")
  268. return
  269. }
  270. }
  271. {
  272. for i := 1; i < betweenDay; i++ {
  273. tmpDataTime := startDataTime.AddDate(0, 0, i)
  274. aDecimal := decimal.NewFromFloat(a)
  275. xDecimal := decimal.NewFromInt(int64(i) + 1)
  276. bDecimal := decimal.NewFromFloat(b)
  277. val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
  278. handleDataMap[tmpDataTime.Format(utils.FormatDate)] = val
  279. dataTimeList = append(dataTimeList, tmpDataTime.Format(utils.FormatDate))
  280. valueList = append(valueList, val)
  281. newEdbInfoDataList = append(newEdbInfoDataList, &data_manage.EdbDataList{
  282. EdbDataId: v.EdbDataId,
  283. EdbInfoId: v.EdbInfoId,
  284. DataTime: tmpDataTime.Format(utils.FormatDate),
  285. DataTimestamp: tmpDataTime.UnixNano() / 1e6,
  286. Value: val,
  287. })
  288. }
  289. }
  290. startEdbInfoData = v
  291. }
  292. return
  293. }