[ENH] Add keywords parameter to StringSimilarityEncoder - #550
Conversation
Codecov Report
@@ Coverage Diff @@
## main #550 +/- ##
=======================================
Coverage 97.47% 97.47%
=======================================
Files 90 90
Lines 3480 3492 +12
Branches 681 687 +6
=======================================
+ Hits 3392 3404 +12
Misses 32 32
Partials 56 56
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
|
I added a bunch of tests, seems good, but maybe it needs more |
solegalli
left a comment
There was a problem hiding this comment.
Hi @glevv
Thank you for the enhancement. It looks good to me. I have mostly some minor comments.
And one question regarding how Nan in the train set should be handled. My understanding is:
- "impute", replaces nan by "". So when creating the dummies, would "" be one of them?
- "raise"; raises an error
- "ignore": nan remain nan. But the current logic, won't make "" part of the dummies?
Thanks a lot for the contribution!
| to create similarity variables. Useful when someone has domain knowledge of the | ||
| problem. Could be defined only for several features; in this case for specified | ||
| features keywords will be used and most common categories will be used for | ||
| unspecified. |
There was a problem hiding this comment.
I don't understand the last sentence of this description. Would you be able to re-phrase it?
| ) | ||
| elif self.missing_values == "impute": | ||
| for var in self.variables_: | ||
| for var in self.variables_: |
There was a problem hiding this comment.
are we removing the functionality to handle missing data? I guess, not because the tests pass.
But regarding this code:
Are we not making nan part of the categories to appear as dummies?
| assert tr.get_feature_names_out(input_features=input_features) == out | ||
|
|
||
|
|
||
| def test_keywords_bad_type(): |
There was a problem hiding this comment.
could we test more than just a string by using parametrize? maybe tuples, integers?
| StringSimilarityEncoder(keywords="hola") | ||
|
|
||
|
|
||
| def test_keywords_bad_items(): |
There was a problem hiding this comment.
same here, could we use parametrize and test more options?
| StringSimilarityEncoder(keywords={"column": "hola"}) | ||
|
|
||
|
|
||
| def test_keywords_dont_match(df_enc_big): |
There was a problem hiding this comment.
Could we either add columns that are in the data to the dictionary, or even better, test a second dictionary with a combination of columns that are in the data, and a column that is not?
Also, here we are testing that the variables/columns don't match, correct? can we adjust the name of the test?
| assert "var_B_F" not in X.columns | ||
|
|
||
|
|
||
| def test_encode_full_keywords(): |
There was a problem hiding this comment.
what do you mean by "full_keywords"?
|
Hi @glevv This is looking really good. Thank you so much for the quick turnaround. I've got a couple of questions about the logic in fit: fit logic:
So if the user defined all categorical variables, or the variables in the parameter At the moment, we've got the keywords dictionary after all the logic in fit(): feature_engine/feature_engine/encoding/similarity_encoder.py Lines 256 to 258 in 05ae18c This means that for the variables in the dictionary, we are fitting twice. I wonder if there is a way in which we could avoid running the logic twice for those variables that are in the keywords dictionary? Something like, if self.keyword exists and all the keys are in variables_ then just copy, alternatively, define the variables not in self.keywords. imputation logic Could we add a few tests to corroborate that:
In short, we need a test to differentiate the behaviour between handle_missing is impute or ignore, and the train set has nan values. Finally, we've got another PR coming up that modifies the strings of this class: #547 Thanks a lot for your time! |
|
Done |
| .head(self.top_categories) | ||
| .index.tolist() | ||
| ) | ||
| if self.keywords: |
There was a problem hiding this comment.
If we update the dictionary here, and the dictionary keys contain all the variables in variables_, we are running all of the logic between 226 and this line, for no reason. Because those keywords will not be used.
Would it not be better to check, at around line 223 that:
- if, all of
variables_are inkeywords.keys(), then just copy dict. - If some of
variables_are in keywords.keys(), then apply the logic to find keywords in the remaining variables - If keywords is None, then apply the logic in all
variables_
What do you think about this?
There was a problem hiding this comment.
No, it will be worse. It will make logic more complicated (which in turn will mess up coverage and tests) and won't give any speed up.
This way it is straightforward and readable.
But I will look into it.
|
I implemented this logic, but tests are failing because some other transformers are not using Optional typing see #555 |
|
Sorry for the delay, I just merged #555 Logic changes look good to me! |
reword docstrings and errors
Added keywords support for StringSimilarityEncoder.
Keywords allow user to introduce some domain knowledge (if any) into encoder