← Back to case study

PROJECT 036 · PYTHON SOURCE

Unsupervised chemistry profiles

Study-specific code. Shared modules, dependency versions, and reproduction instructions are included in all project files.

Download Python file ↓
from pathlib import Path
import sys
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
import numpy as np
import pandas as pd
from scipy.stats import spearmanr
from sklearn.decomposition import PCA
from sklearn.ensemble import IsolationForest
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import confusion_matrix, precision_score, recall_score
from portfolio.data import load
from portfolio.constants import *
from portfolio.methods import result, sql, rates, associations, distribution, regression, classification, cluster
from portfolio.engine import execute

META = {'id': 36, 'dataset': 'wine', 'title': 'Unsupervised chemistry profiles', 'question': 'Do chemistry-based clusters differ in their sensory-score distributions?', 'method': 'Four K-means groups on standardized log chemical measurements; sensory labels excluded during fitting.', 'action': 'Inspect chemical profiles without assigning quality meanings to cluster numbers.', 'limitations': 'Sensory scores are ordinal and concentrated in the middle. Producer and batch IDs are unavailable. Associations are not recipes for changing quality or evidence of market price. '}

def analyze():
    df = load('wine').copy()
    features=[c for c in WINE_FEATURES if c!='wine_type']
    profiles,tagged,sil=cluster(df,features,k=4)
    t=tagged.groupby('cluster').agg(samples=('quality','size'),mean_quality=('quality','mean'),higher_rated_share=('quality',lambda s:s.ge(7).mean()),red_share=('wine_type',lambda s:s.eq('red').mean())).reset_index()
    out=result(t,'cluster','mean_quality','Sensory score',f'Exploratory silhouette={sil:.3f}; K=4 was fixed before fitting. Clusters may mainly reflect wine type.',extra={'chemistry_profiles':profiles})
    return out

if __name__ == "__main__":
    execute(Path(__file__).parent, META, analyze)