Regression Plots in Python with Seaborn | by Alan Jones | Towards Data Science

A Scatter plot is a great way of exploring relationships or patterns in data. But adding a regression line can make those patterns stand out and it is one thing that is not built into the Pandas plot API.
You can use a stats library like Statsmodels, or even Numpy, to create a regression model from your data and include this in your plot. But, if all you need is a visual guide to relationships in your data, Seaborn can do this for you, easily.
Seaborn is a statistical plotting library that can read Pandas dataframes (as well as other data structures) and provides simple methods for adding regression lines to your scatter diagrams.
We are going to take a look at how the regplot function in Seaborn can be used to do this and we’ll look at linear regression that helps us see simple relations in the data and also higher order regressions that show a more complex picture.
To introduce the regplot function, we’ll first manufacture some data to produce some idealised plots and then later use world population data to illustrate its use in a real-world situation.
Below are examples of a scatter plot and the same plot with a linear regression line added. The regression line is an attempt to find the best fit through the points in the scatter plot. The shaded area around the line is the confidence interval.
You were probably able to discern a linear relationship from the first plot but adding a regression line on top of the scatter diagram makes it much clearer.
Let’s get right into the code and see how Seaborn helps us. First import the Seaborn library.
import seaborn as sns
Now we will create a couple of Numpy arrays that will represent the x and y data that we will plot. In the code below we import the Numpy library and then create an array of integers from -5 to 5 — that’s the array representing the x data. To create the y array we use a formula that creates a linear relationship between x and y:
y = x*2 + 3
When we plot this we would expect to see a straight line graph with the intercept at 3 and a two-to-one relationship between x and y. The last line of the code below creates a scatter plot and we can see that it is the form of a straight line.
import numpy as npx=np.array([-5,-4,-3,-2,-1,0,1,2,3,4,5])y=x*2+3sns.scatterplot(x=x,y=y)
So when we create a regplot, a plot that includes a regression line we would expect that line to coincide the scatter points.
sns.regplot(x=x,y=y)
And, of course, it does.
But regression does not have to be linear. In the next block of code we define a quadratic relationship between x and y. We then plot that but instead of the default linear option we set a second order regression, order=2. This instructs regplot to find a quadratic relationship.
y2=x**2+2*x+3sns.regplot(x=x,y=y2,order=2)
Again, the regression line exactly matches the scatter diagram points as expected.
We could go on but we will stop at the third order regression which is illustrated below.
y3=x**3+x**2+2*x+3sns.regplot(x=x,y=y3,order=3)
Those examples were not realistic, of course. We were giving regplot exact representations of first, second and third order plots and, unsurprisingly, the regression line fitted the scatter plot points exactly. Real data is generally more noisy: there are random variations, errors in measurement. Or, maybe the data simply doesn’t conform to our ideal linear, quadratic or third order formulae.
So, now we are going to see the same type of plots but with some real data.
We are going to load some world population data, pick a country and try to see if a regression plot can give us any insights.
Here, we set the url of the data to download to a Github repository — the data is oiginally from Gapminder (you can see the full acknowledgement below*).
We then load the data into a Pandas dataframe.
Just a couple of things to note here: the file is a tsv file, that’s like a csv but with tabs for separators instead of commas, so we need to specify that when converting to a dataframe; and also I convert the year field to an integer to make it easier to make comparisons (it otherwise loads as a float).
The population totals are real numbers and are, of course, in the millions. To make these look a bit nicer on the graphs, I divide them all by 1 million.
popDataURL = "https://raw.githubusercontent.com/jennybc/gapminder/master/inst/extdata/gapminder.tsv"import pandas as pdpopData = pd.read_csv(popDataURL, delimiter='\t',    dtype=({'year':int}))popData['pop']=popData['pop']/1000000popData
I am only going to look at one country, initially, so I created a new dataframe called SpainData. Then I plot the population in Spain over the last several decades on a regplot, looking for the default linear relationship between time and population.
SpainData = popData[popData['country']=='Spain' sns.regplot(x="year", y="pop", data=SpainData)
Looking at this, it seems that there is a steady growth in population, but examining the scatter points it looks like there is a steeper curve in the earlier decades and a shallower one more recently. Perhaps a straight line is not the best fit. Let’s try higher order regressions.
sns.regplot(x="year", y="pop", data=SpainData, order=2, ci=None)
sns.regplot(x="year", y="pop", data=SpainData, order=3, ci=None)
By just looking at the plots above, it looks like the second order graph is closer to the real data than the others. This is not to say that the population of Spain can be interpreted by strictly quadratic model — it’s likely to be more complex that that — but that curve gives us a better understanding of what is happening; that the population growth is not increasing at a steady rate but, rather, it is slowing.
It would probably be a mistake to try and use such a simple mathematical model to predict the likely increase in population of any country because there are so many factors that have to be taken into account. But Seaborn’s visual only approach can give us a better understanding of trends than a scatter chart with no regression line.
What if we want to compare different countries? Seaborn gives us a neat way of doing this using the hue parameter.
Let’s create a new dataframe with five significant European countries, France, Germany, Spain, Italy and The Netherlands and see how the growth of their populations compare.
The resulting plot is done with lmplot. This is similar to regplot but allows us to plot the different countries in different colors by setting hue='country'.
topeucountries = ['France','Germany','Spain','Italy','Netherlands']europeData = popData[popData['country'].isin(topeucountries)]sns.lmplot(x="year", y="pop", data=europeData, hue='country',   order=2, ci=False)
In the resulting graph, you can see that, while still on an apparently upward trajectory, population growth appears to be slowing. This seems particularly clear in the case of Italy.
Let’s look at another example.
It’s indisputable that, on average, the more money you have the longer you can expect to live. Wealth and life expectancy are linked due to access to better healthcare facilities, better diets and so on.
So, the more you earn the longer you live but only up to a point. Life expectancy can’t continue to increase with wealth; there must be a limit.
Here’s a couple of graphs that demonstrate the link. Here, we represent wealth by GDP per capita (that’s the total GDP of a nation divided by the number of people who live there — which can be thought of as the average wealth within a particular nation).
The first linear graph appears to be a reasonably good fit but it cannot be that the line in this diagram will extend to 100, 150 or 200 years as income increases. There must be a limit; increases in income must surely follow a law of diminishing returns.
The order=2 version confirms this and gives a better picture of reality where the increase in life expectancy tails off as GdpPercap increases.
sns.lmplot(x="gdpPercap", y="lifeExp",data=europeData,    ci=False, order=1)sns.lmplot(x="gdpPercap", y="lifeExp",data=europeData,    ci=False, order=2)
Hopefully you can see from the examples above that regression plots can make interpreting data a little easier and that Seaborn gives you the tools to do this easily.
As always, thanks for reading. If you would like to know when I publish new articles, please consider signing up for an email alert here.
If you are not a Medium subscriber, how about signing up so you can read as many articles as you like for $5 a month. Sign up here and I’ll earn a small commision.