ppscore

repository·master·Indexed 22 days ago

https://github.com/8080labs/ppscore

A Python implementation of the Predictive Power Score (PPS), a data-type-agnostic metric used to detect both linear and non-linear relationships between variables. It provides a robust alternative to traditional correlation matrices, using Decision Trees to calculate a score from 0 to 1. The library supports calculating scores for single pairs of columns via `ppscore.score` or generating a full relationship matrix via `ppscore.matrix` for pandas DataFrames.

Tokens
3.6K
Snippets
12
Records
18
Agent score
76%

What's inside ppscore

  1. Understanding PPS special cases: valid and invalid scores

    master

    The PPS implementation identifies specific data scenarios to either optimize computation or signal unsupported inputs.

    Valid scores (Optimized to 0 or 1)

    These cases return a score without fitting a model:

    • feature_is_id: Categoric feature where all categories appear only once. Score: 0.
    • target_is_id: Categoric target where all categories appear only once. Score: 0.
    • target_is_constant: Target column has only one unique value. Score: 0.
    • predict_itself: Feature and target columns are identical. Score: 1.

    Invalid scores (Returns invalid_score)

    These cases indicate the PPS cannot be calculated:

    • target_is_datetime: Target is a datetime type (Solution: convert to string).
    • target_data_type_not_supported: Target has an unsupported data type.
    • empty_dataframe_after_dropping_na: No rows remain after dropping NaNs (Solution: handle missing values first).
    • unknown_error: An unexpected error occurred. This is only reported if catch_errors=True. To debug, set catch_errors=False to see the actual exception.
  2. How classification vs regression is determined in ppscore

    master

    The PPS calculation logic (classification vs regression) is automatically determined by the pandas dtype of the target column. To switch between modes, you must change the data type of the target column.

    • Classification: Chosen if the target has the dtype object, category, string, or boolean.
    • Regression: Chosen if the target has the dtype float or int.

    Metric Logic:

    • Regression uses Mean Absolute Error (MAE). The PPS is normalized as: 1 - (MAE_model / MAE_naive), where MAE_naive is the MAE of a model predicting the median.
    • Classification uses the weighted F1 score (wF1). The PPS is normalized as: (F1_model - F1_naive) / (1 - F1_naive), where F1_naive is the maximum of a model predicting the most common class and a random model.
  3. How the Predictive Power Score (PPS) is calculated

    master

    The PPS is a bivariate metric that measures how well a single feature can predict a target column. Key aspects of the calculation include:

    • No Interaction Effects: Unlike feature importance, PPS calculates scores for each feature independently. It does not account for interactions between multiple features.
    • Cross-Validation: Scores are calculated using the test sets of a $K$-fold cross-validation (default is 4). For classification, stratifiedKFold is used; for regression, KFold is used.
    • Sampling: To optimize performance, if the dataset exceeds 5,000 rows, a random subset of 5,000 rows is used by default. This can be adjusted via the sample parameter.
    • Missing Values: Rows containing missing values in either the feature or the target column are dropped before calculation.
    • Reproducibility: Because the process involves random sampling and shuffling, use the random_seed parameter to ensure reproducible results.
    • Error Handling: If a score cannot be calculated, the package returns an object where is_valid_score is False and the score is set to invalid_score. This prevents the entire process from crashing when scanning large datasets.
  4. How the PPS learning algorithm works

    master

    The core learning algorithm used is a Decision Tree, chosen for its ability to detect non-linear bivariate relationships, robustness to outliers, and speed.

    Implementation Details:

    • Regression: If the target is numeric, sklearn.DecisionTreeRegressor is used.
    • Classification: If the target is categoric, sklearn.DecisionTreeClassifier is used.

    Preprocessing:

    • If the target is categoric (object, category, string, or boolean), it is processed using sklearn.LabelEncoder.
    • If the feature is categoric, it is processed using sklearn.OneHotEncoder.
  5. Determine the best naive predictor for F1 score

    master

    When evaluating performance metrics like the F1 score, you can establish a baseline by comparing two naive predictors: the 'most common value' and 'random guessing'.

    Key observations for choosing a baseline:

    • Skewed classes (2 classes): The most common value is often slightly better than a random guess.
    • Skewed classes (4 classes): A random guess is often slightly better than the most common value.
    • Balanced classes (2 or 4 classes): Random guessing is usually significantly better than the most common value.

    Conclusion: Random values are generally preferred over the most common value as a baseline. However, the most robust baseline is the maximum of the F1 score achieved by the most common value and the F1 score achieved by random values.

    import numpy as np
    import pandas as pd
    from sklearn.metrics import f1_score
    
    # Example helper for most common value baseline
    def f1_score_most_common(series, value):
        # Note: In practice, use the actual length of the series instead of hardcoded 1000
        return f1_score(series, np.random.choice([value], len(series)), average="weighted")
    
    # Example helper for random baseline
    def f1_score_random(series):
        return f1_score(series, series.sample(frac=1), average="weighted")
  6. Visualize PPS results with Seaborn

    master

    You can visualize PPS results using seaborn or other visualization libraries.

    Plotting Predictors: To plot the predictive power of all features against a target, use pps.predictors and pass the resulting DataFrame to sns.barplot.

    Plotting a PPS Matrix: To create a heatmap of the PPS matrix, you must first pivot the tidy DataFrame returned by pps.matrix so that columns and indices match the expected heatmap format.

    Example:

    import seaborn as sns
    import ppscore as pps
    
    # Plotting predictors
    predictors_df = pps.predictors(df, y="y")
    sns.barplot(data=predictors_df, x="x", y="ppscore")
    
    # Plotting matrix heatmap
    matrix_df = pps.matrix(df)[['x', 'y', 'ppscore']].pivot(columns='x', index='y', values='ppscore')
    sns.heatmap(matrix_df, vmin=0, vmax=1, cmap="Blues", linewidths=0.5, annot=True)
    import seaborn as sns
    import ppscore as pps
    
    # Plotting predictors
    predictors_df = ppscore.predictors(df, y="y")
    sns.barplot(data=predictors_df, x="x", y="ppscore")
    
    # Plotting matrix heatmap
    matrix_df = ppscore.matrix(df)[['x', 'y', 'ppscore']].pivot(columns='x', index='y', values='ppscore')
    sns.heatmap(matrix_df, vmin=0, vmax=1, cmap="Blues", linewidths=0.5, annot=True)
  7. Calculate the PPS for a single pair of columns

    master

    Use ppscore.score(df, x, y) to calculate the Predictive Power Score for a specific feature x predicting a target y.

    Key Concepts:

    • The score ranges from 0 (no predictive power) to 1 (perfect predictive power).
    • It is asymmetric and data-type agnostic, meaning it can detect both linear and non-linear relationships.
    • A score of 0 means x cannot predict y better than a naive baseline.

    Parameters:

    • df: pandas.DataFrame containing the columns.
    • x: str, the name of the feature column.
    • y: str, the name of the target column.
    • sample: int or None. Number of rows to sample to decrease calculation time. If None, no sampling occurs.
    • cross_validation: int. Number of iterations for cross-validation. Higher values require more observations to avoid errors.
    • random_seed: int or None. Set for reproducible results.
    • invalid_score: any. Value returned if calculation is invalid (e.g., unsupported data type).
    • catch_errors: bool. If True, errors are caught and reported as unknown_error. If False, exceptions are raised.
    import ppscore as pps
    # Calculate PPS for x predicting y
    result = pps.score(df, "x", "y")
  8. Calculate the PPS matrix for all columns

    master

    Use ppscore.matrix(df, ...) to calculate the PPS between every pair of columns in the DataFrame, creating a full matrix of scores.

    Parameters:

    • df: pandas.DataFrame containing the data.
    • output: str. Either `
  9. Calculate PPS for all predictors against a target

    master

    Use ppscore.predictors(df, y, ...) to find the predictive power of all columns in a DataFrame against a specific target column y.

    Parameters:

    • df: pandas.DataFrame containing the data.
    • y: str, the name of the target column.
    • output: str. Either `
  10. Compare PPS matrix with a Correlation matrix

    master

    You can compare the non-linear predictive power captured by PPS against traditional linear correlation using df.corr() and seaborn.heatmap.

    import seaborn as sns
    
    def corr_heatmap(df):
        # Correlation values range from -1 to 1
        ax = sns.heatmap(df, vmin=-1, vmax=1, cmap="BrBG", linewidths=0.5, annot=True)
        ax.set_title("Correlation matrix")
        return ax
    
    # Usage with standard pandas correlation
    corr_heatmap(df.corr())