private static double[] MapDensityPointsToDiscretePrices(double[] densityPoints, double[] pricesArray) { Common.DoubleList newList = new Common.DoubleList(); for (int i = 0; i < densityPoints.Length; i++) { for (int j = 0; j < pricesArray.Length; j++) { if (pricesArray[j] <= densityPoints[i] && pricesArray[j + 1] >= densityPoints[i]) { if (densityPoints[i] - pricesArray[j] > pricesArray[j + 1] - densityPoints[i]) { newList.Add(pricesArray[j + 1]); } else { newList.Add(pricesArray[j]); } break; } } } newList.Sort(); return(newList.ToArray()); }
private static DAL.AutomatedSuggestedPropertyPrices getSuggestedPropertyPrices(int cMAType, string subjectBBL, List <DAL.CMAResult> results) { DAL.AutomatedSuggestedPropertyPrices price = new DAL.AutomatedSuggestedPropertyPrices(); price.SubjectBBL = subjectBBL; var subject = DAL.CMA.GetSubject(subjectBBL); if (subject == null) { price.message = "Error locating Subject Information"; return(price); } double?GLA = subject.GLA.GetValueOrDefault(); if (GLA == null || GLA == 0) { price.message = "GLA is null or zero for Subject"; return(price); } if (results.Count == 0) { price.message = "No Comparables found"; return(price); } Common.DoubleList pricessqft = new Common.DoubleList(); foreach (var comp in results) { pricessqft.Add(Math.Round(comp.DeedAmount.GetValueOrDefault() / comp.GLA.GetValueOrDefault(), 0)); } pricessqft.Sort(); double medianPrice = Common.Statistics.Percentile(pricessqft, 50); double[] pricesArray = pricessqft.ToArray(); //Round Prices for (int j = 0; j < pricesArray.Length; j++) { pricesArray[j] = Math.Round(pricesArray[j], 0); } //What is the minimum threshold required to get a cluster from our comparables // double[] derivatives = GetSimplePriceDerivates(pricesArray); // double[] minThresholds = GetThresholdsForClusters(cMAType, derivatives); //KDE Approach double[] kDEDensityPoints = ApplyGaussianKDE(pricesArray); double[] modifiedDerivatives = GetModifiedPriceDerivatesUsingKDEDensityPoints(pricesArray, kDEDensityPoints); double[] minKDEThresholds = GetThresholdsForClusters(cMAType, modifiedDerivatives); if (minKDEThresholds.Length < 1) { price.message = "No price clusters can be established based on threshold percentages defined."; return(price); } //Using minThresholds find clusters in comparables with KDE points //List<KDECluster> clusters = FindClustersWithKDE(cMAType, kDEDensityPoints, minThresholds, pricesArray); List <KDECluster> clusters = FindClustersWithKDE(cMAType, kDEDensityPoints, minKDEThresholds, pricesArray); //Using minThresholds find clusters in comparables Old Approach //Clusters clusterInfo = FindClusters(cMAType, derivatives, minThresholds); //Select the appropriate cluster based on CMAType price derivatives approach //ClusterSelection clusterSelection = SelectCluster(cMAType, clusterInfo); // ClusterSelection clusterSelectionKDE = SelectCluster(cMAType, clusters, medianPrice); ClusterSelection clusterSelectionKDE = SelectCluster(cMAType, clusters, medianPrice); //mix and max values from the cluster double?minClusterValue = null, maxClusterValue = null; if (clusterSelectionKDE.kDEcluster != null) { minClusterValue = clusterSelectionKDE.kDEcluster.minValue; maxClusterValue = clusterSelectionKDE.kDEcluster.maxValue; } /* * else if (clusterSelection.clusterValue != -1) //old Approach * { * minClusterValue = Math.Round(pricesArray[clusterInfo.clusters[clusterSelection.clusterValue]],0); * maxClusterValue = Math.Round(pricesArray[clusterInfo.clusters[clusterSelection.clusterValue] + 1],0); * int i = clusterInfo.clusters[clusterSelection.clusterValue] + 1; * while (i < derivatives.Length) * { * if (derivatives[i] <= clusterInfo.minThresholdRequired.GetValueOrDefault()) * maxClusterValue = Math.Round(pricesArray[i + 1],0); * else * break; * i++; * } * price.message = clusterSelection.message; * } */ //use min max values to compute subject price if (minClusterValue != null && maxClusterValue != null) { price.SubjectBBL = subjectBBL; price.minClusterValue = minClusterValue; price.maxClusterValue = maxClusterValue; price.LowPrice = Math.Round(pricessqft.Min(x => x >= minClusterValue && x <= maxClusterValue) * GLA.GetValueOrDefault(), 0); price.AVGPrice = Math.Round(pricessqft.Average(x => x >= minClusterValue && x <= maxClusterValue) * GLA.GetValueOrDefault(), 0); price.MedianPrice = Math.Round(Common.Statistics.Percentile(pricessqft.SubList(x => x >= minClusterValue && x <= maxClusterValue), 50) * GLA.GetValueOrDefault(), 0); price.HighPrice = Math.Round(pricessqft.Max(x => x >= minClusterValue && x <= maxClusterValue) * GLA.GetValueOrDefault(), 0); } else { price.SubjectBBL = subjectBBL; price.message = clusterSelectionKDE.message; } return(price); }