public
Created

R for car search

  • Download Gist
carsearch.R
R
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
#
# Get appraised value of car from Edmunds.com using the developer API with R
# Reference: http://developer.edmunds.com/docs/read/The_Vehicle_API
#
 
# set working dir
setwd('~/R/carvalue')
 
#load libraries
library(RJSONIO)
library(ggplot2)
library(plyr)
 
# get all makes
APIkey="YourAPIkey"
# get the URL that gets the JSON file
resURL=paste("https://api.edmunds.com/api/vehicle/v2/makes?fmt=json&api_key=",
APIkey,sep="")
# convert JSON to a list
makesJSON=fromJSON(resURL)
# get make names
makes=sapply(makesJSON$makes,function(x) x$niceName)
makes
 
# get makes and models
makeslist=sapply(makesJSON$makes,function(x) rep(x$niceName,length(x$models)))
modelslist=sapply(makesJSON$makes,function(x) sapply(x$models,function(y) y$id))
modelslist2=sapply(makesJSON$makes,function(x) sapply(x$models,function(y) y$niceName))
makesModels=data.frame(make=unlist(makeslist),modelname=unlist(modelslist),
model=unlist(modelslist2))
head(makesModels)
 
# models for toyota
makesModels[makesModels$make == "toyota",]
# models for chrysler
makesModels[makesModels$make == "chrysler",]
 
# function to get a list of styles for make->model->year
 
stylefn=function(pickmake,pickmodel,pickyr){
# URL to extract JSON file
resURL=paste("https://api.edmunds.com/api/vehicle/v2/",
pickmake,"/",pickmodel,"/",pickyr,"?fmt=json&api_key=",
APIkey,sep="")
# convert JSON to list
stylesJSON=fromJSON(resURL)
# extract style info from the list into a dataframe
styles=sapply(stylesJSON$styles,function(x) c(x$id,x$name,x$trim))
styles=data.frame(t(styles),stringsAsFactors=FALSE)
names(styles)=c("styleid","stylename","trim")
styles$make=pickmake
styles$model=pickmodel
styles$year=pickyr
return(styles)
}
 
# test stylefn
pickmake="toyota"
pickmodel="corolla"
pickyr=2010
test=stylefn(pickmake,pickmodel,pickyr)
 
# pick make and model
pickmake="toyota"
pickmodel="corolla"
# get list of styles for a given set of years for a given model->make
yrlist=c(2008,2009,2010,2011,2012,2013)
stylelist=lapply(yrlist,function(x) stylefn(pickmake,pickmodel,x))
styledf=do.call(rbind,stylelist)
 
# function to get tmv for a style with typically equipped vehicle
valfn=function(pickstyleid,pickzip){
 
# URL to extract JSON file
resURL=paste("http://api.edmunds.com/v1/api/tmv/tmvservice/calculatetypicallyequippedusedtmv?styleid=",
pickstyleid,
"&zip=",pickzip,"&api_key=",APIkey,"&fmt=json",sep="")
tmv=fromJSON(resURL)
# market value (retail, private party and trade-in)
tmv=c(tmvretail=tmv$tmv$totalWithOptions$usedTmvRetail,
tmvpp=tmv$tmv$totalWithOptions$usedPrivateParty,
tmvtradein=tmv$tmv$totalWithOptions$usedTradeIn)
return(tmv)
}
 
# test valfn
pickstyleid="101209943"
pickzip="60201"
test=valfn(pickstyleid,pickzip)
 
# get tmv for a style with typically equipped vehicle for a list of styles
pickzip="60201"
tmvlist=lapply(styledf$styleid,function(x) valfn(x,pickzip))
tmvdf=do.call(rbind,tmvlist)
tmvdf=cbind(styledf,tmvdf)
# remove records with zero tmvretail value
tmvdf=tmvdf[tmvdf$tmvretail > 0,]
 
 
# summarize by year and trim
tmvdfS1=ddply(tmvdf,c("year","trim"),summarize,tmvmin=min(tmvretail),tmvmax=max(tmvretail))
# plot TMV by year and trim
 
# y range for plot
ymin=round(min(tmvdfS1$tmvmin),-3)-500
ymax=round(max(tmvdfS1$tmvmax),-3)+1500
 
ggplot(data=tmvdfS1,aes(x=factor(year),y=tmvmin,color=trim))+
geom_crossbar(aes(ymin=tmvmin,ymax=tmvmax,fill=trim,width=0.4),position="dodge")+
scale_y_continuous(breaks=seq(ymin,ymax,1000))+
xlab("")+ylab("True Market Value (Retail) ($)")+theme_bw(20)
 
 
 
 
# function to get tmv for options, condition, mileage for a style
valoptfn=function(pickstyleid,pickzip,pickmiles,pickcondition,pickoption){
resURL=paste("http://api.edmunds.com/v1/api/tmv/tmvservice/calculateusedtmv?styleid=",
pickstyleid,"&condition=",pickcondition,"&mileage=",pickmiles,
"&zip=",pickzip,"&api_key=",APIkey,
"&optionid=",pickoption,
"&fmt=json",sep="")
tmv=fromJSON(resURL)
# TMV for options
tmvopt=c(tmvretail=tmv$tmv$optionTMVPrices[[1]]$usedTmvRetail,
tmvpp=tmv$tmv$optionTMVPrices[[1]]$usedPrivateParty,
tmvtradein=tmv$tmv$optionTMVPrices[[1]]$usedTradeIn)
# TMV for condition adjustment
tmvcond=c(tmvretail=tmv$tmv$conditionAdjustment$usedTmvRetail,
tmvpp=tmv$tmv$conditionAdjustment$usedPrivateParty,
tmvtradein=tmv$tmv$conditionAdjustment$usedTradeIn)
# TMV for mileage adjustment
tmvmiles=c(tmvretail=tmv$tmv$mileageAdjustment$usedTmvRetail,
tmvpp=tmv$tmv$mileageAdjustment$usedPrivateParty,
tmvtradein=tmv$tmv$mileageAdjustment$usedTradeIn)
# TMV with all options
tmvtot=c(tmvretail=tmv$tmv$totalWithOptions$usedTmvRetail,
tmvpp=tmv$tmv$totalWithOptions$usedPrivateParty,
tmvtradein=tmv$tmv$totalWithOptions$usedTradeIn)
return(list(tmvopt=tmvopt,tmvcond=tmvcond,tmvmiles=tmvmiles,
tmvtot=tmvtot))
}
 
# get a list of options for a given style
 
# styleid for Toyota Corolla LE 4dr Sedan (1.8L 4cyl 4A) year 2008
pickstyleid="100884950"
 
resURL=paste("http://api.edmunds.com/v1/api/vehicle-directory-ajax/vehicle-options/options?styleId=",
pickstyleid,"&fmt=json&api_key=",
APIkey,sep="")
optionsJSON=fromJSON(resURL)
options=sapply(optionsJSON,function(x) c(x["optionId"],x["optionDescription"]))
options=data.frame(t(options))
head(options)
 
# test valoptfn
pickzip="60201"
pickmiles="120000"
pickcondition="clean"
pickoption="TMVU1008849501501000083"
test=valoptfn(pickstyleid,pickzip,pickmiles,pickcondition,pickoption)
 
# find adjsment for options, condition and miles
 
# find adjustment for options
adjopt=apply(options,1,function(x) valoptfn(pickstyleid,pickzip,"40000",
"clean",x["optionId"])$tmvopt)
adjopt2=cbind(options,t(adjopt))
# plot option adjustment
ggplot(adjopt2,aes(x=reorder(optionDescription,tmvretail),y=tmvretail))+
xlab("")+ylab("Adjustment for an option ($)")+
geom_bar(stat="identity")+coord_flip()+theme_bw()
 
# find adjustment for condition
condlist=data.frame(condition=c("Rough","Average","Clean","Outstanding"))
adjcond=apply(condlist,1,function(x) valoptfn(pickstyleid,pickzip,"40000",x,options$optionId[1])$tmvcond)
adjcond2=cbind(condlist,t(adjcond))
# plot condition adjustment
ggplot(adjcond2,aes(x=reorder(condition,tmvretail),y=tmvretail))+
xlab("")+ylab("Adjustment for condition ($)")+
geom_bar(stat="identity")+coord_flip()+theme_bw(20)
 
# find adjustment by mileage
milelist=data.frame(miles=seq(10000,90000,by=10000))
#milelist=data.frame(miles=c(90000,110000,120000))
adjmiles=apply(milelist,1,function(x) valoptfn(pickstyleid,pickzip,x,"clean",options$optionId[1])$tmvmiles)
adjmiles2=cbind(milelist,t(adjmiles))
# plot mileage adjustment
ggplot(adjmiles2,aes(x=miles,y=tmvretail))+geom_line()+
xlab("Miles")+ylab("Mileage Adjustment ($)")+
scale_x_continuous(breaks=seq(10000,90000,by=10000))+
scale_y_continuous(breaks=seq(-1000,1000,200))+theme_bw(20)

great post! Thanks for showing me around the edmunds API, buying a used car will never be the same (for the salesperson...hehe).

Do you know of a way to put pause in between requests? For example, lines 68, 69 use lapply to quickly bring back single years of car styles then line 70 binds them together. I'm hitting up against a rate limit on the API (2 requests/second) if I have more than a few years.

More broadly, is there a way to slow down requests to an api?

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.