Add Pearsons correlation to _column_associations#1203
Conversation
|
This is the output, which I excluded for now, due to errors: Not sure why Pearson is showing up as |
There was a problem hiding this comment.
Hey @reshamas, thank you for starting this!
In skrub, we use methods defined in skrub._dataframe._common.py to dispatch operations on polars or pandas dataframes. We do this to avoid copying dataframes from one backend to the other, and later to enable features like lazy evaluation. Therefore, the input of the function skrub._column_associations.column_associations() could be either a pandas or a polars DataFrame.
So, here, we would like to use something like sbd.corr() ("sbd" stands for "skrub dataframe"), instead of pandas corr. Since this method doesn't exist yet, you'll have to add it to skrub._dataframe._common.py 😁
Alternatively, you could turn your dataframe into a numpy array with skb.to_numpy() and then use np.corrcoef. I slightly prefer the former suggestion because it adds corr() in skrub, which I think would be also useful later.
If you go with the first option, I suggest converting the output to a numpy 2d array, so that you can directly use the _stack_symmetric_associations() function to melt the symmetric matrix into a long format. You need to select only numeric columns when passing your dataframe to _stack_symmetric_associations().
Finally, you can apply the merge operation with skrub._join_utils.left_join.
We know that developing skrub is fairly involved at the moment, and we plan on making a simple documentation for all our internals. In the meantime, I'm here to help you to move this PR forward!
|
Hey @reshamas, do you plan to continue working on this? |
|
@Vincent-Maladiere No, I won't be continuing work on this. |
|
@jeromedockes, I have an error on the TruncatedSVD for Windows; have you experienced this recently? |
|
I don't think so 🤔 |
|
Ok, it's gone! |
| > | ||
| {{ association["cramer_v"] | format_number }} | ||
| </td> | ||
| <td> {{ association["pearson_corr"] | format_number }} </td> |
There was a problem hiding this comment.
|
very interesting to see in your iris dataset example that these correlations are not concordant (third line: 0.395 vs 0.818, compared to the two lines above where the Cramer's is much higher) |
| <th scope="col">Column 1</th> | ||
| <th scope="col">Column 2</th> | ||
| <th scope="col"><a href="https://en.wikipedia.org/wiki/Cram%C3%A9r%27s_V">Cramér's V</a></th> | ||
| <th scope="col">Pearson's Correlation</a></th> |
There was a problem hiding this comment.
| <th scope="col">Pearson's Correlation</a></th> | |
| <th scope="col"><a href="https://en.wikipedia.org/wiki/Pearson_correlation_coefficient">Pearson's Correlation</a></th> |
to be consistent with the other column we can add the link even though most people know what pearson correlation is. if you prefer not to add the link you need to remove the closing </a> tag, as there is no corresponding opening <a>
There was a problem hiding this comment.
woops, html is forgiving
|
|
||
| To compute the Pearson's Correlation Coefficient, only numeric columns are | ||
| considered. The correlation is computed using the Pearson method used in | ||
| pandas. |
There was a problem hiding this comment.
| pandas. | |
| pandas or polars, depending on the input dataframe. |
|
|
||
| * `Pearson's Correlation Coefficient | ||
| <https://en.wikipedia.org/wiki/Pearson_correlation_coefficient>`_ | ||
| * `pandas.DataFrame.corr |
There was a problem hiding this comment.
if we have the link to pandas doc would it make sense to ahve the polars one?
There was a problem hiding this comment.
Only if we use pl.DataFrame.corr() I'd say, otherwise we should mention what we use for polars inputs
yeah that's true... the cramer thing is quite rough and does aggressive binning and subsampling... it will be interesting to investigate a bit more |
it should be a bit more similar to spearman's I guess |
|
I guess polars and pandas have a different way of handling nans, pandas drops them whereas in polars they result in NaN correlations. WDYT would be the right behavior here? I think the pandas one because we already have other ways of indicating when there are nans so even if it should be interpreted cautiously the non-nan correlation is more informative. it will require a bit more work so could also be done in a separate pr |
|
and finally, have you checked the computation time for largish dataframes, does it change a lot the total time of the report? |
| i, j contains the statistic for column i x column j. | ||
|
|
||
| """ | ||
| # Replace categorical columns with np.nan to get a correlation matrix of shape |
There was a problem hiding this comment.
I think we could simplify this a bit
- select numeric columns only
- use sbd.pearson_corr on those
- use pandas stack().reset_index() to convert to tall format
- or in polars case insert a column like
with_column(left_col=<the column names>)then usedf.unpivot(index=left_col)(only we would use a random name instead ofleft_colto have no name clash) - then do the left join as you are doing in the caller
we would no longer use stack_symmetric_associations for this one I guess, but we would no longer need to do the filling with np.nan or the loops over columns. WDYT?
There was a problem hiding this comment.
Yes, I hesitated with this approach, but I saw avoiding manually dispatching between polars and pandas as an advantage, and reusing stack_symmetric_associations also makes things easier to understand IMO. Note that you wouldn't need to select numeric because sbd.pearson_corr does it for you. I agree that adding NaNs columns is a bit convoluted, though. WDYT?
There was a problem hiding this comment.
ok I see what you mean. I still think a nice advantage of using a left join as you did is that we don't care if we have different columns in the 2 pairwise matrices, and it's not that bad to do the dispatch with the decorator we will just have 2 helpers like
@_stack.specialize('pandas')
def _stack_pandas(df, ...):
# one-liner
(private to this module and with only the parameters we need here, not a general one in skrub._dataframe), and we don't need to insert the numpy nans and then convert all the columns to numpy and do the hstack
but both options make sense
There was a problem hiding this comment.
Ok, will do this option
Right, I guess polars |
I think it's a bit more complicated than that because you want to drop nulls for each pair of columns. when computing the correlation between columns A and B I don't want to drop rows that have a null in column C but have values for A and B: so it might be easier to leave that for a different PR |
|
Yes right, I realized that just now. Not a huge deal to compute corr pairwise, though. Worse case scenario we can convert everything to pandas and forget about it |
|
thanks a lot for doing this investigation @Vincent-Maladiere . I guess convert to pandas is ok for now, though I would like to limit the number of things we do that require pandas to work in case one day we want to make it optional. another option would be to keep using polars.corr() and if it ends up full of nan that's ok, and maybe one day polars will add an option to handle nans differently. as you prefer I think that as for plotting, we should skip computing associations when there are many columns by default, but that's for another PR. as you show anyway the cramer statistic is much more expensive to compute than correlations, which is expected, so this PR doesn't really weigh on that |
|
As I feared, dispatching was not straightforward, and I ran into tons of edge cases |
ouch sorry about that @Vincent-Maladiere I did not have this foresight and was more optimistic :/ . thanks so much for pushing through, though!! I'll do a final pass tomorrow but this looks like it is ready 🚀 |
|
No worries, I learned a lot while doing it |
jeromedockes
left a comment
There was a problem hiding this comment.
great, thank you very much @reshamas and @Vincent-Maladiere ! seeing correlations is one of the first things we want so this will be appreciated
Co-authored-by: Vincent Maladiere <maladiere.vincent@yahoo.fr>
Co-authored-by: Vincent Maladiere <maladiere.vincent@yahoo.fr>








Towards #1176
Add Pearsons correlation to column associations.