Skip to content

Instantly share code, notes, and snippets.

@wllmtrng
Last active September 5, 2016 19:13
Show Gist options
  • Save wllmtrng/ff72bf455078448e5e40ece3bff15354 to your computer and use it in GitHub Desktop.
Save wllmtrng/ff72bf455078448e5e40ece3bff15354 to your computer and use it in GitHub Desktop.
Prosper Score Distribution

View at http://bl.ocks.org/wllmtrng/ff72bf455078448e5e40ece3bff15354

Design

The Prosper Marketplace provides an alternative avenue for people to invest and borrow money. When a potential borrower fills out an application, a Prosper Score from 1 to 11 is assigned. Lending to an individual of a lower score will have a better return on investment, but also have increased chances of defaulting. Lending to an individual of a higher score will have a lower chance of defaulting, but a lower return on investment.

Quite often, investors use historical data and group past borrowers by certain criteria to compare against potential borrowers of similar criteria. One criteria used often is Occupations. Potential borrowers with Occupations that have a higher Prosper Score on average can be generally more credit worthy.

Initially I chose to use this dashboard type of visualization because:

  1. Bar plots are useful in showing the difference in frequency among the Prosper Scores.
  2. The Pie Chart and Legend on the right is able to provide secondary distribution of Occupation for a selected Prosper Score.
  3. The Pie Chart can show drastic differences between the distribution of Occupation for a certain Prosper Score.
  4. The Legend complements the Pie Chart by showing differences between Occupations with higher resolution.

There are a total of 68 occupations recorded in the Prosper Loan Dataset. I took the top ten occupations by count for my visualization. Originally amongst the top ten, there were occupations that weren't clear, so I omitted them and replaced them with the next occupation.

After some feedback from my submission and reading an article which discourages the use of pie charts, I sought to change the visualization to remove the pie chart. I came across a hierarchical bar chart example and thought it conveyed my story better.

Feedback

Ronald Truong

What I see right away is a bar plot showing the distribution of Prosper Scores from 1 - 11. I noticed that by hovering over the bars, the pie chart and legend changes to account for how the occupations listed make up percentage wise for that score.

What I don't like is that there are two Occupation types that the data is skewed towards. Other and Professional Occupations don't give much value. Although they are indeed the top 10 Occupation, I believe they should be removed.

It's interesting to see that Computer Programmers are very credit worthy occupations. They have a high prosper score on average compared to all the other professions, besides Executive.

t0mkaka

Forum Mentor

@wllmtrng

Hi William,

Great work with all the plot and data in sync. I was testing how fast the numbers can be changed :slight_smile:

I can notice that there are few borowwers for the lower end and upper end of the scores and most of the loans are from mid -level. The pie-chart on the right is also showing the values and I can see the distribution for a particular profession by hovering over the pies

Is there something you don’t understand in the graphic?

I would suggest you work more on this. Your plots are great but to a person who does not know about loan data this is very confusing.

Title - A title tells information we are going to see. An appropriate title helps in better understanding.
Axis Labels - There is no labels on axis in your bar plots. As a person unaware of the data it took me some time to understand whats on x-axis and what is on y-axis.
Pie-Chart - I am not so against pie-chart when they convey clear information (which is usually the case when there are only 2-3 sections) . You have 10 and it is very difficult to interpret percentage numbers from that. The numbers are on the table to the right but again, one has to check table then match color.

These are all my suggestions but number 1 and 2 will definitely improve the readability.

Will wait for your iterations. All the best.

include all feedback you received from others on your visualization from the first sketch to the final visualization

Dai Ying Wu

The title could be changed to reflect a more targetted story you're trying to get across. I'm assuming you want to show people what professions are most credit worthy. One thing you can do to demonstrate that more properly is to maybe sort the legend when a Prosper Score is highlighted.

The things I do notice is that the distribution amongs occupations is pretty even in the midrange prosper scores. In the higher end executives, nurses, and programmers dominate. On the lower end, Teachers, Administrative Assistants, Executives, and Accountants take much of the proportion. It is ironic that for the Prosper Score of 1 that 13% of them are Accountants.

Resources and References

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
background-color: #e4e8e7;
padding: 10px;
}
h1 {
font: 30px Futura;
fill: black;
}
p {font: 16px Futura;
fill: black;
}
li {
font: 14px Futura;
fill: black;
}
text {
font: 11px Futura;
fill: black;
stroke: #grey;
}
rect.background {
fill: #e4e8e7;
stoke: #9D7917;
}
.axis {
shape-rendering: crispEdges;
}
.axis path,
.axis line {
fill: #638ea3;
stroke: none;
}
</style>
<body>
<h1>Occupations and their Prosper Score, 2009-2014</h1>
<p><a href="https://www.prosper.com/">The Prosper Marketplace</a> provides an
alternative avenue for people to invest and borrow money. When a potential
borrower fills out an application, a Prosper Score from 1 to 11 is
assigned. Lending to an individual of a lower score will have a better
return on investment, but also have increased chances of defaulting.
Lending to an individual of a higher score will have a lower chance of
defaulting, but a lower return on investment.
</p>
<p>Quite often, investors use historical data and group past borrowers by
certain criteria to compare against potential borrowers of similar criteria.
Occupations is a criteria often used. Potential borrowers with occupations
that have a higher Prosper Score on average can be generally more credit worthy.
</p>
<p>Shown below are number of past borrowers grouped by occupation. Click on the bar
of each occupation to see how Prosper Score is split between the individuals.
To return back to the Occupations display, click on the blank portion of the
visualization canvas
</p>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
function hierarchical(data) {
var margin = {top: 30, right: 120, bottom: 0, left: 120},
width = 960 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]);
var barHeight = 20;
var color = d3.scale.ordinal()
.range(["steelblue", "#ccc"]);
var duration = 750,
delay = 25;
var partition = d3.layout.partition()
.value(function (d) {
return d.size;
}).sort(null);
var xAxis = d3.svg.axis()
.scale(x)
.orient("top");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("rect")
.attr("class", "background")
.attr("width", width)
.attr("height", height)
.on("click", up);
svg.append("g")
.attr("class", "x axis");
svg.append("g")
.attr("class", "y axis")
.append("line")
.attr("y1", "100%");
partition.nodes(data);
x.domain([0, data.value]).nice();
down(data, 0);
function down(d, i) {
if (!d.children || this.__transition__) return;
var end = duration + d.children.length * delay;
// Mark any currently-displayed bars as exiting.
var exit = svg.selectAll(".enter")
.attr("class", "exit");
// Entering nodes immediately obscure the clicked-on bar, so hide it.
exit.selectAll("rect").filter(function (p) {
return p === d;
})
.style("fill-opacity", 1e-6);
// Enter the new bars for the clicked-on data.
// Per above, entering bars are immediately visible.
var enter = bar(d)
.attr("transform", stack(i))
.style("opacity", 1);
// Have the text fade-in, even though the bars are visible.
// Color the bars as parents; they will fade to children if appropriate.
enter.select("text").style("fill-opacity", 1e-6);
enter.select("rect").style("fill", color(true));
// Update the x-scale domain.
x.domain([0, d3.max(d.children, function (d) {
return d.value;
})]).nice();
// Update the x-axis.
svg.selectAll(".x.axis").transition()
.duration(duration)
.call(xAxis);
// Transition entering bars to their new position.
var enterTransition = enter.transition()
.duration(duration)
.delay(function (d, i) {
return i * delay;
})
.attr("transform", function (d, i) {
return "translate(0," + barHeight * i * 1.2 + ")";
});
// Transition entering text.
enterTransition.select("text")
.style("fill-opacity", 1);
// Transition entering rects to the new x-scale.
enterTransition.select("rect")
.attr("width", function (d) {
return x(d.value);
})
.style("fill", function (d) {
return color(!!d.children);
});
// Transition exiting bars to fade out.
var exitTransition = exit.transition()
.duration(duration)
.style("opacity", 1e-6)
.remove();
// Transition exiting bars to the new x-scale.
exitTransition.selectAll("rect")
.attr("width", function (d) {
return x(d.value);
});
// Rebind the current node to the background.
svg.select(".background")
.datum(d)
.transition()
.duration(end);
d.index = i;
}
function up(d) {
if (!d.parent || this.__transition__) return;
var end = duration + d.children.length * delay;
// Mark any currently-displayed bars as exiting.
var exit = svg.selectAll(".enter")
.attr("class", "exit");
// Enter the new bars for the clicked-on data's parent.
var enter = bar(d.parent)
.attr("transform", function (d, i) {
return "translate(0," + barHeight * i * 1.2 + ")";
})
.style("opacity", 1e-6);
// Color the bars as appropriate.
// Exiting nodes will obscure the parent bar, so hide it.
enter.select("rect")
.style("fill", function (d) {
return color(!!d.children);
})
.filter(function (p) {
return p === d;
})
.style("fill-opacity", 1e-6);
// Update the x-scale domain.
x.domain([0, d3.max(d.parent.children, function (d) {
return d.value;
})]).nice();
// Update the x-axis.
svg.selectAll(".x.axis").transition()
.duration(duration)
.call(xAxis);
// Transition entering bars to fade in over the full duration.
var enterTransition = enter.transition()
.duration(end)
.style("opacity", 1);
// Transition entering rects to the new x-scale.
// When the entering parent rect is done, make it visible!
enterTransition.select("rect")
.attr("width", function (d) {
return x(d.value);
})
.each("end", function (p) {
if (p === d) d3.select(this).style("fill-opacity", null);
});
// Transition exiting bars to the parent's position.
var exitTransition = exit.selectAll("g").transition()
.duration(duration)
.delay(function (d, i) {
return i * delay;
})
.attr("transform", stack(d.index));
// Transition exiting text to fade out.
exitTransition.select("text")
.style("fill-opacity", 1e-6);
// Transition exiting rects to the new scale and fade to parent color.
exitTransition.select("rect")
.attr("width", function (d) {
return x(d.value);
})
.style("fill", color(true));
// Remove exiting nodes when the last child has finished transitioning.
exit.transition()
.duration(end)
.remove();
// Rebind the current parent to the background.
svg.select(".background")
.datum(d.parent)
.transition()
.duration(end);
}
// Creates a set of bars for the given data node, at the specified index.
function bar(d) {
var bar = svg.insert("g", ".y.axis")
.attr("class", "enter")
.attr("transform", "translate(0,5)")
.selectAll("g")
.data(d.children)
.enter().append("g")
.style("cursor", function (d) {
return !d.children ? null : "pointer";
})
.on("click", down);
bar.append("text")
.attr("x", -2)
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function (d) {
return d.name;
});
bar.append("rect")
.attr("width", function (d) {
return x(d.value);
})
.attr("height", barHeight);
return bar;
}
// A stateful closure for stacking bars horizontally.
function stack(i) {
var x0 = 0;
return function (d) {
var tx = "translate(" + x0 + "," + barHeight * i * 1.2 + ")";
x0 += x(d.value);
return tx;
};
}
}
</script>
<script>
data = {
"name": "Occupations",
"children": [
{
"name": "Executive",
"children": [
{
"name": "1",
"size": 33
},
{
"name": "2",
"size": 158
},
{
"name": "3",
"size": 233
},
{
"name": "4",
"size": 393
},
{
"name": "5",
"size": 333
},
{
"name": "6",
"size": 419
},
{
"name": "7",
"size": 439
},
{
"name": "8",
"size": 575
},
{
"name": "9",
"size": 387
},
{
"name": "10",
"size": 337
},
{
"name": "11",
"size": 130
}
]
},
{
"name": "Computer Programmer",
"children": [
{
"name": "1",
"size": 37
},
{
"name": "2",
"size": 133
},
{
"name": "3",
"size": 186
},
{
"name": "4",
"size": 284
},
{
"name": "5",
"size": 278
},
{
"name": "6",
"size": 385
},
{
"name": "7",
"size": 381
},
{
"name": "8",
"size": 582
},
{
"name": "9",
"size": 439
},
{
"name": "10",
"size": 383
},
{
"name": "11",
"size": 112
}
]
},
{
"name": "Teacher",
"children": [
{
"name": "1",
"size": 31
},
{
"name": "2",
"size": 189
},
{
"name": "3",
"size": 268
},
{
"name": "4",
"size": 403
},
{
"name": "5",
"size": 362
},
{
"name": "6",
"size": 469
},
{
"name": "7",
"size": 347
},
{
"name": "8",
"size": 419
},
{
"name": "9",
"size": 222
},
{
"name": "10",
"size": 106
},
{
"name": "11",
"size": 42
}
]
},
{
"name": "Analyst",
"children": [
{
"name": "1",
"size": 21
},
{
"name": "2",
"size": 136
},
{
"name": "3",
"size": 182
},
{
"name": "4",
"size": 331
},
{
"name": "5",
"size": 286
},
{
"name": "6",
"size": 333
},
{
"name": "7",
"size": 315
},
{
"name": "8",
"size": 481
},
{
"name": "9",
"size": 297
},
{
"name": "10",
"size": 256
},
{
"name": "11",
"size": 73
}
]
},
{
"name": "Administrative Assistant",
"children": [
{
"name": "1",
"size": 46
},
{
"name": "2",
"size": 201
},
{
"name": "3",
"size": 261
},
{
"name": "4",
"size": 445
},
{
"name": "5",
"size": 377
},
{
"name": "6",
"size": 438
},
{
"name": "7",
"size": 331
},
{
"name": "8",
"size": 342
},
{
"name": "9",
"size": 158
},
{
"name": "10",
"size": 77
},
{
"name": "11",
"size": 21
}
]
},
{
"name": "Accountant/CPA",
"children": [
{
"name": "1",
"size": 36
},
{
"name": "2",
"size": 154
},
{
"name": "3",
"size": 214
},
{
"name": "4",
"size": 304
},
{
"name": "5",
"size": 280
},
{
"name": "6",
"size": 385
},
{
"name": "7",
"size": 295
},
{
"name": "8",
"size": 403
},
{
"name": "9",
"size": 256
},
{
"name": "10",
"size": 171
},
{
"name": "11",
"size": 52
}
]
},
{
"name": "Sales - Commission",
"children": [
{
"name": "1",
"size": 20
},
{
"name": "2",
"size": 157
},
{
"name": "3",
"size": 210
},
{
"name": "4",
"size": 358
},
{
"name": "5",
"size": 248
},
{
"name": "6",
"size": 304
},
{
"name": "7",
"size": 289
},
{
"name": "8",
"size": 356
},
{
"name": "9",
"size": 195
},
{
"name": "10",
"size": 133
},
{
"name": "11",
"size": 48
}
]
},
{
"name": "Skilled Labor",
"children": [
{
"name": "1",
"size": 15
},
{
"name": "2",
"size": 148
},
{
"name": "3",
"size": 206
},
{
"name": "4",
"size": 353
},
{
"name": "5",
"size": 262
},
{
"name": "6",
"size": 354
},
{
"name": "7",
"size": 261
},
{
"name": "8",
"size": 304
},
{
"name": "9",
"size": 156
},
{
"name": "10",
"size": 79
},
{
"name": "11",
"size": 19
}
]
},
{
"name": "Nurse (RN)",
"children": [
{
"name": "1",
"size": 16
},
{
"name": "2",
"size": 103
},
{
"name": "3",
"size": 168
},
{
"name": "4",
"size": 328
},
{
"name": "5",
"size": 234
},
{
"name": "6",
"size": 324
},
{
"name": "7",
"size": 291
},
{
"name": "8",
"size": 330
},
{
"name": "9",
"size": 190
},
{
"name": "10",
"size": 116
},
{
"name": "11",
"size": 45
}
]
},
{
"name": "Clerical",
"children": [
{
"name": "1",
"size": 25
},
{
"name": "2",
"size": 187
},
{
"name": "3",
"size": 266
},
{
"name": "4",
"size": 361
},
{
"name": "5",
"size": 273
},
{
"name": "6",
"size": 329
},
{
"name": "7",
"size": 267
},
{
"name": "8",
"size": 218
},
{
"name": "9",
"size": 111
},
{
"name": "10",
"size": 42
},
{
"name": "11",
"size": 8
}
]
},
{
"name": "Sales - Retail",
"children": [
{
"name": "1",
"size": 34
},
{
"name": "2",
"size": 196
},
{
"name": "3",
"size": 247
},
{
"name": "4",
"size": 351
},
{
"name": "5",
"size": 235
},
{
"name": "6",
"size": 285
},
{
"name": "7",
"size": 243
},
{
"name": "8",
"size": 233
},
{
"name": "9",
"size": 115
},
{
"name": "10",
"size": 49
},
{
"name": "11",
"size": 24
}
]
},
{
"name": "Retail Management",
"children": [
{
"name": "1",
"size": 15
},
{
"name": "2",
"size": 149
},
{
"name": "3",
"size": 161
},
{
"name": "4",
"size": 287
},
{
"name": "5",
"size": 251
},
{
"name": "6",
"size": 346
},
{
"name": "7",
"size": 271
},
{
"name": "8",
"size": 263
},
{
"name": "9",
"size": 144
},
{
"name": "10",
"size": 72
},
{
"name": "11",
"size": 19
}
]
},
{
"name": "Truck Driver",
"children": [
{
"name": "1",
"size": 15
},
{
"name": "2",
"size": 113
},
{
"name": "3",
"size": 134
},
{
"name": "4",
"size": 243
},
{
"name": "5",
"size": 154
},
{
"name": "6",
"size": 199
},
{
"name": "7",
"size": 203
},
{
"name": "8",
"size": 159
},
{
"name": "9",
"size": 87
},
{
"name": "10",
"size": 35
},
{
"name": "11",
"size": 15
}
]
},
{
"name": "Construction",
"children": [
{
"name": "1",
"size": 16
},
{
"name": "2",
"size": 103
},
{
"name": "3",
"size": 110
},
{
"name": "4",
"size": 251
},
{
"name": "5",
"size": 160
},
{
"name": "6",
"size": 169
},
{
"name": "7",
"size": 171
},
{
"name": "8",
"size": 156
},
{
"name": "9",
"size": 106
},
{
"name": "10",
"size": 60
},
{
"name": "11",
"size": 11
}
]
},
{
"name": "Police Officer",
"children": [
{
"name": "1",
"size": 10
},
{
"name": "2",
"size": 78
},
{
"name": "3",
"size": 100
},
{
"name": "4",
"size": 187
},
{
"name": "5",
"size": 151
},
{
"name": "6",
"size": 219
},
{
"name": "7",
"size": 177
},
{
"name": "8",
"size": 164
},
{
"name": "9",
"size": 94
},
{
"name": "10",
"size": 66
},
{
"name": "11",
"size": 14
}
]
},
{
"name": "Laborer",
"children": [
{
"name": "1",
"size": 9
},
{
"name": "2",
"size": 107
},
{
"name": "3",
"size": 139
},
{
"name": "4",
"size": 210
},
{
"name": "5",
"size": 164
},
{
"name": "6",
"size": 195
},
{
"name": "7",
"size": 157
},
{
"name": "8",
"size": 130
},
{
"name": "9",
"size": 63
},
{
"name": "10",
"size": 20
},
{
"name": "11",
"size": 6
}
]
},
{
"name": "Civil Service",
"children": [
{
"name": "1",
"size": 16
},
{
"name": "2",
"size": 63
},
{
"name": "3",
"size": 95
},
{
"name": "4",
"size": 157
},
{
"name": "5",
"size": 142
},
{
"name": "6",
"size": 165
},
{
"name": "7",
"size": 155
},
{
"name": "8",
"size": 173
},
{
"name": "9",
"size": 79
},
{
"name": "10",
"size": 59
},
{
"name": "11",
"size": 23
}
]
},
{
"name": "Engineer - Mechanical",
"children": [
{
"name": "1",
"size": 8
},
{
"name": "2",
"size": 50
},
{
"name": "3",
"size": 81
},
{
"name": "4",
"size": 138
},
{
"name": "5",
"size": 122
},
{
"name": "6",
"size": 147
},
{
"name": "7",
"size": 151
},
{
"name": "8",
"size": 190
},
{
"name": "9",
"size": 123
},
{
"name": "10",
"size": 94
},
{
"name": "11",
"size": 22
}
]
},
{
"name": "Food Management",
"children": [
{
"name": "1",
"size": 5
},
{
"name": "2",
"size": 74
},
{
"name": "3",
"size": 96
},
{
"name": "4",
"size": 155
},
{
"name": "5",
"size": 120
},
{
"name": "6",
"size": 158
},
{
"name": "7",
"size": 108
},
{
"name": "8",
"size": 149
},
{
"name": "9",
"size": 79
},
{
"name": "10",
"size": 40
},
{
"name": "11",
"size": 9
}
]
},
{
"name": "Engineer - Electrical",
"children": [
{
"name": "1",
"size": 6
},
{
"name": "2",
"size": 38
},
{
"name": "3",
"size": 56
},
{
"name": "4",
"size": 113
},
{
"name": "5",
"size": 70
},
{
"name": "6",
"size": 100
},
{
"name": "7",
"size": 119
},
{
"name": "8",
"size": 147
},
{
"name": "9",
"size": 113
},
{
"name": "10",
"size": 101
},
{
"name": "11",
"size": 30
}
]
}
]
};
hierarchical(data);
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment