# Finding Abnormally Low Ticket Prices

I'm creating a program where my goal is to analyse lists of ticket prices and locate tickets that are priced abnormally low in relation to the spread of prices.

My preliminary model does the following to the price list in this order..(examples are at the end of my writeup - they include the modifications made after running through the model)

1. Removes any tickets that are priced over 999.00 . Sometimes tickets will be priced intentionally at 9999.99 to ensure they do not sell - so i don't want to use them in my calculations.
2. Removes any tickets that are priced 1.5 standard deviations above the new mean. I found that unrealistically high priced tickets were unnecessarily influencing the mean.
3. Recalculates the mean and SD and pulls tickets that are 2.9 standard deviations BELOW the mean (I'm calling this the "Price Floor".

This results in some success, however it also produces Price Floors that are negative in some cases.

I would like to improve my model to be able to take any price list and develop "Price Floors" that are more realistic.

My questions are:

1. Am I going down the right path with my current model?
2. Would you change any aspects of my current model?
3. Are there other methods available that may be more effective than standard deviation?

Below are two samples of the data I'm working with using the model I described above. In Set 1, the Price Floor is 36.48, thus producing one result of 36.1.

In Set 2, the Price Floor is -3.45. While I would not expect a result from Set 2, I feel that my model is inadequate due to the unrealistic Price Floor.

Set 1 (Price Floor: 36.48)

 => 36.1
 => 41.6
 => 43.8
 => 44.9
 => 45
 => 46
 => 46
 => 46
 => 46
 => 46
 => 48.2
 => 49.03
 => 49.3
 => 49.3
 => 49.3
 => 50.4
 => 51.5
 => 51.5
 => 51.5
 => 51.5
 => 51.5
 => 52.05
 => 52.47
 => 52.6
 => 52.6
 => 52.6
 => 52.6
 => 52.6
 => 52.6
 => 53.7
 => 53.7
 => 53.7
 => 53.7
 => 53.7
 => 53.7
 => 54.8
 => 54.8
 => 54.8
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 57
 => 57
 => 57
 => 57
 => 57
 => 57
 => 59.2
 => 59.2
 => 59.2
 => 59.2
 => 59.2
 => 60.3
 => 61.4
 => 62.5
 => 64
 => 64.15
 => 64.15
 => 64.15
 => 65
 => 65
 => 66
 => 67.45
 => 67.45


Set 2 (Price Floor -3.45)

 => 46
 => 58.1
 => 58.38
 => 59.2
 => 61.4
 => 62.5
 => 64.7
 => 65.25
 => 65.25
 => 65.25
 => 65.25
 => 66.35
 => 66.9
 => 67.99
 => 67.99
 => 67.99
 => 67.99
 => 67.99
 => 68.55
 => 70.2
 => 71.85
 => 71.85
 => 72.4
 => 72.4
 => 73.5
 => 73.5
 => 73.5
 => 74.83
 => 75.7
 => 79
 => 79
 => 79.55
 => 80.1
 => 84.5
 => 84.5
 => 84.5
 => 85.05
 => 87.8
 => 89.45
 => 93.3
 => 95.5
 => 97.15
 => 98.76
 => 98.8
 => 99.66
 => 106.5
 => 108.7
 => 112
 => 112
 => 119.15
 => 119.15
 => 122.45
 => 123
 => 124.65
 => 125.75
 => 125.75
 => 128.5
 => 128.5
 => 133.45
 => 134
 => 135.65
 => 136.2
 => 139.5
 => 139.5
 => 139.5
 => 140.6
 => 149.95
 => 150.5
 => 154.9
 => 160.4
 => 161.5
 => 164.25
 => 164.8
 => 165.9
 => 167
 => 167
 => 167
 => 167.55
 => 169.75
 => 171.4
 => 172.5

• can you edit you question to only leave the numbers (no [#], no arrows). – user603 May 21 '13 at 7:56
• @user603 See my answer below for cut-and-paste code fragment to read in his data. – Bill May 21 '13 at 16:25
• Sorry for the formatting issues.. Thank you so much for your responses.. I'm far from fluent with stats and this is a huge help. I'm on the road right now and will take a closer look later today. – rizzle May 21 '13 at 19:27

You are worried about outliers (values that are "too high" or "too low") affecting the mean and standard deviation of ticket prices. This is a very reasonable worry, and there are statistical tools to deal with it. The tools go by the name of "robust statistics."

In your case, I would make three suggestions. First, instead of using the mean, use the median. It can't be moved around (much) by crazy high and crazy low values. Second, instead of using standard deviations to define your price floors, use percentiles. Third, don't manually throw away data: let the robust methods ignore the crazy outliers for you.

Maybe put your price floor at the 5th percentile. In set 1, that would make the price floor around 45. In set 2, that would make the price floor around 61.

R code, including code to read in inconveniently formatted data:

> # R script out of order.  Code to read in data is below
> library(stringr)
> summary(dataset1)
Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
36.10   51.50   54.80   54.52   57.00   67.45
> quantile(dataset1,c(0.05,0.50,0.95))
5%    50%    95%
44.955 54.800 65.000
> summary(dataset2)
Min. 1st Qu.  Median    Mean 3rd Qu.    Max.
46.00   71.85   95.50  104.50  135.60  172.50
> quantile(dataset2,c(0.05,0.50,0.95))
5%   50%   95%
61.4  95.5 167.0

# Code to read in inconveniently formatted data
set1 <- " => 36.1
 => 41.6
 => 43.8
 => 44.9
 => 45
 => 46
 => 46
 => 46
 => 46
 => 46
 => 48.2
 => 49.03
 => 49.3
 => 49.3
 => 49.3
 => 50.4
 => 51.5
 => 51.5
 => 51.5
 => 51.5
 => 51.5
 => 52.05
 => 52.47
 => 52.6
 => 52.6
 => 52.6
 => 52.6
 => 52.6
 => 52.6
 => 53.7
 => 53.7
 => 53.7
 => 53.7
 => 53.7
 => 53.7
 => 54.8
 => 54.8
 => 54.8
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 55.9
 => 57
 => 57
 => 57
 => 57
 => 57
 => 57
 => 59.2
 => 59.2
 => 59.2
 => 59.2
 => 59.2
 => 60.3
 => 61.4
 => 62.5
 => 64
 => 64.15
 => 64.15
 => 64.15
 => 65
 => 65
 => 66
 => 67.45
 => 67.45"

set2 <- " => 46
 => 58.1
 => 58.38
 => 59.2
 => 61.4
 => 62.5
 => 64.7
 => 65.25
 => 65.25
 => 65.25
 => 65.25
 => 66.35
 => 66.9
 => 67.99
 => 67.99
 => 67.99
 => 67.99
 => 67.99
 => 68.55
 => 70.2
 => 71.85
 => 71.85
 => 72.4
 => 72.4
 => 73.5
 => 73.5
 => 73.5
 => 74.83
 => 75.7
 => 79
 => 79
 => 79.55
 => 80.1
 => 84.5
 => 84.5
 => 84.5
 => 85.05
 => 87.8
 => 89.45
 => 93.3
 => 95.5
 => 97.15
 => 98.76
 => 98.8
 => 99.66
 => 106.5
 => 108.7
 => 112
 => 112
 => 119.15
 => 119.15
 => 122.45
 => 123
 => 124.65
 => 125.75
 => 125.75
 => 128.5
 => 128.5
 => 133.45
 => 134
 => 135.65
 => 136.2
 => 139.5
 => 139.5
 => 139.5
 => 140.6
 => 149.95
 => 150.5
 => 154.9
 => 160.4
 => 161.5
 => 164.25
 => 164.8
 => 165.9
 => 167
 => 167
 => 167
 => 167.55
 => 169.75
 => 171.4
 => 172.5"

parse.set1 <- str_match(readLines(tc<-textConnection(set1)),"[[:digit:]\\.]+$") dataset1 <- as.numeric(parse.set1[,1]) parse.set2 <- str_match(readLines(tc<-textConnection(set2)),"[[:digit:]\\.]+$")
dataset2 <- as.numeric(parse.set2[,1])

• (+1). Also, the boxplot indicates that prices below 44 (first dataset) and 46 (second dataset) are suspiciously far from the main body of the data. Same for prices above 65 (dataset1) and 172 (dataset2). – user603 May 21 '13 at 16:52
• Using the median and something based on percentiles sound like good ideas but setting the threshold directly at some low percentile assumes that a fixed proportions of prices is abnormal in each sample. Why would it be the case? The boxplot approach (x times the interquartile range) would avoid this problem. – Gala May 21 '13 at 16:59
• @GaëlLaurans I agree with you and user603. The boxplot is a better approach than just using the 5th percentile. – Bill May 21 '13 at 21:43