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()); }
public static double[] GetThresholdsForClusters(int cMAType, double[] derivatives) { Common.DoubleList minThresholdRequiredList = new Common.DoubleList(); Common.DoubleList finalMinThresholdRequiredList = new Common.DoubleList(); double?minThresholdRequired = 0; double?localMinThresholdRequired = 0; while (minThresholdRequired != null) { minThresholdRequired = null; if (derivatives.Length >= 2) { for (int j = 0; j < derivatives.Length - 1; j++) { double localThreshold = derivatives[j] > derivatives[j + 1] ? derivatives[j] : derivatives[j + 1]; if (localThreshold > localMinThresholdRequired) { if (minThresholdRequired == null) { minThresholdRequired = localThreshold; } else if (minThresholdRequired > localThreshold) { minThresholdRequired = localThreshold; } } } if (minThresholdRequired != null) { localMinThresholdRequired = minThresholdRequired; minThresholdRequiredList.Add(minThresholdRequired.GetValueOrDefault()); } } } foreach (var val in minThresholdRequiredList) { double?maxAllowedThreshold = null; switch (cMAType) { case (int)CMAType.Regular: maxAllowedThreshold = MAX_REDQ_THRESHOLD; break; case (int)CMAType.ShortSale: maxAllowedThreshold = MAX_SHORTSALE_THRESHOLD; break; case (int)CMAType.Rehab: maxAllowedThreshold = MAX_REHAB_THRESHOLD; break; } if (val <= maxAllowedThreshold) { finalMinThresholdRequiredList.Add(val); } } return(finalMinThresholdRequiredList.ToArray()); }
public DoubleList SubList(Func <double, bool> filter) { DoubleList retList = new Common.DoubleList(); foreach (var val in this) { if (filter(val)) { retList.Add(val); } } return(retList); }
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); }
private static double[] ApplyGaussianKDE(double[] pricesArray) { double minValue, maxValue; int distance; int kernelSize; Common.DoubleList localDensityPoints = new Common.DoubleList(); if (pricesArray.Length <= 1) { return(localDensityPoints.ToArray()); } minValue = pricesArray[0]; maxValue = pricesArray[pricesArray.Length - 1]; distance = Convert.ToInt32(Math.Round(maxValue - minValue) + 1); kernelSize = distance / (pricesArray.Length - 1); if (kernelSize % 2 == 0) { kernelSize += 1; } double[] SampleArray = new double[distance]; for (int i = 0; i < distance; i++) { SampleArray[i] = 0; } for (int j = 0; j < pricesArray.Length; j++) { int samplePoint = Convert.ToInt32(pricesArray[j] - minValue); SampleArray[samplePoint] += 1000; } double[] densityArray = Common.Statistics.ApplyGaussianKDEV2(SampleArray, kernelSize, GAUSSIAN_SIGMA); double?localMaxima = 0; int? direction = null; for (int i = 0; i < distance; i++) { if (localMaxima == null) { localMaxima = densityArray[i]; } else if (densityArray[i] >= localMaxima) { direction = 1; localMaxima = densityArray[i]; } else { if (direction == 1) { localDensityPoints.Add(i + minValue); } direction = 0; localMaxima = densityArray[i]; } } return(localDensityPoints.ToArray()); }