Median-impute NaN in calc_cross_validation_score - #397
Open
drussellmrichie wants to merge 1 commit into
Open
drussellmrichie wants to merge 1 commit into
drussellmrichie wants to merge 1 commit into
Conversation
The sibling helpers in this file -- calc_elastic_net_regularization, calc_p_values_recursive_drop, calc_t_values_recursive_drop and calc_vif_recursive_drop -- all impute NaN before their sklearn / statsmodels fits (PRs larsiusprime#313, larsiusprime#316, larsiusprime#318). calc_cross_validation_score was missed. Real assessment data carries genuine missing building attributes (a few hundred null bedroom counts in a 500k-parcel universe is normal), so cross_val_score raises "Input X contains NaN" inside individual folds and emits hundreds of FitFailedWarnings per run. The failure is also silent. When only some folds fail, -scores.mean() is nan, and the caller in model_runner.py:get_variable_recommendations does: cv_score = calc_cross_validation_score(X, y) if cv_score < best_score: # nan < x is always False best_score = cv_score best_variables = curr_variables.copy() so best_variables is never updated and the cross-validation refinement of the variable set is inert on any dataset with a NaN anywhere in X. Adds a median-impute guard with the same UserWarning as the siblings, drops all-NaN columns (no median to impute from), and supports the np.ndarray half of the declared signature. Behaviour on NaN-free input is unchanged.
Contributor
|
Thank you for your contribution. I affirm that this contributor has signed the CLA Russell Richie seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
calc_elastic_net_regularization,calc_p_values_recursive_drop,calc_t_values_recursive_dropandcalc_vif_recursive_dropall median-impute NaN before their sklearn / statsmodels fits (#313, #316, #318).calc_cross_validation_scorewas missed.Real assessment data carries genuine missing building attributes — a few hundred null bedroom counts in a 500k-parcel universe is normal — so
cross_val_score(LinearRegression(), X, y, cv=5)raisesInput X contains NaNinside individual folds and emits hundreds ofFitFailedWarnings per run.The failure is silent as well as loud. When only some folds fail,
-scores.mean()isnan, and the caller inmodel_runner.py:get_variable_recommendationsdoes:so
best_variablesis never updated and the cross-validation refinement of the variable set is inert on any dataset with a NaN anywhere inX.What this PR does
Adds the same median-impute guard and
UserWarningthe sibling helpers carry, plus two things they don't need:np.ndarrayhalf of the declaredX: pd.DataFrame | np.ndarraysignature is handled.Behaviour on NaN-free input is unchanged (asserted in the test).
Test added:
tests/test_stats.py::test_cross_validation_score_with_nan— NaN feature column, all-NaN column, and ndarray path.Separate observation, deliberately not fixed here
This patch alone changes no model output, because the CV refinement is disconnected at both ends.
get_variable_recommendationshas exactly two call sites:try_variablescalls it withdo_cross=True, then doesbest_variables = var_recs["variables"]and never reads that variable again — oneStore, zeroLoads atmodel_runner.py:434, confirmed by AST rather than by eye. Onlydf_resultsescapes, toout/try/<group>/<status>.csv; thereportis built butfinish_reportonly runs whendo_report=True.run_one_model— the only path whosevariablesactually becomesind_vars— passesdo_cross=False.So the CV loop runs where its answer is discarded, and is skipped where the answer would matter. (Confirmed downstream on our data: every model group's saved feature list is byte-identical to its configured
ind_vars.)Whether
try_variablesshould use its own CV result, or whether auto-reduce should enabledo_cross, changes which variables models actually train on — that seemed like your call rather than something to decide in a NaN-handling PR. Happy to follow up with whichever you prefer.Found while running Philadelphia OPA data through the pipeline.
🤖 Generated with Claude Code