The new kid on the statistics-in-Python block: pingouin | by Eryk Lewinson | Towards Data Science

Python has a few very well developed and mature libraries used for statistical analysis, with the biggest two being statsmodels and scipy. These two contain a lot (and I mean a LOT) of statistical functions and classes that will in 99% of the times cover all your use-cases. So why are there still any new libraries being released?
The newcomers often try to fill in a niche or to provide something extra that the established competition does not have. Recently, I stumbled upon a relatively new library called pingouin. Some key features of the library include:
The library is written in Python 3 and is based mostly on pandas and numpy. Operating directly on DataFrames is something that can definitely come in handy and simplify the workflow.
pingouin tries to strike a balance between complexity and simplicity, both in terms of coding and the generated output. In some cases, the output of statsmodels can be overwhelming (especially for new data scientists), while scipy can be a bit too concise (for example, in the case of the t-test, it reports only the t-statistic and the p-value).
Many of pingouin’s implementations are direct ports from popular R packages for statistical analysis.
The library provides a few new functionalities not found in the other libraries, such as calculating different effect sizes and converting between them, pairwise t-tests and correlations, circular statistics, and more!
In this article, I provide a brief introduction to some of the most popular functionalities available in pingouin and compare them to the already established and mature equivalents.
To start, we need to install the library by running pip install pingouin. Then, we import all the libraries that we will use in this article.
In this part, we explore a selection of functionalities available in pingouin, while highlighting the differences as compared to the other libraries.
Probably the most popular use-case of the statistical libraries (or at least on par with linear regression) is the t-test, which is most often used for hypothesis testing when running A/B tests.
Starting with scipy, we calculate the results of the t-test by running:
ttest_ind(x, y)
What generates the following output:
In the case of pingouin, we use the following syntax:
pg.ttest(x, y)
And receive:
scipy reports only the t-statistic and the p-value, while pingouin additionally reports the following:
degrees of freedom (dof),
95% confidence intervals (CI95%),
the effect size measured by Cohen’s d (cohen-d),
the Bayes factor, which indicates the strength of evidence in favor of the considered hypothesis (BF10),
the statistical power (power).
Note: statsmodels also contains a class for calculating the t-test (statsmodels.stats.weightstats.ttest_ind), which is essentially a wrapper around scipy’s ttest_ind, with a few modifications to the input parameters.
pingouin also contains more variants/extensions of the standard t-test, such as:
Pairwise t-Tests,
Mann-Whitney U test (a non-parametric version of the independent t-test),
Wilcoxon signed-rank test (a non-parametric version of the paired t-test).
Another very popular application of statistical libraries is to calculate the required sample size for an A/B test. To do so, we use power analysis. Please refer to my previous article if you are interested in more details.
In this example, we will focus on the case of calculating the required sample size for a t-test. However, you can easily adjust the code to calculate any of the other components (significance level, power, effect size).
For simplicity, we fix the other 3 parameters to some standard values.
Running the code generates the following output:
Required sample size (statsmodels): 64Required sample size (pingouin): 64
To be honest, there is not much difference in terms of power analysis for a standard t-test. We can additionally customize the type of the alternative hypothesis (whether it’s a one- or two-sided test). What is worth mentioning is that pingouin enables us to run power analysis for a few tests, which are not available in other libraries, such as the balanced one-way repeated measures ANOVA or the correlation test.
pingouin contains a selection of really nicely implemented visualizations, however, most of them are pretty domain-specific and might not be that interesting to the general reader (I do encourage you to take a look at them in the documentation).
However, one of the plots can definitely come in handy. In one of my previous articles, I described how to create QQ-plots in Python. pingouin definitely simplifies the process, as we can create a really nice QQ-plot with just one line of code.
np.random.seed(42)x = np.random.normal(size=100)ax = pg.qqplot(x, dist='norm')
What’s more, pingouin automatically handles how to display the reference line, while in the case of statsmodels, we need to do the same thing by providing an argument to theqqplot method of the ProbPlot class. A clear example of simplifying the task!
Quoting pg.qqplot’s documentation:
In addition, the function also plots a best-fit line (linear regression) for the data and annotates the plot with the coefficient of determination.
We will now investigate how to run ANOVA (analysis of variance). To do so, we will employ one of the built-in datasets describing the pain threshold per hair color (interesting idea!). First, we load and slightly transform the dataset.
We dropped one unnecessary column and replaced the space in column names with an underscore (this will make implementing ANOVA in statsmodels easier).
First, we present the pingouin approach.
What generates the following output:
Before moving further, we should mention the potential benefit of using pingouin: it adds an extra method (anova) directly to the pd.DataFrame, so we can skip calling pg.anova and specifying the data argument.
For comparison’s sake, we also carry out ANOVA using statsmodels. Using this library, it is a two-step process. First, we need to fit an OLS regression, and only then carry out ANOVA.
The outputs are very similar, although the one from pingouin contains an additional column, which is the effect size measure as partial eta-squared.
Similarly to the t-test, there are different variants of ANOVA included in pingouin.
As the last example, we inspect one of the most basic machine learning models — the linear regression. To do so, we first load the famous Boston Housing dataset from scikit-learn:
from sklearn.datasets import load_bostonX, y = load_boston(return_X_y=True)
Note: scikit-learn also contains the class to train linear regression, however, the output is the most basic of all the known to me Python libraries. In some cases, that is perfectly fine. However, coming from R, I prefer a more detailed output, which we will see soon enough.
To fit a linear regression model in pingouin, we need to run the following line of code.
lm = pg.linear_regression(X, y)lm
It can’t get simpler than that! And the output looks as follows:
The table is quite big and detailed. Personally, I don’t think including R2 and the adjusted variant makes a lot of sense here, as it results in a lot of repetition. My guess is that it was done to keep the output in the form of a DataFrame. Alternatively, we can turn that behavior off by setting as_dataframe=False, what results in creating a dictionary instead. This way, we additionally get the residuals of the model.
One extra thing about pingouin‘s implementation is that we can extract a measure of feature importance, which is expressed as “partitioning of the total R2 of the model into individual R2 contribution”. To display them, we need to set relimp to True.
It is time to move forward to the statsmodels implementation.
The code is a bit lengthier, as we also need to manually add the constant (a column of ones) to the DataFrame containing the independent variables. Please note that this step is not necessary when using the functional syntax (as used in the ANOVA example), however, in that case, the features and the target need to be in one object.
The following image presents the output of running the summary method on the fitted object:
For me, the extra two lines of code are definitely worth it, as the output is much more comprehensive and often saves us the trouble of running a few extra statistical tests or calculating a few measures of the goodness of fit.
In this article, I only presented a selection of the functionalities of the pingouin library. Some of the interesting features available are:
A wide range of functions for circular statistics,
Pairwise post-hocs tests,
Different Bayes Factors,
A selection of different measures of effect size and a function for converting between them.
And more!
In this article, I presented a brief overview of pingouin, a new library for statistical analysis. I do like the approach taken by the authors, in which they try to simplify the process as much as possible (also by making some things happen automatically in the background, like choosing the best reference line for a QQ-plot or applying corrections to the t-test), while at the same time keeping the output as thorough and complete as possible.
While I am still a fan of the statsmodels’s approach to summarizing the output of linear regression, I do find pingouin a nice tool that can save us some time and trouble in day-to-day data science tasks. I am looking forward to seeing how the library develops with time!
You can find the code used for this article on my GitHub. As always, any constructive feedback is welcome. You can reach out to me on Twitter or in the comments.
Found this article interesting? Become a Medium member to continue learning by reading without limits. If you use this link to become a member, you will support me at no extra cost to you. Thanks in advance and see you around!