Wolfram Computation Meets Knowledge

Automotive Reliability in the Wolfram Language

This post originally appeared on Wolfram Community, where the conversation about reliable cars continues. Be sure to check out that conversation and more—we can’t wait to see what you come up with!

For the past couple of years, I’ve been playing with, collecting and analyzing data from used car auctions in my free time with an automotive journalist named Steve Lang to try and get an idea of what the used car market looks like in terms of long-term vehicle reliability. I figured it was about time that I showed off some of the ways that the Wolfram Language has allowed us to parse through information on over one million vehicles (and counting).

Vehicle Class Quality Index Rating

I’ll start off by saying that there isn’t anything terribly elaborate about the process we’re using to collect and analyze the information on these vehicles; it’s mostly a process of reading in reports from our data provider (and cleaning up the data), and then cross-referencing that data with various automotive APIs to get additional information. This data then gets dumped into a database that we use for our analysis, but having all of the tools we need built into the Wolfram Language makes the entire operation something that can be scripted—which greatly streamlines the process. I’ll have to skip over some of the details or this will be a very long post, but I’ll try to cover most of the key elements.

The data we get comes in from a third-party provider that manages used car auctions around the country (unfortunately, our licensing agreement doesn’t allow me to share the data right now), but it’s not very computable at first (the data comes in as a text file report once a week):

text = "01/02/2017 Schaumburg 128 1999 Acura CL 3.0 2D Coupe 131612 \   19UYA2256XL014922 Green A,L,R,Y          9:00 AM Illinois Announcements: Major Transmission Defect, \   Miles Exempt          01/02/2017 Hickory 33 1997 Acura CL 2.2 2D Coupe 217449 \   19UYA1255VL011890 Blue A,L,R,Y          2:00 PM North Carolina Announcements: Major Transmission Defect         01/02/2017 Ft. Bend 46 1995 Acura Integra LS 4D Sedan 98124 \   JH4DB7654SS013119 Green A,R          9:30 AM Texas Announcements: Miles Exempt          01/03/2017 Kansas City 57 1992 Acura Integra LS 4D Sedan \ 174537 \   JH4DB1653NS000122 T/A Yellow A,Y          2:00 PM Kansas Announcements: Structural Damage, Title Absent \      ";

Fortunately, parsing this sort of log-like data into individual records is easy in the Wolfram Language using basic string patterns:

vinPattern = RegularExpression["[A-Z\\d]{17}"]; recordPattern =      DatePattern[{"Month", "Day", "Year"}] ~~ __ ~~     vinPattern ~~ __ ~~        "Announcements:" ~~ __ ~~ "\n";
StringCases[text, Shortest[recordPattern]]

Then it’s mostly a matter of cleaning up the individual records into something more standardized (I’ll spare you some of the hacky details due to artifacts in the data feed). You’ll end up with something like the following:

record = <|"Date" -> "2017-01-02", "ModelYear" -> 1999,       "Make" -> "Acura", "Model" -> "CL",     "TransmissionIssue" -> True,       "EngineIssue" -> False, "Miles" -> 131612,       "VIN" -> "19UYA2256XL014922"|>;

From there, we use the handy Edmunds vehicle API to get more information on an individual vehicle using their VIN decoder:

lookupVIN[vin_String] :=   ImportString[   URLFetch["https://api.edmunds.com/api/vehicle/v2/vins/" <> vin <>      "?fmt=json&api_key=" <> apikey    ], "JSON"]

lookupVIN[vin_String] :=   ImportString[   URLFetch["https://api.edmunds.com/api/vehicle/v2/vins/" <> vin <>      "?fmt=json&api_key=" <> apikey    ], "JSON"]

We then insert the records into an HSQL database (conveniently included with Mathematica), resulting in an easy way to search for the records we want:

SQLSelect[$DataBase, $Table, {"Year", "Miles", "Transmission"},    And[SQLColumn["Make"] == "Nissan", SQLColumn["Model"] == "Cube",     SQLColumn["Year"] <= 2010]] // Short

From there, we can take a quick look at metrics using larger datasets, such as the number of transmission issues for a given set of vehicles for different model years:

Number of transmission issues

Or a histogram of those issues broken down by vehicle mileage:

Issues by vehicle mileage

It also lets us look at industry-wide trends, so we can develop a baseline for what the expected rate of defects for an average vehicle (or vehicle of a certain class) should be:

Yearly defect ratio

lm = LinearModelFit[modeldata, {date, modelyear}, {date, modelyear}]
lm = LinearModelFit[modeldata, {date, modelyear}, {date, modelyear}]

We can then compare a given vehicle to that model:

Powertrain issue rate

We then use that model, as well as other information, to generate a statistical index. We use that index to give vehicles an overall quality rating based on their historical reliability, which ranges from a score of 0 (chronic reliability issues) to 100 (exceptional reliability), with the industry average hovering right around 50:

Full-size

We also use various gauges to put together informative visualizations of defect rates and the overall quality:

MileageGauge[mileage_, opts___] := With[{color = Which[                mileage <= 100000, Lighter[Red],                100000 <= mileage <= 120000, Lighter[Yellow],                120000 <= mileage <= 130000, Lighter[Blue],                True, Lighter[Green]]},       HorizontalGauge[{mileage, $IndustryAverageMileage}, {50000,          200000},           ScalePadding -> {.08, .1},           GaugeLabels -> {                  Placed[             Style[Row[{"Model average: ",                    AccountingForm[mileage, DigitBlock -> 3],           " miles"}],                FontSize -> 20], Above],                   Placed[             Style[Row[{"Industry average: ",                              AccountingForm[$IndustryAverageMileage, DigitBlock -> 3],                    " miles"}], FontSize -> 16], Below]                  },           ScaleRanges -> {If[                    mileage < $IndustryAverageMileage, {mileage, \         \ $IndustryAverageMileage}, {$IndustryAverageMileage, mileage}]},           ScaleRangeStyle -> color, GaugeStyle -> {Darker[Red], Black},           ImageSize -> 500,          ScaleDivisions -> {7, 7},     GaugeFaceStyle -> Lighter[color, .8],           opts]       ]

announcementGauge[value_] :=     AngularGauge[value, {0, .3},        GaugeLabels -> Style[ToString[N[value, 3]*100] <> "%", 15],        PlotLabel -> Style["Transmission Issues", 15],        ScaleRanges -> {{0, $IndustryAverageIssueRates - .01} ->                 Lighter[Green], {{$IndustryAverageIssueRates - .01,                    $IndustryAverageIssueRates + .01}, {0, .2}}, \      \  {$IndustryAverageIssueRates + .01,               1.5*$IndustryAverageIssueRates} ->                       Lighter[Yellow], {1.5*$IndustryAverageIssueRates, 1} ->            Lighter[Red]},        GaugeStyle -> {RGBColor[{.15, .4, .6}], RGBColor[{.5, .5, .5}]}]

There is a lot more we do to pull all of this together (like the Wolfram Language templating we use to generate the HTML pages and reports), and honestly, there is a whole lot more we could do (my background in statistics is pretty limited, so most of this is pretty rudimentary, and I’m sure others here may already have ideas for improvements in presentation for some of this data). If you’d like to take a look at the site, it’s freely available (Steve has a nice introduction to the site here, and he also writes articles for the page related to practical uses for our findings).

Our original site was called the Long-Term Quality Index, which is still live but showed off my lack of experience in HTML development, so we recently rolled out our newer, WordPress-based venture Dashboard Light, which also includes insights from our auto journalist on his experiences running an independent, used car dealership.

This is essentially a two-man project that Steve and I handle in our (limited) free time, and we’re still getting a handle on presenting the data in a useful way, so if anyone has any suggestions or questions about our methodology, feel free to reach out to us.

Cheers!

Continue the conversation at Wolfram Community.

Comments

Join the discussion

!Please enter your comment (at least 5 characters).

!Please enter your name.

!Please enter a valid email address.

2 comments

  1. Can you post code for your yearly defect ratio plot?

    Reply
  2. I just wanted to say thanks for your hard work on this useful and interesting project. One suggestion that I have is for you to refine the analysis to include analysis by model generation. For example, I’m in the market for a gently used late model small suv and was considering the Jeep Cherokee because I like the lines, but learned there were significant power train issues in the 2014-2016 model years. I was surprised by your data showing exceptional reliability for the Cherokee, but it appears that earlier generation Cherokees were carrying the day. Well, just my two cents. Thanks again for your efforts and all the useful information provided.
    Best,
    Eric

    Reply