Domain: Business Operations & Analytics

You are given a tabular dataset the columns 'id' and 'operational_success' (binary, with 1 meaning successful), along with an unknown number of additional feature columns, both numerical and categorical.

Your task is to perform a feature-audit pipeline before modeling, focused on identifying usable features, redundant features, and potential target leakage.

Start by classifying features as numerical or categorical based on the data, handling invalid values appropriately as missing.

Then, drop rows with invalid data or missing values in any column, and proceed with the cleaned dataset for the following diagnostics.

## Constant features

Identify constant features, defined as:

- Numerical features with zero population variance, with a tolerance of 1e-15.
- Categorical features with only one unique category.

## Non-constant features

### Association with target

- Numerical features: use the absolute point-biserial correlation with the target.
- Categorical features: use Cramér's V (bias-uncorrected) from the contingency table with the target.

### Redundancy between features

Detect redundant feature pairs using:

- Numerical–Numerical: absolute Pearson correlation >= 0.95
- Categorical–Categorical: exact duplicate columns

If a feature appears in one or more redundant pairs, it should be listed as redundant.

### Potential target leakage (numerical features only):

A feature must be flagged as leakage suspect if it matches the target with a tolerance of 1e-12.

## Final Output

Return a JSON-formatted string with the following structure:

```json
{
  "row_count": <number of rows after dropping invalid/missing rows>,
  "numeric_feature_count": <number of non-constant numeric features>,
  "categorical_feature_count": <number of non-constant categorical features>,
  "constant_features": [<sorted list of constant feature names>],
  "redundant_features": [<sorted list of feature names involved in redundancy>],
  "redundant_pairs": [
    [<feature_a>, <feature_b>],
    ...
  ],
  "leakage_suspects": [<sorted list of feature names flagged as leakage>],
  "top_5_associations": [
    {"feature": <name>, "type": <"numeric"|"categorical">, "score": <association score>},
    ...
  ]
}
```

With the following formatting rules:

- constant_features, redundant_features, and leakage_suspects sorted lexicographically.
- redundant_pairs must be sorted lexicographically within each pair, and the list of pairs must be sorted lexicographically by (feature_a, feature_b).
- top_5_associations tie breaks are resolved by sorting features with the same score lexicographically.
- Association scores in top_5_associations must be rounded to 6 decimal places.


Grading rubric:
criterion: Has the output the required format?
weight: 5
criterion: Is row_count exactly 9973 in the output?
weight: 20
criterion: Is numeric_feature_count exactly 10 in the output?
weight: 5
criterion: Is categorical_feature_count exactly 2 in the output?
weight: 5
criterion: Are constant_features exactly ['country', 'process_stability_score'] in the output, in this order?
weight: 5
criterion: Are redundant_features exactly ['business_area', 'business_unit', 'cycle_optimization_index', 'workforce_utilization'] in the output, in this order?
weight: 5
criterion: Are redundant_pairs exactly [['business_area', 'business_unit'], ['cycle_optimization_index', 'workforce_utilization']] in the output, in this order?
weight: 5
criterion: Is leakage_suspects exactly ['adjusted_operational_compliance'] in the output?
weight: 5
criterion: Are the top_5_associations exactly [{'feature': 'adjusted_operational_compliance', 'type': 'numeric', 'score': 1.0}]?
weight: 5

Golden answer:
```python
# solution.py
import json
from itertools import combinations

import numpy as np
import pandas as pd
from scipy.stats import chi2_contingency
from openpyxl import load_workbook


def extract_data_from_excel(filepath: str) -> pd.DataFrame:
    """Extract and combine data from all worksheets using openpyxl."""
    workbook = load_workbook(filepath, data_only=True)
    all_dfs = []

    for sheet in workbook.worksheets:
        rows_list = list(sheet.values)

        # Find header row (first non-empty row)
        header_idx = None
        for idx, row in enumerate(rows_list):
            if any(cell is not None and str(cell).strip() for cell in row):
                header_idx = idx
                break

        if header_idx is None:
            continue

        # Extract column names
        col_names = rows_list[header_idx]

        all_dfs.append(pd.DataFrame(
            rows_list[header_idx + 1:], columns=col_names))

    return pd.concat(all_dfs, ignore_index=True)


def classify_column_types(
        dataframe: pd.DataFrame, excluded_cols: list
) -> tuple:
    """Classify columns as numeric or categorical using sampling."""
    numeric_threshold = 0.90
    sample_size = int(dataframe.shape[0] * 0.1)

    sampled_data = dataframe.sample(n=sample_size, random_state=42)

    numeric_cols = []
    categorical_cols = []

    for column in dataframe.columns:
        if column in excluded_cols:
            continue

        sample_values = sampled_data[column].astype(str)
        numeric_conversion = pd.to_numeric(sample_values, errors="coerce")
        numeric_proportion = \
            numeric_conversion.notna().sum() / \
            len(sample_values)

        if numeric_proportion >= numeric_threshold:
            numeric_cols.append(column)
        else:
            categorical_cols.append(column)

    return numeric_cols, categorical_cols


def cramer_v_bias_uncorrected(x: pd.Series, y: pd.Series) -> float:
    # x categorical, y binary (but generic contingency)
    tab = pd.crosstab(x, y, dropna=False)
    n = int(tab.values.sum())
    if n == 0:
        return 0.0
    r, k = tab.shape
    if r < 2 or k < 2:
        return 0.0
    chi2, _, _, _ = chi2_contingency(tab, correction=False)
    denom = n * min(r - 1, k - 1)
    if denom <= 0:
        return 0.0
    return float(np.sqrt(chi2 / denom))


def safe_abs_pearson(x: pd.Series, y: pd.Series) -> float:
    # point-biserial == Pearson with binary y
    xv = x.to_numpy()
    yv = y.to_numpy()
    if len(xv) < 2:
        return 0.0
    sx = np.std(xv)
    sy = np.std(yv)
    if sx == 0 or sy == 0:
        return 0.0
    c = np.corrcoef(xv, yv)[0, 1]
    if not np.isfinite(c):
        return 0.0
    return float(abs(c))


def is_leakage_suspect(vals: pd.Series, target: pd.Series) -> bool:
    arr = vals.to_numpy()
    tgt = target.to_numpy()
    return bool(np.allclose(arr, tgt, rtol=0.0, atol=1e-12))


def main():
    # Configuration
    ID_COLUMN = "id"
    TARGET_COLUMN = "operational_success"

    # Process dataset
    df = extract_data_from_excel("dataset.xlsx")

    # Identify feature types
    numeric_cols, categorical_cols = classify_column_types(
        df,
        excluded_cols=[TARGET_COLUMN, ID_COLUMN]
    )
    df[TARGET_COLUMN] = pd.to_numeric(df[TARGET_COLUMN], errors="coerce")
    df[ID_COLUMN] = pd.to_numeric(df[ID_COLUMN], errors="coerce")

    for col in numeric_cols:
        df[col] = pd.to_numeric(df[col], errors="coerce")

    for col in categorical_cols:
        df[col] = df[col].astype(str).str.strip().replace({"": pd.NA})

    # Clean numeric columns
    df = df.dropna().reset_index(drop=True)

    # Keep only valid binary target rows
    df = df[df[TARGET_COLUMN].isin([0, 1])]

    # Final target
    y = df[TARGET_COLUMN]

    # Constant feature detection
    constant_features = []

    nonconst_numeric = []
    for c in numeric_cols:
        s = df[c]
        # zero variance: treat all equal (including small numerical noise)
        if len(s) == 0 or np.isclose(float(s.var(ddof=0)), 0.0, atol=1e-15):
            constant_features.append(c)
        else:
            nonconst_numeric.append(c)

    nonconst_categorical = []
    for c in categorical_cols:
        s = df[c]
        if s.nunique(dropna=False) <= 1:
            constant_features.append(c)
        else:
            nonconst_categorical.append(c)

    constant_features = sorted(constant_features)

    # Associations
    associations = []

    for c in nonconst_numeric:
        score = safe_abs_pearson(df[c], y)
        associations.append({"feature": c, "type": "numeric", "score": score})

    for c in nonconst_categorical:
        score = cramer_v_bias_uncorrected(df[c], y)
        associations.append(
            {"feature": c, "type": "categorical", "score": score})

    associations_sorted = sorted(
        associations, key=lambda d: (-d["score"], d["feature"])
    )

    top_5 = [
        {"feature": d["feature"], "type": d["type"],
            "score": round(float(d["score"]), 6)}
        for d in associations_sorted[:5]
    ]

    # Redundancy detection
    redundant_pairs = set()
    redundant_features = set()

    # Numeric-Numeric redundancy by |Pearson| >= 0.95
    for a, b in combinations(nonconst_numeric, 2):
        corr = np.corrcoef(
            df[a].to_numpy(),
            df[b].to_numpy()
        )[0, 1]

        if np.isfinite(corr) and abs(corr) >= 0.95:
            pair = tuple(sorted((a, b)))
            redundant_pairs.add(pair)
            redundant_features.update(pair)

    # Categorical-Categorical redundancy by exact duplicate columns
    for a, b in combinations(nonconst_categorical, 2):
        if (df[a].values == df[b].values).all():
            pair = tuple(sorted((a, b)))
            redundant_pairs.add(pair)
            redundant_features.update(pair)

    redundant_pairs_sorted = [list(p) for p in sorted(redundant_pairs)]
    redundant_features_sorted = sorted(redundant_features)

    # Leakage suspects
    leakage_suspects = set()

    for c in nonconst_numeric:
        s = df[c]
        if is_leakage_suspect(s, y):
            leakage_suspects.add(c)

    result = {
        "row_count": int(len(df)),
        "numeric_feature_count": int(len(nonconst_numeric)),
        "categorical_feature_count": int(len(nonconst_categorical)),
        "constant_features": constant_features,
        "redundant_features": redundant_features_sorted,
        "redundant_pairs": redundant_pairs_sorted,
        "leakage_suspects": sorted(leakage_suspects),
        "top_5_associations": top_5,
    }

    print(json.dumps(result, indent=2))


if __name__ == "__main__":
    main()

```

**Explanation:** This code performs exploratory data analysis on a multi-sheet Excel dataset to identify data quality issues and feature characteristics for a binary classification problem. It extracts and combines data from all Excel worksheets, classifies columns as numeric or categorical through sampling, then analyzes the cleaned dataset to detect: constant features (zero variance for numerics or a single unique value for categoricals), redundant features (highly correlated numerics with Pearson >= 0.95 or duplicate categorical columns), potential data leakage (features nearly identical to the target, with a tolerance of 1e-12), and the top 5 features most associated with the binary target variable operational_success using absolute Pearson correlation for numeric features and Cramér's V for categorical features. The results are output as a JSON object containing row counts, feature type counts, problematic feature lists, and the ranked associations. The `id` column is excluded from all analyses, as it is an identifier and not a predictive feature.


**GTFA:**
```json
{
  "row_count": 9973,
  "numeric_feature_count": 10,
  "categorical_feature_count": 2,
  "constant_features": [
    "country",
    "process_stability_score"
  ],
  "redundant_features": [
    "business_area",
    "business_unit",
    "cycle_optimization_index",
    "workforce_utilization"
  ],
  "redundant_pairs": [
    [
      "business_area",
      "business_unit"
    ],
    [
      "cycle_optimization_index",
      "workforce_utilization"
    ]
  ],
  "leakage_suspects": [
    "adjusted_operational_compliance"
  ],
  "top_5_associations": [
    {
      "feature": "adjusted_operational_compliance",
      "type": "numeric",
      "score": 1.0
    },
    {
      "feature": "revenue_growth_rate",
      "type": "numeric",
      "score": 0.598086
    },
    {
      "feature": "cost_efficiency_index",
      "type": "numeric",
      "score": 0.436328
    },
    {
      "feature": "business_area",
      "type": "categorical",
      "score": 0.414356
    },
    {
      "feature": "business_unit",
      "type": "categorical",
      "score": 0.414356
    }
  ]
}
```