Project_Carmignac/brouillon/.ipynb_checkpoints/clustering-checkpoint.ipynb

3026 lines
3.6 MiB
Plaintext
Raw Permalink Normal View History

2026-04-07 20:26:19 +02:00
{
"cells": [
{
"cell_type": "markdown",
"id": "aa4cb7c9-15d7-466b-a473-d5eb42cb5587",
"metadata": {},
"source": [
"IMPORTS & CONFIGURATION"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "b4fd8626-44a3-4116-af2f-3637b6fd4bbd",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import s3fs\n",
"import warnings\n",
"warnings.filterwarnings(\"ignore\")\n",
"\n",
"os.environ[\"AWS_ACCESS_KEY_ID\"] = 'UMMV3Z72A70MCCSRV17O'\n",
"os.environ[\"AWS_SECRET_ACCESS_KEY\"] = 'wBFxaez78UPNW3BtchZOf4f238ZNXKnCexeGufaa'\n",
"os.environ[\"AWS_SESSION_TOKEN\"] = 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJVTU1WM1o3MkE3ME1DQ1NSVjE3TyIsImFjciI6IjAiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJhdWQiOlsibWluaW8iLCJhY2NvdW50Il0sImF1dGhfdGltZSI6MTc3NTEzNTA4NiwiYXpwIjoib255eGlhLW1pbmlvIiwiZW1haWwiOiJzYXJhaC50aG91bXlyZUBlbnNhZS5mciIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJleHAiOjE3NzYzNDQ3NDksImZhbWlseV9uYW1lIjoiVEhPVU1ZUkUiLCJnaXZlbl9uYW1lIjoiU2FyYWgiLCJncm91cHMiOlsiYmRjLWRhdGEiLCJiZGMtY2FybWlnbmFjLWczIl0sImlhdCI6MTc3NTEzNTE0OCwiaXNzIjoiaHR0cHM6Ly9hdXRoLmdyb3VwZS1nZW5lcy5mci9yZWFsbXMvZ2VuZXMiLCJqdGkiOiJlZGY1ZDQ1OC1hYzkxLTQ5NTAtYmI5Ny0zNjMwNWY1MTQwYTIiLCJuYW1lIjoiU2FyYWggVEhPVU1ZUkUiLCJwb2xpY3kiOiJzdHNvbmx5IiwicHJlZmVycmVkX3VzZXJuYW1lIjoic3Rob3VteXJlLWVuc2FlIiwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwiZGVmYXVsdC1yb2xlcy1nZW5lcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsInNpZCI6IjMzMjg4YjJjLTlhMjAtNDNhOS1iMDlhLTdlMjc1OWQ1NjIxNiIsInN1YiI6ImVhYWVkN2QyLWM4MjYtNGIxNC05MzczLTYwYjNhODhlMWFiNiIsInR5cCI6IkJlYXJlciJ9.rffoTJijRiGK2DCDhXj5y8R31DRH1LWkTwuH_1lvU9qN_xJSTmBIM4uGR_zp7XpMnq_ePwVhlkoWN15cNUgjMA'\n",
"os.environ[\"AWS_DEFAULT_REGION\"] = 'us-east-1'\n",
"fs = s3fs.S3FileSystem(\n",
" client_kwargs={'endpoint_url': 'https://'+'minio-simple.lab.groupe-genes.fr'},\n",
" key = os.environ[\"AWS_ACCESS_KEY_ID\"], \n",
" secret = os.environ[\"AWS_SECRET_ACCESS_KEY\"], \n",
" token = os.environ[\"AWS_SESSION_TOKEN\"])\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"\n",
"from sklearn.preprocessing import RobustScaler\n",
"from sklearn.cluster import KMeans\n",
"from sklearn.metrics import (\n",
" silhouette_score, davies_bouldin_score,\n",
" pairwise_distances, adjusted_rand_score\n",
")\n",
"from sklearn.linear_model import LinearRegression\n",
"\n",
"sns.set_style(\"whitegrid\")\n",
"pd.set_option(\"display.max_columns\", 200)\n",
"pd.set_option(\"display.max_rows\", 200)\n",
"\n",
"EPS = 1e-9\n",
"RANDOM_STATE = 42"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "57e7d14d-db0f-4fbb-b4d8-21e0f4c14dff",
"metadata": {},
"outputs": [],
"source": [
"# Column names\n",
"ID_COL = \"Registrar Account - ID\"\n",
"ISIN_COL = \"Product - Isin\"\n",
"FUND_COL = \"Product - Fund\"\n",
"ASSET_COL = \"Product - Asset Type\"\n",
"FLOW_DATE_COL = \"Centralisation Date\"\n",
"AUM_DATE_COL = \"Centralisation Date\"\n",
"FLOW_QTY_COL = \"Quantity - NetFlows\"\n",
"FLOW_SUB_COL = \"Quantity - Subscription\"\n",
"FLOW_RED_COL = \"Quantity - Redemption\"\n",
"AUM_QTY_COL = \"Quantity - AUM\"\n",
"AUM_VAL_COL = \"Value - AUM €\"\n",
"REGION_COL = \"Registrar Account - Region\"\n",
"COUNTRY_COL = \"RegistrarAccount - Country\"\n",
"NAV_DATE_COL = \"Dat\"\n",
"NAV_ISIN_COL = \"Isin\"\n",
"NAV_PRICE_COL = \"Price (TF PartPrice)\"\n",
"NAV_BENCH_COL = \"PriceBench\"\n",
"RATE_DATE_COL = \"Date\"\n",
"RATE_VAL_COL = \"Yld to Maturity\"\n",
"\n",
"PATH_NAV = \"s3://projet-bdc-data/carmignac/Data Modélisation/Nav/NAV_Bench_data.csv\"\n",
"PATH_RATES = \"s3://projet-bdc-data/carmignac/Data Modélisation/market data/esterRates.csv\""
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "27b7b71b-6792-4abd-bca1-3911c7d19066",
"metadata": {},
"outputs": [],
"source": [
"# ============================================================\n",
"# UTILITAIRES \n",
"# ============================================================\n",
"def robust_zscore(s):\n",
" med = np.nanmedian(s)\n",
" mad = np.nanmedian(np.abs(s - med))\n",
" if mad == 0 or np.isnan(mad):\n",
" return np.zeros(len(s))\n",
" return (s - med) / (1.4826 * mad)\n",
"\n",
"def plot_heatmap(dfc, profile_vars, cluster_col, title, figsize=(16, 4)):\n",
" \"\"\"Heatmap des signatures de clusters avec z-score robuste et cap à ±3.\"\"\"\n",
" dfc_viz = dfc[profile_vars + [cluster_col]].copy()\n",
" for col in profile_vars:\n",
" vals = pd.to_numeric(dfc_viz[col], errors=\"coerce\").to_numpy(dtype=float)\n",
" lo = np.nanpercentile(vals, 2)\n",
" hi = np.nanpercentile(vals, 98)\n",
" dfc_viz[col] = np.clip(vals, lo, hi)\n",
" prof = dfc_viz.groupby(cluster_col)[profile_vars].median()\n",
" prof_z = prof.apply(lambda col: robust_zscore(col.values), axis=0)\n",
" prof_z = prof_z.clip(-3, 3) # cap pour lisibilité\n",
" plt.figure(figsize=figsize)\n",
" sns.heatmap(prof_z, cmap=\"RdBu_r\", center=0, annot=True, fmt=\".2f\",\n",
" xticklabels=profile_vars,\n",
" yticklabels=[f\"Cluster {i}\" for i in range(len(prof))])\n",
" plt.title(title)\n",
" plt.xticks(rotation=45, ha=\"right\")\n",
" plt.tight_layout()\n",
" plt.show()\n",
" return prof\n",
"\n",
"def winsorize_mad(series, n_sigma=3):\n",
" \"\"\"Clip MAD n sigma. Si MAD~0, clip au p95.\"\"\"\n",
" vals = pd.to_numeric(series, errors=\"coerce\").to_numpy(dtype=float)\n",
" med = np.nanmedian(vals)\n",
" mad = np.nanmedian(np.abs(vals - med)) * 1.4826\n",
" if mad > 0:\n",
" return np.clip(vals, med - n_sigma * mad, med + n_sigma * mad)\n",
" else:\n",
" return np.clip(vals, 0, np.nanpercentile(vals, 95))\n",
"\n",
"def add_months_since_last_tx(dfc, df_month, id_col, suffix=\"\"):\n",
" \"\"\"Ajoute months_since_last_tx[suffix] à dfc.\"\"\"\n",
" col_name = f\"months_since_last_tx{suffix}\"\n",
" reference_date = df_month[\"month\"].max()\n",
" last_active = (\n",
" df_month[df_month[\"active_month\"] == 1]\n",
" .groupby(id_col)[\"month\"]\n",
" .max()\n",
" .reset_index(name=\"last_active_month\")\n",
" )\n",
" last_active[col_name] = (\n",
" (reference_date.to_period(\"M\") -\n",
" last_active[\"last_active_month\"].dt.to_period(\"M\"))\n",
" .apply(lambda x: x.n)\n",
" )\n",
" dfc = dfc.merge(last_active[[id_col, col_name]], on=id_col, how=\"left\")\n",
" max_months = dfc[col_name].max()\n",
" dfc[col_name] = dfc[col_name].fillna(max_months + 1)\n",
" return dfc"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "90b6f9a5-9eb8-439c-8d6e-4f459aa613f9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"flows: (2574461, 26)\n",
"aum: (4824814, 19)\n",
"nav: (623914, 6)\n"
]
}
],
"source": [
"# ============================================================\n",
"# 1. DATA LOADING\n",
"# ============================================================\n",
"df_flows = pd.read_csv(\"flows.csv\", low_memory=False)\n",
"df_aum = pd.read_csv(\n",
" \"s3://projet-bdc-carmignac-g3/paco/AUM_repaired.csv\", low_memory=False\n",
")\n",
"df_nav = pd.read_csv(PATH_NAV, sep=\";\")\n",
"df_rates = pd.read_csv(PATH_RATES, sep=\";\")\n",
"\n",
"# Date parsing\n",
"for df, col in [\n",
" (df_flows, FLOW_DATE_COL), (df_aum, AUM_DATE_COL),\n",
" (df_nav, NAV_DATE_COL), (df_rates, RATE_DATE_COL)\n",
"]:\n",
" df[col] = pd.to_datetime(df[col], errors=\"coerce\")\n",
" df[\"month\"] = df[col].dt.to_period(\"M\").dt.to_timestamp()\n",
"\n",
"for col in [FLOW_QTY_COL, FLOW_SUB_COL, FLOW_RED_COL]:\n",
" df_flows[col] = pd.to_numeric(df_flows[col], errors=\"coerce\")\n",
"for col in [AUM_QTY_COL, AUM_VAL_COL]:\n",
" df_aum[col] = pd.to_numeric(df_aum[col], errors=\"coerce\")\n",
"for col in [NAV_PRICE_COL, NAV_BENCH_COL]:\n",
" df_nav[col] = pd.to_numeric(df_nav[col], errors=\"coerce\")\n",
"df_rates[RATE_VAL_COL] = pd.to_numeric(df_rates[RATE_VAL_COL], errors=\"coerce\")\n",
"\n",
"for df in [df_flows, df_aum]:\n",
" df[ISIN_COL] = df[ISIN_COL].astype(str).str.strip()\n",
"df_nav[NAV_ISIN_COL] = df_nav[NAV_ISIN_COL].astype(str).str.strip()\n",
"\n",
"# Filtrer les comptes techniques\n",
"df_flows = df_flows[~df_flows[ID_COL].isin(\n",
" [\"Off Distribution\", \"Private Clients\", \"Private Client\"]\n",
")]\n",
"df_aum = df_aum[~df_aum[ID_COL].isin(\n",
" [\"Off Distribution\", \"Private Clients\", \"Private Client\"]\n",
")]\n",
"\n",
"print(\"flows:\", df_flows.shape)\n",
"print(\"aum: \", df_aum.shape)\n",
"print(\"nav: \", df_nav.shape)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "339c6c5d-4ebc-447c-a8c5-022de42ca752",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Panel shape: (4754355, 24)\n"
]
}
],
"source": [
"# ============================================================\n",
"# 2. MONTHLY PANEL CONSTRUCTION\n",
"# ============================================================\n",
"df_flows_m = (\n",
" df_flows\n",
" .dropna(subset=[ID_COL, ISIN_COL, \"month\"])\n",
" .assign(\n",
" gross_flow_qty = lambda x: x[FLOW_QTY_COL].abs(),\n",
" sub_qty = lambda x: x[FLOW_SUB_COL].fillna(0),\n",
" red_qty = lambda x: x[FLOW_RED_COL].fillna(0)\n",
" )\n",
" .groupby([ID_COL, ISIN_COL, \"month\"], as_index=False)\n",
" .agg(\n",
" net_flow_qty = (FLOW_QTY_COL, \"sum\"),\n",
" gross_flow_qty = (\"gross_flow_qty\", \"sum\"),\n",
" sub_qty = (\"sub_qty\", \"sum\"),\n",
" red_qty = (\"red_qty\", \"sum\"),\n",
" n_tx = (FLOW_QTY_COL, \"size\"),\n",
" region = (REGION_COL, \"last\"),\n",
" country = (COUNTRY_COL, \"last\")\n",
" )\n",
")\n",
"\n",
"df_aum_m = (\n",
" df_aum\n",
" .dropna(subset=[ID_COL, ISIN_COL, \"month\"])\n",
" .groupby([ID_COL, ISIN_COL, \"month\"], as_index=False)\n",
" .agg(\n",
" aum_qty = (AUM_QTY_COL, \"sum\"),\n",
" aum_val = (AUM_VAL_COL, \"sum\"),\n",
" fund = (FUND_COL, \"last\"),\n",
" asset_type = (ASSET_COL, \"last\"),\n",
" region = (REGION_COL, \"last\"),\n",
" country = (COUNTRY_COL, \"last\")\n",
" )\n",
")\n",
"\n",
"keys = pd.concat([\n",
" df_flows_m[[ID_COL, ISIN_COL, \"month\"]],\n",
" df_aum_m[[ID_COL, ISIN_COL, \"month\"]]\n",
"]).drop_duplicates()\n",
"\n",
"df_rel_m = (\n",
" keys\n",
" .merge(df_aum_m, on=[ID_COL, ISIN_COL, \"month\"], how=\"left\")\n",
" .merge(df_flows_m, on=[ID_COL, ISIN_COL, \"month\"], how=\"left\",\n",
" suffixes=(\"\", \"_flow\"))\n",
")\n",
"\n",
"for c in [\"aum_qty\",\"aum_val\",\"net_flow_qty\",\"gross_flow_qty\",\n",
" \"sub_qty\",\"red_qty\",\"n_tx\"]:\n",
" df_rel_m[c] = df_rel_m[c].fillna(0)\n",
"\n",
"df_rel_m[\"region\"] = df_rel_m[\"region\"].fillna(df_rel_m.get(\"region_flow\"))\n",
"df_rel_m[\"country\"] = df_rel_m[\"country\"].fillna(df_rel_m.get(\"country_flow\"))\n",
"df_rel_m[\"active_rel_month\"] = (df_rel_m[\"gross_flow_qty\"] > 0).astype(int)\n",
"df_rel_m[\"holding_rel_month\"] = (df_rel_m[\"aum_qty\"] > 0).astype(int)\n",
"df_rel_m[\"flow_to_aum_rel\"] = df_rel_m[\"net_flow_qty\"] / (df_rel_m[\"aum_qty\"].abs() + EPS)\n",
"df_rel_m[\"turnover_rel\"] = df_rel_m[\"gross_flow_qty\"] / (df_rel_m[\"aum_qty\"].abs() + EPS)\n",
"\n",
"# NAV & rates\n",
"df_nav_m = (\n",
" df_nav\n",
" .dropna(subset=[NAV_ISIN_COL, \"month\", NAV_PRICE_COL])\n",
" .sort_values([NAV_ISIN_COL, \"month\"])\n",
" .groupby([NAV_ISIN_COL, \"month\"], as_index=False).tail(1).copy()\n",
")\n",
"df_nav_m[\"ret_fund_m\"] = df_nav_m.groupby(NAV_ISIN_COL)[NAV_PRICE_COL].pct_change()\n",
"df_nav_m[\"ret_bench_m\"] = df_nav_m.groupby(NAV_ISIN_COL)[NAV_BENCH_COL].pct_change()\n",
"df_nav_m[\"active_return_m\"] = df_nav_m[\"ret_fund_m\"] - df_nav_m[\"ret_bench_m\"]\n",
"df_nav_m = df_nav_m.rename(columns={NAV_ISIN_COL: ISIN_COL})[\n",
" [ISIN_COL, \"month\", \"ret_fund_m\", \"ret_bench_m\", \"active_return_m\"]\n",
"]\n",
"\n",
"df_rates_m = (\n",
" df_rates.dropna(subset=[\"month\", RATE_VAL_COL])\n",
" .sort_values(RATE_DATE_COL)\n",
" .groupby(\"month\", as_index=False).tail(1).copy()\n",
")\n",
"df_rates_m[\"delta_rate_m\"] = df_rates_m[RATE_VAL_COL].diff()\n",
"df_rates_m = df_rates_m[[\"month\", RATE_VAL_COL, \"delta_rate_m\"]]\n",
"\n",
"df_rel_m = df_rel_m.merge(df_nav_m, on=[ISIN_COL, \"month\"], how=\"left\")\n",
"df_rel_m = df_rel_m.merge(\n",
" df_rates_m[[\"month\", \"delta_rate_m\"]], on=\"month\", how=\"left\"\n",
")\n",
"for c in [\"ret_fund_m\",\"ret_bench_m\",\"active_return_m\",\"delta_rate_m\"]:\n",
" df_rel_m[c] = df_rel_m[c].fillna(0)\n",
"\n",
"print(\"Panel shape:\", df_rel_m.shape)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "80b93757-f141-4e94-80fa-4fc0538e0f1d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"df_month shape: (931089, 22)\n",
"ISIN-level client features: (12582, 12)\n",
"Asset shares: (7473, 6)\n",
"Fund shares: (6591, 11)\n",
"df_client_base shape: (12582, 47)\n"
]
}
],
"source": [
"# ============================================================\n",
"# 3. FEATURE ENGINEERING\n",
"# ============================================================\n",
"\n",
"# 3a. Panel mensuel\n",
"tmp = df_rel_m.copy()\n",
"tmp[\"isin_held_flag\"] = (tmp[\"aum_qty\"] > 0).astype(int)\n",
"tmp[\"isin_active_flag\"] = (tmp[\"gross_flow_qty\"] > 0).astype(int)\n",
"\n",
"df_month = (\n",
" tmp.groupby([ID_COL, \"month\"], as_index=False)\n",
" .agg(\n",
" aum_qty = (\"aum_qty\", \"sum\"),\n",
" aum_val = (\"aum_val\", \"sum\"),\n",
" net_flow_qty = (\"net_flow_qty\", \"sum\"),\n",
" gross_flow_qty = (\"gross_flow_qty\", \"sum\"),\n",
" sub_qty = (\"sub_qty\", \"sum\"),\n",
" red_qty = (\"red_qty\", \"sum\"),\n",
" n_tx = (\"n_tx\", \"sum\"),\n",
" n_isin_held = (\"isin_held_flag\", \"sum\"),\n",
" n_isin_active = (\"isin_active_flag\", \"sum\"),\n",
" delta_rate_m = (\"delta_rate_m\", \"first\"),\n",
" ret_fund_m = (\"ret_fund_m\", \"mean\"),\n",
" region = (\"region\", \"first\"),\n",
" country = (\"country\", \"first\"),\n",
" )\n",
" .sort_values([ID_COL, \"month\"])\n",
" .reset_index(drop=True)\n",
")\n",
"\n",
"df_month[\"active_month\"] = (df_month[\"gross_flow_qty\"] > 0).astype(int)\n",
"df_month[\"flow_to_aum_m\"] = np.where(\n",
" df_month[\"aum_qty\"].abs() > 0,\n",
" df_month[\"net_flow_qty\"] / df_month[\"aum_qty\"].abs(), np.nan\n",
")\n",
"df_month[\"turnover_m\"] = np.where(\n",
" df_month[\"aum_qty\"].abs() > 0,\n",
" df_month[\"gross_flow_qty\"] / df_month[\"aum_qty\"].abs(), np.nan\n",
")\n",
"df_month[\"sub_share_m\"] = np.where(\n",
" df_month[\"gross_flow_qty\"] > 0,\n",
" df_month[\"sub_qty\"] / df_month[\"gross_flow_qty\"], np.nan\n",
")\n",
"df_month[\"red_share_m\"] = np.where(\n",
" df_month[\"gross_flow_qty\"] > 0,\n",
" df_month[\"red_qty\"] / df_month[\"gross_flow_qty\"], np.nan\n",
")\n",
"df_month[\"aum_peak_to_date\"] = df_month.groupby(ID_COL)[\"aum_qty\"].cummax()\n",
"df_month[\"aum_drawdown\"] = np.where(\n",
" df_month[\"aum_peak_to_date\"] > 0,\n",
" 1 - df_month[\"aum_qty\"] / df_month[\"aum_peak_to_date\"], np.nan\n",
")\n",
"\n",
"print(\"df_month shape:\", df_month.shape)\n",
"\n",
"# 3b. ISIN-level features\n",
"tmp = df_rel_m.sort_values([ID_COL, ISIN_COL, \"month\"]).copy()\n",
"tmp[\"prev_aum\"] = tmp.groupby([ID_COL, ISIN_COL])[\"aum_qty\"].shift(1)\n",
"tmp[\"entry_event\"] = ((tmp[\"prev_aum\"].fillna(0) <= 0) & (tmp[\"aum_qty\"] > 0)).astype(int)\n",
"tmp[\"full_exit_event\"] = ((tmp[\"prev_aum\"] > 0) & (tmp[\"aum_qty\"] <= 0)).astype(int)\n",
"tmp[\"ret_fund_m_lag1\"] = tmp.groupby([ID_COL, ISIN_COL])[\"ret_fund_m\"].shift(1)\n",
"tmp[\"buy_on_perf\"] = ((tmp[\"net_flow_qty\"] > 0) & (tmp[\"ret_fund_m_lag1\"] > 0)).astype(int)\n",
"tmp[\"sell_on_perf\"] = ((tmp[\"net_flow_qty\"] < 0) & (tmp[\"ret_fund_m_lag1\"] < 0)).astype(int)\n",
"\n",
"df_rel_feat = (\n",
" tmp.groupby([ID_COL, ISIN_COL], as_index=False)\n",
" .agg(\n",
" rel_n_months = (\"month\", \"nunique\"),\n",
" rel_active_months = (\"active_rel_month\", \"sum\"),\n",
" rel_holding_months = (\"holding_rel_month\", \"sum\"),\n",
" rel_aum_mean = (\"aum_qty\", \"mean\"),\n",
" rel_turnover_mean = (\"turnover_rel\", \"mean\"),\n",
" rel_turnover_vol = (\"turnover_rel\", \"std\"),\n",
" rel_flow_to_aum_vol = (\"flow_to_aum_rel\", \"std\"),\n",
" rel_n_tx = (\"n_tx\", \"sum\"),\n",
" rel_full_exit_count = (\"full_exit_event\", \"sum\"),\n",
" rel_entry_count = (\"entry_event\", \"sum\"),\n",
" buy_on_perf_rate = (\"buy_on_perf\", \"mean\"),\n",
" sell_on_perf_rate = (\"sell_on_perf\", \"mean\"),\n",
" )\n",
")\n",
"\n",
"isin_aum = df_rel_feat.groupby(ID_COL)[\"rel_aum_mean\"].transform(\"sum\")\n",
"df_rel_feat[\"isin_weight\"] = np.where(\n",
" isin_aum > 0, df_rel_feat[\"rel_aum_mean\"] / isin_aum, np.nan\n",
")\n",
"hhi_isin = (\n",
" df_rel_feat.groupby(ID_COL)[\"isin_weight\"]\n",
" .apply(lambda w: np.sum(w**2))\n",
" .reset_index(name=\"hhi_isin\")\n",
")\n",
"\n",
"df_rel_client = (\n",
" df_rel_feat.groupby(ID_COL, as_index=False)\n",
" .agg(\n",
" n_isin_total = (ISIN_COL, \"nunique\"),\n",
" rel_turnover_mean_avg = (\"rel_turnover_mean\", \"mean\"),\n",
" rel_turnover_vol_avg = (\"rel_turnover_vol\", \"mean\"),\n",
" rel_flow_to_aum_vol_avg = (\"rel_flow_to_aum_vol\", \"mean\"), \n",
" full_exit_count = (\"rel_full_exit_count\", \"sum\"),\n",
" entry_count = (\"rel_entry_count\", \"sum\"),\n",
" avg_holding_months_per_isin = (\"rel_holding_months\", \"mean\"),\n",
" max_holding_months_per_isin = (\"rel_holding_months\", \"max\"),\n",
" buy_on_perf_rate_avg = (\"buy_on_perf_rate\", \"mean\"),\n",
" sell_on_perf_rate_avg = (\"sell_on_perf_rate\", \"mean\"),\n",
" )\n",
" .merge(hhi_isin, on=ID_COL, how=\"left\")\n",
")\n",
"\n",
"print(\"ISIN-level client features:\", df_rel_client.shape)\n",
"\n",
"# 3c. Asset & fund shares\n",
"aum_by_asset = (\n",
" df_aum.dropna(subset=[ID_COL, ASSET_COL])\n",
" .groupby([ID_COL, ASSET_COL], as_index=False)[AUM_VAL_COL].sum()\n",
")\n",
"total_aum_acc = aum_by_asset.groupby(ID_COL)[AUM_VAL_COL].sum().rename(\"total_aum\")\n",
"aum_by_asset = aum_by_asset.merge(total_aum_acc, on=ID_COL)\n",
"aum_by_asset[\"share\"] = np.where(\n",
" aum_by_asset[\"total_aum\"] > 0,\n",
" aum_by_asset[AUM_VAL_COL] / aum_by_asset[\"total_aum\"], np.nan\n",
")\n",
"asset_shares = (\n",
" aum_by_asset\n",
" .pivot_table(index=ID_COL, columns=ASSET_COL, values=\"share\", aggfunc=\"mean\")\n",
" .fillna(0).reset_index()\n",
")\n",
"asset_shares.columns = [ID_COL] + [\n",
" f\"share_asset_{c.lower().replace(' ','_')}\" for c in asset_shares.columns[1:]\n",
"]\n",
"\n",
"aum_by_fund = (\n",
" df_aum.dropna(subset=[ID_COL, FUND_COL])\n",
" .groupby([ID_COL, FUND_COL], as_index=False)[AUM_VAL_COL].sum()\n",
")\n",
"aum_by_fund = aum_by_fund.merge(total_aum_acc, on=ID_COL)\n",
"aum_by_fund[\"share\"] = np.where(\n",
" aum_by_fund[\"total_aum\"] > 0,\n",
" aum_by_fund[AUM_VAL_COL] / aum_by_fund[\"total_aum\"], np.nan\n",
")\n",
"top_funds = aum_by_fund.groupby(FUND_COL)[AUM_VAL_COL].sum().nlargest(10).index\n",
"fund_shares = (\n",
" aum_by_fund[aum_by_fund[FUND_COL].isin(top_funds)]\n",
" .pivot_table(index=ID_COL, columns=FUND_COL, values=\"share\", aggfunc=\"mean\")\n",
" .fillna(0).reset_index()\n",
")\n",
"fund_shares.columns = [ID_COL] + [\n",
" f\"share_fund_{c.lower().replace(' ','_')[:30]}\" for c in fund_shares.columns[1:]\n",
"]\n",
"\n",
"print(\"Asset shares:\", asset_shares.shape)\n",
"print(\"Fund shares: \", fund_shares.shape)\n",
"\n",
"# 3e. Static client features (commun)\n",
"df_client_base = (\n",
" df_month.groupby(ID_COL, as_index=False)\n",
" .agg(\n",
" n_months = (\"month\", \"nunique\"),\n",
" n_active_months = (\"active_month\", \"sum\"),\n",
" flow_freq = (\"active_month\", \"mean\"),\n",
" aum_qty_mean = (\"aum_qty\", \"mean\"),\n",
" aum_qty_median = (\"aum_qty\", \"median\"),\n",
" aum_qty_max = (\"aum_qty\", \"max\"),\n",
" aum_qty_last = (\"aum_qty\", \"last\"),\n",
" net_flow_qty_sum = (\"net_flow_qty\", \"sum\"),\n",
" gross_flow_qty_sum = (\"gross_flow_qty\", \"sum\"),\n",
" gross_flow_qty_mean= (\"gross_flow_qty\", \"mean\"),\n",
" sub_qty_sum = (\"sub_qty\", \"sum\"),\n",
" red_qty_sum = (\"red_qty\", \"sum\"),\n",
" n_tx_total = (\"n_tx\", \"sum\"),\n",
" avg_n_isin_held = (\"n_isin_held\", \"mean\"),\n",
" max_n_isin_held = (\"n_isin_held\", \"max\"),\n",
" net_flow_qty_vol = (\"net_flow_qty\", \"std\"),\n",
" aum_drawdown_last = (\"aum_drawdown\", \"last\"),\n",
" aum_drawdown_max = (\"aum_drawdown\", \"max\"),\n",
" region = (\"region\", \"last\"),\n",
" country = (\"country\", \"last\"),\n",
" )\n",
")\n",
"df_client_base[\"net_flow_qty_vol\"] = df_client_base[\"net_flow_qty_vol\"].fillna(0)\n",
"\n",
"df_client_base = (\n",
" df_client_base\n",
" .merge(df_rel_client, on=ID_COL, how=\"left\")\n",
" .merge(asset_shares, on=ID_COL, how=\"left\")\n",
" .merge(fund_shares, on=ID_COL, how=\"left\")\n",
")\n",
"\n",
"print(\"df_client_base shape:\", df_client_base.shape)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae1415ce-3518-4948-9b49-fe1380bd16f7",
"metadata": {},
"outputs": [],
"source": [
"# ============================================================\n",
"# PART 1 — GLOBAL CLUSTERING \n",
"# ============================================================\n",
"print(\"\\n\" + \"=\"*70)\n",
"print(\"PARTIE 1 — CLUSTERING GLOBAL\")\n",
"print(\"=\"*70)\n",
"\n",
"# 2f. Engineered ratios\n",
"dfc = df_client_base.copy()\n",
"dfc[\"log_aum_qty_mean\"] = np.log1p(dfc[\"aum_qty_mean\"].clip(lower=0))\n",
"dfc[\"gross_flow_to_aum\"] = np.where(\n",
" dfc[\"aum_qty_mean\"] > 1,\n",
" dfc[\"gross_flow_qty_sum\"] / dfc[\"aum_qty_mean\"], np.nan\n",
")\n",
"dfc[\"flow_direction_balance\"] = np.where(\n",
" dfc[\"gross_flow_qty_sum\"] > 0,\n",
" dfc[\"net_flow_qty_sum\"] / dfc[\"gross_flow_qty_sum\"], np.nan\n",
")\n",
"dfc[\"sub_share_mean\"] = np.where(\n",
" dfc[\"gross_flow_qty_sum\"] > 0,\n",
" dfc[\"sub_qty_sum\"] / dfc[\"gross_flow_qty_sum\"], np.nan\n",
")\n",
"dfc[\"redemption_bias\"] = np.where(\n",
" dfc[\"gross_flow_qty_sum\"] > 0,\n",
" (dfc[\"red_qty_sum\"] - dfc[\"sub_qty_sum\"]) / dfc[\"gross_flow_qty_sum\"], np.nan\n",
")\n",
"dfc[\"exit_rate_per_isin\"] = np.where(\n",
" dfc[\"n_isin_total\"] > 0,\n",
" dfc[\"full_exit_count\"] / dfc[\"n_isin_total\"], np.nan\n",
")\n",
"dfc[\"aum_final_to_peak\"] = np.where(\n",
" dfc[\"aum_qty_max\"] > 0,\n",
" dfc[\"aum_qty_last\"] / dfc[\"aum_qty_max\"], np.nan\n",
")\n",
"dfc[\"aum_drawdown_last\"] = dfc[\"aum_drawdown_last\"].clip(0, 1)\n",
"\n",
"for col in [\"aum_qty_mean\", \"gross_flow_qty_sum\", \"n_tx_total\"]:\n",
" dfc[f\"log_{col}\"] = np.log1p(dfc[col].clip(lower=0))\n",
"\n",
"# Filtres qualité\n",
"dfc = dfc[(dfc[\"n_months\"] >= 6) & (dfc[\"aum_qty_mean\"] > 0)].copy()\n",
"for col in [\"aum_qty_mean\", \"gross_flow_qty_sum\", \"n_tx_total\"]:\n",
" cap = dfc[col].quantile(0.99)\n",
" dfc = dfc[dfc[col] <= cap].copy()\n",
"\n",
"# Géographie\n",
"top_countries = dfc[\"country\"].fillna(\"Unknown\").value_counts().head(10).index\n",
"top_regions = dfc[\"region\"].fillna(\"Unknown\").value_counts().head(10).index\n",
"dfc[\"country_grp\"] = np.where(dfc[\"country\"].isin(top_countries), dfc[\"country\"], \"Other\")\n",
"dfc[\"region_grp\"] = np.where(dfc[\"region\"].isin(top_regions), dfc[\"region\"], \"Other\")\n",
"\n",
"# months_since_last_tx\n",
"dfc = add_months_since_last_tx(dfc, df_month, ID_COL)\n",
"\n",
"print(f\"After filters: {len(dfc)} accounts\")\n",
"\n",
"# Feature selection & preprocessing\n",
"base_features_global = [\n",
" \"flow_freq\",\n",
" \"gross_flow_to_aum\",\n",
" \"n_isin_total\",\n",
" \"avg_holding_months_per_isin\",\n",
" \"exit_rate_per_isin\",\n",
" \"flow_direction_balance\",\n",
" \"log_aum_qty_mean\",\n",
" \"months_since_last_tx\",\n",
"]\n",
"all_features_global = [c for c in base_features_global if c in dfc.columns]\n",
"\n",
"dfc_clean = dfc.copy()\n",
"\n",
"for col in [\"flow_direction_balance\", \"months_since_last_tx\"]:\n",
" if col in dfc_clean.columns:\n",
" dfc_clean[col] = dfc_clean[col].fillna(0)\n",
"\n",
"for col in [\"n_isin_total\", \"exit_rate_per_isin\",\n",
" \"avg_holding_months_per_isin\", \"months_since_last_tx\"]:\n",
" if col in dfc_clean.columns:\n",
" dfc_clean[col] = winsorize_mad(dfc_clean[col], n_sigma=3)\n",
"\n",
"col = \"gross_flow_to_aum\"\n",
"if col in dfc_clean.columns:\n",
" vals = dfc_clean[col].to_numpy(dtype=float)\n",
" vals = np.clip(vals, 0, np.nanpercentile(vals, 90))\n",
" dfc_clean[col] = np.log1p(vals)\n",
"\n",
"col = \"flow_freq\"\n",
"if col in dfc_clean.columns:\n",
" vals = dfc_clean[col].to_numpy(dtype=float)\n",
" dfc_clean[col] = np.log1p(np.clip(vals, 0, None))\n",
"\n",
"col = \"log_aum_qty_mean\"\n",
"if col in dfc_clean.columns:\n",
" dfc_clean[col] = winsorize_mad(dfc_clean[col], n_sigma=3)\n",
"\n",
"X_global = dfc_clean[all_features_global].copy()\n",
"X_global = X_global.loc[:, ~X_global.columns.duplicated()]\n",
"X_global = X_global.fillna(X_global.median())\n",
"\n",
"scaler_global = RobustScaler()\n",
"X_global_scaled = scaler_global.fit_transform(X_global)\n",
"\n",
"# Diagnostic\n",
"X_df = pd.DataFrame(X_global_scaled, columns=X_global.columns)\n",
"extreme = (X_df.abs() > 5).any(axis=1).sum()\n",
"print(f\"Accounts: {X_global.shape[0]} | Features: {X_global.shape[1]}\")\n",
"print(f\"Points > 5 std after scaling: {extreme} ({extreme/len(X_df):.1%})\")\n",
"\n",
"# K-selection\n",
"rows = []\n",
"for k in range(2, 8):\n",
" km = KMeans(n_clusters=k, n_init=50, random_state=RANDOM_STATE)\n",
" labels = km.fit_predict(X_global_scaled)\n",
" rows.append({\n",
" \"k\": k, \"inertia\": km.inertia_,\n",
" \"silhouette\": silhouette_score(X_global_scaled, labels),\n",
" \"davies_bouldin\": davies_bouldin_score(X_global_scaled, labels),\n",
" })\n",
"df_kdiag_global = pd.DataFrame(rows)\n",
"print(df_kdiag_global.to_string(index=False))\n",
"\n",
"fig, axes = plt.subplots(1, 3, figsize=(15, 4))\n",
"for ax, col, title in zip(axes,\n",
" [\"inertia\", \"silhouette\", \"davies_bouldin\"],\n",
" [\"Elbow / Inertia\", \"Silhouette (higher=better)\", \"Davies-Bouldin (lower=better)\"]):\n",
" ax.plot(df_kdiag_global[\"k\"], df_kdiag_global[col], marker=\"o\")\n",
" ax.set_title(title); ax.set_xlabel(\"K\")\n",
"plt.suptitle(\"K-selection — Global Clustering\")\n",
"plt.tight_layout(); plt.show()\n",
"\n",
"# Clustering K=4\n",
"RESULTS_GLOBAL = {}\n",
"for k in [4]:\n",
" km = KMeans(n_clusters=k, n_init=50, random_state=RANDOM_STATE)\n",
" dfc[f\"cluster_k{k}\"] = km.fit_predict(X_global_scaled)\n",
" RESULTS_GLOBAL[k] = {\n",
" \"model\": km,\n",
" \"silhouette\": silhouette_score(X_global_scaled, dfc[f\"cluster_k{k}\"]),\n",
" \"davies_bouldin\": davies_bouldin_score(X_global_scaled, dfc[f\"cluster_k{k}\"]),\n",
" }\n",
" print(f\"K={k} | sil={RESULTS_GLOBAL[k]['silhouette']:.4f} \"\n",
" f\"| db={RESULTS_GLOBAL[k]['davies_bouldin']:.4f}\")\n",
" counts = dfc[f\"cluster_k{k}\"].value_counts().sort_index()\n",
" props = counts / counts.sum() * 100\n",
" print(pd.DataFrame({\"n_comptes\": counts, \"pct\": props.round(1)}))\n",
"\n",
"# Heatmaps\n",
"profile_vars_behavior = [\n",
" \"gross_flow_to_aum\", \"flow_freq\", \"flow_direction_balance\",\n",
" \"n_isin_total\", \"avg_holding_months_per_isin\", \"exit_rate_per_isin\",\n",
" \"log_aum_qty_mean\", \"months_since_last_tx\",\n",
"]\n",
"profile_vars_behavior = [c for c in profile_vars_behavior if c in dfc.columns]\n",
"\n",
"prof_behavior = plot_heatmap(\n",
" dfc, profile_vars_behavior, \"cluster_k4\",\n",
" title=\"Cluster signatures — Comportement (K=4, robust z-score)\",\n",
" figsize=(14, 4)\n",
")\n",
"print(\"\\n=== Médianes comportement K=4 ===\")\n",
"print(prof_behavior.round(3).to_string())\n",
"\n",
"profile_vars_allocation = [\n",
" c for c in [\n",
" \"share_asset_fixed_income\", \"share_asset_diversified\",\n",
" \"share_asset_equity\", \"share_fund_carmignac_patrimoine\",\n",
" \"share_fund_carmignac_investissement\", \"share_fund_carmignac_sécurité\",\n",
" \"share_fund_carmignac_emergents\",\n",
" ] if c in dfc.columns\n",
"]\n",
"\n",
"prof_allocation = plot_heatmap(\n",
" dfc, profile_vars_allocation, \"cluster_k4\",\n",
" title=\"Cluster signatures — Allocation produits (K=4, descriptif)\",\n",
" figsize=(12, 4)\n",
")\n",
"print(\"\\n=== Médianes allocation K=4 ===\")\n",
"print(prof_allocation.round(3).to_string())\n",
"\n",
"# Description géographique\n",
"print(\"\\n=== Distribution géographique par cluster ===\")\n",
"geo_country = pd.crosstab(\n",
" dfc[\"cluster_k4\"], dfc[\"country_grp\"].fillna(\"Unknown\"),\n",
" normalize=\"index\"\n",
").round(3) * 100\n",
"geo_region = pd.crosstab(\n",
" dfc[\"cluster_k4\"], dfc[\"region_grp\"].fillna(\"Unknown\"),\n",
" normalize=\"index\"\n",
").round(3) * 100\n",
"\n",
"fig, axes = plt.subplots(1, 2, figsize=(18, 4))\n",
"sns.heatmap(geo_country, cmap=\"Blues\", annot=True, fmt=\".1f\",\n",
" ax=axes[0], cbar_kws={\"label\": \"%\"})\n",
"axes[0].set_title(\"Distribution par pays (% par cluster)\")\n",
"sns.heatmap(geo_region, cmap=\"Blues\", annot=True, fmt=\".1f\",\n",
" ax=axes[1], cbar_kws={\"label\": \"%\"})\n",
"axes[1].set_title(\"Distribution par région (% par cluster)\")\n",
"plt.tight_layout(); plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 207,
"id": "8f67a20a-f31e-4380-9ecb-5e87eb67bed1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Colonnes disponibles : ['Registrar Account - ID', 'cluster_k4', 'cluster_alternative', 'cluster_diversified', 'cluster_equity', 'cluster_fixed_income']\n",
"Shape : (7179, 6)\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABs8AAATMCAYAAADI7xmhAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3Xd8jef/x/F3phUriJLE7okRe28JtVe01O4wW1WlWnRS1PiWtkZrU5SqPWqV2ntVqwQ1agchkpCIJPfvD8n5OTKRnEPyej4eHu257vW573MnOZ/zua/rsjMMwxAAAAAAAAAAAAAA2ds6AAAAAAAAAAAAAOB5QfEMAAAAAAAAAAAAiEHxDAAAAAAAAAAAAIhB8QwAAAAAAAAAAACIQfEMAAAAAAAAAAAAiEHxDAAAAAAAAAAAAIhB8QwAAAAAAAAAAACIQfEMAAAAAAAAAAAAiEHxDAAAAAAAAAAAAIhB8QwAAAAJ6tKli7y8vGwdRro3ceJEeXl5ad++fbYOJVX4+vrK19fX1mGkiGXLlsnLy0vLli17pv14eXmpS5cuKRRVXIMHD5aXl5cuXbqUasdIKdz/AAAAAKzN0dYBAAAAIHHHjh3TggULdPDgQV2/fl3R0dFyc3NT+fLl1bp1a9WsWdPWIaY7ly5dUv369eXn56fRo0c/1T6e5/e1S5cu2r9/v06ePGmzGJ4HkZGR+u2337R+/XodO3ZMt2/flqOjo/LmzavSpUurUaNGql+/vuzteSbxSXH/41mtWLFCgwYNkiQtXrxYZcqUsXFE8Vu2bJmGDBmiUaNGqU2bNkmuv2/fPnXt2jXZ+69SpYrmzZv3LCECAAAgHhTPAAAAnlPR0dEaM2aM5syZI0dHR1WrVk2+vr5ydHTUxYsXtW3bNq1atUrvv/+++vTpkyoxjBkzRmFhYamy7/TqeXhfnzdz5syxdQhxXL58We+9956OHz+unDlzqnr16sqfP7+io6N1+fJl7dixQ6tXr1aDBg00efJkW4f7wuD+j+t5vP9fBEuWLJGdnZ0Mw9DSpUuf2+LZk3J3d9d7771n0RYcHKy5c+fK3d1dfn5+cdYHAABAyqN4BgAA8Jz67rvvNGfOHJUoUUITJkxQgQIFLJaHh4dr/vz5CgoKSrUY8ufPn2r7Tq+eh/f1efP4NbC10NBQdevWTefOnVP37t3Vt29fZcyY0WKdBw8eaM2aNdqyZYuNonwxcf/H9bzd/y+C8+fP68CBA/L19dXZs2f122+/aciQIXF+Tl9EHh4e6tu3r0XbpUuXzMWzx5cBAAAgdTC+CAAAwHPov//+04wZM5QjRw7NmDEj3i9XM2bMqO7du+v99983t8XOY3Tx4kXNmjVLTZs2lbe3twYPHmxe59SpU+rXr5+qV68ub29v+fr6auTIkbp9+3acY8Q351l0dLQWL16s1157TVWqVFGZMmVUp04d9e7dO945iQ4cOKDevXuratWq8vb2VsOGDfXtt9/G6dG2b98+eXl5aeLEiTp8+LC6dOmi8uXLq1q1aho6dKjCw8MlSVu3btXrr7+ucuXKqUaNGho7dqwiIyPjvY6bNm3SG2+8ocqVK6t06dJq3ry5Zs6cqaioKIv1Hp2naufOnWrfvr3Kli2rqlWratCgQRbXZtmyZapfv74kafny5fLy8jL/S2pOpqd9X+Pz6PV63KVLl+Tl5WXxvksPv3AeMmSIfH195e3trSpVqqhly5YaOXKkDMOQ9HCurf3795v/P/bf4/vy9/dX//79VatWLXl7e8vHx0fDhw+Pcx89GsuZM2fUp08fVa1a1WK+rfjmfHp0nqvVq1erVatWKlOmjGrVqqURI0aY74dHRUZGaurUqWrQoIFKly6tV155RVOnTtXFixfjPYeEzJgxQ+fOnZOfn58++uijeL+Qd3Jykp+fn8aPH5+sfUrSoUOH1LNnT1WpUkWlS5dW48aNNWHChER7d167dk0DBgxQ1apVVbZsWbVv3167d++Os965c+c0duxY+fn5qWrVquZhJb/55hvdvXs32THGZ9q0afLy8tIXX3yR4LIvv/wyyf1w/78Y9/+jf0emT5+uhg0bqnTp0vL19dWkSZP04MEDi/UjIiI0b948devWTXXr1pW3t7eqV69u7rn5uEd/3/7xxx9q3769ypcv/0Tzvi1dulSS1Lp1a7Vq1UohISFav359vOuGhITo+++/V9OmTVW+fHlVqFBBr7zyigYNGqTLly+b17t//75mzZqlli1bqmLFiipXrpx8fX3Vr18/+fv7x9lvcv6+DB48WEOGDJEkDRkyxOKeelbffvutvLy8tHbt2niXL1myRF5eXpo6daq5LXYuxeT+XpEevr+zZ8+Wn5+fypUrp/Lly6tjx47avHnzM58DAADA84yeZwAAAM+hZcuWKSoqSu3bt1fu3LkTXdfZ2TlO2/Dhw3X06FHVrVtXPj4+ypUrlyTp4MGD6t69ux48eKBGjRrJ3d1df/75p+bOnautW7dq0aJFcnV1TfR448aNM3/x3bx5c2XJkkUBAQE6dOiQdu/erapVq5rXXbBggb766itly5ZNPj4+cnV11bFjxzRlyhTt27dPc+fOjRP/0aNHNX36dNWqVUvt27fXvn37tHDhQoWGhsrX11eDBw9W/fr1Va5cOW3dulUzZ85U5syZ4wxzNW7cOE2bNk158+bVK6+8oqxZs+rgwYMaO3asjh49qgkTJsQ5tz/++ENbt26Vr6+vypcvrwMHDmjFihW6cOGCFi5cKEkqUaKEunbtqrlz56p48eJq0KCBefukhs961vf1WQQEBKht27YKCwtT3bp11bRpU4WFhen8+fNauHChBg0aJEdHR7333ntavny5edjCWCVKlDD//+bNm/XBBx/I3t5e9evX10svvaQzZ85o/vz52rlzp3799Vdlz57d4vj//fef2rVrJ5PJJD8/PwUFBcnJySnJuH/++Wft2LFDvr6+qlatmnbs2KF58+bp9u3bGjdunMW6n3zyiVauXClPT0916tRJERERmjNnjo4cOfJE12rZsmWSpHfffTfJdR0dk5dSrVu3Th9++KGcnZ3VpEkT5cqVS7t27dLkyZO1c+dOzZs3TxkyZLDY5s6dO+rQoYNy5syptm3b6tatW1q3bp26d++uCRMmWNx7v//+u5YuXaqqVauqSpUqio6ONv8sHThwQPPnz0/W9Y5P9+7dtWvXLi1atEh16tQxH/evv/7ShAkTVKxYMXOBIDHc/y/G/R9r5MiROnLkiBo3bqzMmTNry5Ytmjhxok6dOmXx+/POnTv6+uuvValSJdWtW1fZsmXTxYsX9ccff2j79u2aP39+vEMqrl+/Xrt27VK9evXUsWNHhYaGJiuuqKgoLV++XNmzZ5ePj4+8vb01YcIELV26VK1bt7ZY1zAMdevWTUePHlWFChVUu3Zt2dvb6/Lly/rjjz/UqlUr8+/tQYMGad26dfLy8lKbNm3k7Oysa9euad++ffr7779VvHhx836T+/elQYMGCg4O1ubNm1W/fn2L++hZtWvXTtOmTdOSJUvUtGnTOMsXL14sR0fHOPOsPcnvlYiICHXr1k379+9XiRIl9Nprr+nBgwfatm2b3n33XX3++efq3Llzip0TAADAc8UAAADAc6dz586GyWQydu/e/UTbDRo0yDCZTEadOnWMy5cvWyyLiooyGjRoYJhMJmP79u0Wy8aMGWOYTCZjyJAh8cbxqCpVqhi1atUy7t27F+f4t2/fNv//6dOnjZIlSxotW7Y0bt26ZbHe1KlTDZPJZMycOdPctnfvXsNkMhkmk8n4/fffze0RERFGixYtDC8vL6Nq1arG0aNHzctCQkKM6tWrG1WqVDEiIiLM7Tt37jRMJpPx9ttvG3fv3jW3R0dHG1988YVhMpmM9evXm9uXLl1qmEwmo2TJksbBgwfN7ZGRkeZrcOTIEXP7xYsXDZPJZAwaNCjONUjM076vEyZMMEwmk7F3715zW+z1mjBhQpz144tv7ty5hslkMubMmRNn/Ufft0fjjM+tW7eMChUqGLVr1zYuXbpksWzNmjWGyWQyvvrqqzi
"text/plain": [
"<Figure size 1800x1200 with 8 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"============================================================\n",
"Global x Alternative\n",
"============================================================\n",
"\n",
"% par cluster global (chaque ligne somme à 100%) :\n",
" Non exposé Asset C0 Asset C1\n",
"Global C0 91.1 1.1 7.8\n",
"Global C1 48.7 10.7 40.5\n",
"Global C2 86.5 6.2 7.3\n",
"Global C3 93.2 0.9 5.9\n",
"\n",
"% par cluster asset (chaque colonne somme à 100%) :\n",
" Non exposé Asset C0 Asset C1\n",
"Global C0 41.0 11.0 23.5\n",
"Global C1 9.5 47.9 52.7\n",
"Global C2 21.2 34.6 12.0\n",
"Global C3 28.2 6.5 11.8\n",
"\n",
"============================================================\n",
"Global x Diversified\n",
"============================================================\n",
"\n",
"% par cluster global (chaque ligne somme à 100%) :\n",
" Non exposé Asset C0 Asset C1\n",
"Global C0 64.2 33.9 1.8\n",
"Global C1 21.1 61.7 17.2\n",
"Global C2 31.6 40.4 27.9\n",
"Global C3 40.9 54.0 5.1\n",
"\n",
"% par cluster asset (chaque colonne somme à 100%) :\n",
" Non exposé Asset C0 Asset C1\n",
"Global C0 54.4 28.5 6.6\n",
"Global C1 7.8 22.5 26.7\n",
"Global C2 14.6 18.5 54.4\n",
"Global C3 23.3 30.5 12.3\n",
"\n",
"============================================================\n",
"Global x Equity\n",
"============================================================\n",
"\n",
"% par cluster global (chaque ligne somme à 100%) :\n",
" Non exposé Asset C0 Asset C1 Asset C2\n",
"Global C0 70.6 25.9 3.2 0.2\n",
"Global C1 18.7 23.1 9.7 48.6\n",
"Global C2 37.4 32.8 29.5 0.3\n",
"Global C3 44.2 49.1 6.8 0.0\n",
"\n",
"% par cluster asset (chaque colonne somme à 100%) :\n",
" Non exposé Asset C0 Asset C1 Asset C2\n",
"Global C0 54.8 29.9 11.6 0.9\n",
"Global C1 6.3 11.5 15.0 98.3\n",
"Global C2 15.8 20.6 57.2 0.9\n",
"Global C3 23.1 38.0 16.2 0.0\n",
"\n",
"============================================================\n",
"Global x Fixed Income\n",
"============================================================\n",
"\n",
"% par cluster global (chaque ligne somme à 100%) :\n",
" Non exposé Asset C0 Asset C1\n",
"Global C0 34.5 61.5 4.0\n",
"Global C1 19.3 52.9 27.9\n",
"Global C2 65.4 21.2 13.3\n",
"Global C3 72.0 24.1 3.9\n",
"\n",
"% par cluster asset (chaque colonne somme à 100%) :\n",
" Non exposé Asset C0 Asset C1\n",
"Global C0 27.2 54.8 15.5\n",
"Global C1 6.6 20.4 46.4\n",
"Global C2 28.1 10.3 28.0\n",
"Global C3 38.2 14.4 10.1\n",
"\n",
"============================================================\n",
"Adjusted Rand Index — cohérence global x asset\n",
"============================================================\n",
"(1 = identiques, 0 = aléatoire, <0 = pire qu'aléatoire)\n",
"\n",
" Alternative : ARI=0.0278 (n=1166 comptes communs)\n",
" Diversified : ARI=0.0347 (n=3980 comptes communs)\n",
" Equity : ARI=0.1587 (n=3691 comptes communs)\n",
" Fixed Income : ARI=0.1106 (n=3743 comptes communs)\n",
"\n",
"============================================================\n",
"Exposition multi-asset par cluster global\n",
"============================================================\n",
"\n",
"Nombre moyen d'asset types par cluster global :\n",
"cluster_k4\n",
"0 1.40\n",
"1 2.92\n",
"2 1.79\n",
"3 1.50\n",
"Name: n_asset_types, dtype: float64\n",
"\n",
"Distribution du nombre d'asset types par cluster global :\n",
" 0 asset(s) 1 asset(s) 2 asset(s) 3 asset(s) 4 asset(s)\n",
"Global C0 0.4 73.9 14.8 7.3 3.5\n",
"Global C1 0.8 17.5 13.6 25.0 43.1\n",
"Global C2 0.0 49.2 29.3 14.8 6.7\n",
"Global C3 0.0 64.7 23.3 9.6 2.4\n"
]
}
],
"source": [
"# ============================================================\n",
"# CROISEMENT — clustering global x clustering par asset type\n",
"# ============================================================\n",
"\n",
"# ── 1. Merge des labels asset dans dfc ────────────────────────────────────\n",
"dfc_cross = dfc[[ID_COL, \"cluster_k4\"]].copy()\n",
"\n",
"for asset, res in ASSET_RESULTS.items():\n",
" cluster_col = res[\"cluster_col\"]\n",
" df_a = res[\"df\"][[ID_COL, cluster_col]].copy()\n",
" dfc_cross = dfc_cross.merge(df_a, on=ID_COL, how=\"left\")\n",
"\n",
"print(\"Colonnes disponibles :\", dfc_cross.columns.tolist())\n",
"print(\"Shape :\", dfc_cross.shape)\n",
"\n",
"# ── 2. Tables de contingence global x asset ───────────────────────────────\n",
"fig, axes = plt.subplots(2, 2, figsize=(18, 12))\n",
"axes = axes.flatten()\n",
"\n",
"for i, (asset, res) in enumerate(ASSET_RESULTS.items()):\n",
" cluster_col = res[\"cluster_col\"]\n",
"\n",
" if cluster_col not in dfc_cross.columns:\n",
" continue\n",
"\n",
" # Table de contingence normalisée par ligne (% par cluster global)\n",
" ct = pd.crosstab(\n",
" dfc_cross[\"cluster_k4\"],\n",
" dfc_cross[cluster_col].fillna(-1).astype(int),\n",
" normalize=\"index\"\n",
" ).round(3) * 100\n",
"\n",
" # Renommer les colonnes\n",
" col_names = {\n",
" c: f\"Asset C{c}\" if c >= 0 else \"Non exposé\"\n",
" for c in ct.columns\n",
" }\n",
" ct = ct.rename(columns=col_names)\n",
" ct.index = [f\"Global C{i}\" for i in ct.index]\n",
"\n",
" sns.heatmap(\n",
" ct,\n",
" cmap=\"Blues\",\n",
" annot=True,\n",
" fmt=\".1f\",\n",
" ax=axes[i],\n",
" cbar_kws={\"label\": \"%\"},\n",
" vmin=0,\n",
" vmax=100,\n",
" )\n",
" axes[i].set_title(f\"Global x {asset} (% par cluster global)\")\n",
" axes[i].set_xlabel(f\"Cluster {asset}\")\n",
" axes[i].set_ylabel(\"Cluster Global\")\n",
"\n",
"plt.suptitle(\"Croisement Clustering Global x Clustering par Asset Type\",\n",
" fontsize=14, y=1.02)\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"# ── 3. Tables de contingence détaillées ───────────────────────────────────\n",
"for asset, res in ASSET_RESULTS.items():\n",
" cluster_col = res[\"cluster_col\"]\n",
" if cluster_col not in dfc_cross.columns:\n",
" continue\n",
"\n",
" print(f\"\\n{'='*60}\")\n",
" print(f\"Global x {asset}\")\n",
" print(f\"{'='*60}\")\n",
"\n",
" # % par cluster global\n",
" ct_row = pd.crosstab(\n",
" dfc_cross[\"cluster_k4\"],\n",
" dfc_cross[cluster_col].fillna(-1).astype(int),\n",
" normalize=\"index\"\n",
" ).round(3) * 100\n",
" ct_row.index = [f\"Global C{i}\" for i in ct_row.index]\n",
" ct_row.columns = [f\"Asset C{c}\" if c >= 0 else \"Non exposé\"\n",
" for c in ct_row.columns]\n",
" print(\"\\n% par cluster global (chaque ligne somme à 100%) :\")\n",
" print(ct_row.to_string())\n",
"\n",
" # % par cluster asset\n",
" ct_col = pd.crosstab(\n",
" dfc_cross[\"cluster_k4\"],\n",
" dfc_cross[cluster_col].fillna(-1).astype(int),\n",
" normalize=\"columns\"\n",
" ).round(3) * 100\n",
" ct_col.index = [f\"Global C{i}\" for i in ct_col.index]\n",
" ct_col.columns = [f\"Asset C{c}\" if c >= 0 else \"Non exposé\"\n",
" for c in ct_col.columns]\n",
" print(\"\\n% par cluster asset (chaque colonne somme à 100%) :\")\n",
" print(ct_col.to_string())\n",
"\n",
"# ── 4. Indice de Rand Ajusté — mesure de cohérence ────────────────────────\n",
"from sklearn.metrics import adjusted_rand_score\n",
"\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(\"Adjusted Rand Index — cohérence global x asset\")\n",
"print(\"=\"*60)\n",
"print(\"(1 = identiques, 0 = aléatoire, <0 = pire qu'aléatoire)\\n\")\n",
"\n",
"for asset, res in ASSET_RESULTS.items():\n",
" cluster_col = res[\"cluster_col\"]\n",
" if cluster_col not in dfc_cross.columns:\n",
" continue\n",
"\n",
" # Garder seulement les comptes présents dans les deux clusterings\n",
" mask = dfc_cross[cluster_col].notna()\n",
" labels_global = dfc_cross.loc[mask, \"cluster_k4\"].values\n",
" labels_asset = dfc_cross.loc[mask, cluster_col].values\n",
"\n",
" ari = adjusted_rand_score(labels_global, labels_asset)\n",
" n_common = mask.sum()\n",
" print(f\" {asset:20s} : ARI={ari:.4f} (n={n_common} comptes communs)\")\n",
"\n",
"# ── 5. Profil des comptes présents dans plusieurs asset types ─────────────\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(\"Exposition multi-asset par cluster global\")\n",
"print(\"=\"*60)\n",
"\n",
"# Compter le nombre d'asset types par compte\n",
"asset_cols = [res[\"cluster_col\"] for res in ASSET_RESULTS.values()\n",
" if res[\"cluster_col\"] in dfc_cross.columns]\n",
"dfc_cross[\"n_asset_types\"] = dfc_cross[asset_cols].notna().sum(axis=1)\n",
"\n",
"print(\"\\nNombre moyen d'asset types par cluster global :\")\n",
"print(dfc_cross.groupby(\"cluster_k4\")[\"n_asset_types\"].mean().round(2))\n",
"\n",
"print(\"\\nDistribution du nombre d'asset types par cluster global :\")\n",
"ct_multi = pd.crosstab(\n",
" dfc_cross[\"cluster_k4\"],\n",
" dfc_cross[\"n_asset_types\"],\n",
" normalize=\"index\"\n",
").round(3) * 100\n",
"ct_multi.index = [f\"Global C{i}\" for i in ct_multi.index]\n",
"ct_multi.columns = [f\"{c} asset(s)\" for c in ct_multi.columns]\n",
"print(ct_multi.to_string())"
]
},
{
"cell_type": "code",
"execution_count": 208,
"id": "268e0cda-9040-44a9-8f5c-210ad00dae39",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"=== Fonds disponibles (top 20 par AUM) ===\n",
"Product - Fund\n",
"Carmignac Patrimoine 1.838372e+12\n",
"Carmignac Sécurité 1.053010e+12\n",
"Carmignac Investissement 5.300035e+11\n",
"Carmignac Portfolio Sécurité 2.562135e+11\n",
"Carmignac Portfolio Flexible Bond 2.223185e+11\n",
"Carmignac Portfolio Patrimoine 2.035761e+11\n",
"Carmignac Emergents 1.218833e+11\n",
"Carmignac Portfolio Global Bond 1.119945e+11\n",
"Carmignac Portfolio Credit 8.413277e+10\n",
"Carmignac Court Terme 8.224046e+10\n",
"Carmignac Portfolio Emerging Patrimoine 7.216283e+10\n",
"Carmignac Portfolio Grande Europe 6.404670e+10\n",
"Carmignac Portfolio Long-Short European Equities 6.162365e+10\n",
"Carmignac Portfolio Climate Transition 5.125412e+10\n",
"Carmignac Absolute Return Europe 4.100414e+10\n",
"Carmignac Credit 2027 3.937522e+10\n",
"Carmignac Portfolio Patrimoine Europe 3.880186e+10\n",
"Carmignac Portfolio Investissement 3.643094e+10\n",
"Carmignac Investissement Latitude 3.474053e+10\n",
"Carmignac Portfolio Emergents 2.942745e+10\n",
"\n",
"Fonds retenus (15) :\n",
" Carmignac Patrimoine : 6185 clients, AUM=1838371784989\n",
" Carmignac Sécurité : 2827 clients, AUM=1053009711661\n",
" Carmignac Investissement : 4984 clients, AUM=530003536916\n",
" Carmignac Portfolio Sécurité : 1266 clients, AUM=256213510896\n",
" Carmignac Portfolio Flexible Bond : 1433 clients, AUM=222318524868\n",
" Carmignac Portfolio Patrimoine : 1236 clients, AUM=203576125394\n",
" Carmignac Emergents : 4233 clients, AUM=121883253216\n",
" Carmignac Portfolio Global Bond : 2116 clients, AUM=111994458004\n",
" Carmignac Portfolio Credit : 1137 clients, AUM=84132771053\n",
" Carmignac Court Terme : 1333 clients, AUM=82240456223\n",
" Carmignac Portfolio Emerging Patrimoine : 1675 clients, AUM=72162829525\n",
" Carmignac Portfolio Grande Europe : 2952 clients, AUM=64046699189\n",
" Carmignac Portfolio Long-Short European Equities : 691 clients, AUM=61623651990\n",
" Carmignac Portfolio Climate Transition : 3099 clients, AUM=51254115016\n",
" Carmignac Absolute Return Europe : 1990 clients, AUM=41004139345\n",
"\n",
"df_month_fund shape: (3873987, 19)\n",
"df_client_fund shape: (20740, 23)\n",
"\n",
"Comptes par fund :\n",
"Product - Fund\n",
"Carmignac Patrimoine 3155\n",
"Carmignac Investissement 2194\n",
"Carmignac Emergents 1781\n",
"Carmignac Portfolio Global Bond 1718\n",
"Carmignac Sécurité 1624\n",
"Carmignac Portfolio Grande Europe 1388\n",
"Carmignac Portfolio Climate Transition 1280\n",
"Carmignac Portfolio Sécurité 1163\n",
"Carmignac Portfolio Patrimoine 1145\n",
"Carmignac Portfolio Emerging Patrimoine 1137\n",
"Carmignac Portfolio Flexible Bond 1089\n",
"Carmignac Portfolio Credit 1018\n",
"Carmignac Absolute Return Europe 914\n",
"Carmignac Portfolio Long-Short European Equities 607\n",
"Carmignac Court Terme 527\n",
"Name: Registrar Account - ID, dtype: int64\n",
"\n",
"============================================================\n",
"FUND : Carmignac Patrimoine\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.5061 0.8297 656\n",
" 3 0.4952 0.8445 571\n",
" 4 0.3581 1.2279 337\n",
" 5 0.3858 1.1136 276\n",
" 6 0.3209 1.1835 271\n",
"→ K retenu : 2 (silhouette=0.5061)\n",
" n_comptes pct\n",
"cluster_carmignac_patrimoine \n",
"0 2499 79.2\n",
"1 656 20.8\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Patrimoine:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_patrimoine \n",
"0 0.038 2.322 0.65 -0.879 4.746 83.0 0.000 1.000 0.0\n",
"1 0.085 0.127 1.00 -1.000 4.749 12.0 0.907 0.093 0.0\n",
"\n",
"============================================================\n",
"FUND : Carmignac Sécurité\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.5716 0.8488 309\n",
" 3 0.5540 0.8263 192\n",
" 4 0.4157 0.9818 96\n",
" 5 0.3493 1.1866 84\n",
" 6 0.2712 1.1710 81\n",
"→ K retenu : 2 (silhouette=0.5716)\n",
" n_comptes pct\n",
"cluster_carmignac_sécurité \n",
"0 309 19.0\n",
"1 1315 81.0\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Sécurité:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_sécurité \n",
"0 0.111 1.312 1.000 0.067 5.183 12.0 0.916 0.084 0.0\n",
"1 0.071 4.444 0.525 -0.128 4.721 81.0 0.000 1.000 0.0\n",
"\n",
"============================================================\n",
"FUND : Carmignac Investissement\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.4310 1.0214 381\n",
" 3 0.4221 0.9168 363\n",
" 4 0.2891 1.2951 314\n",
" 5 0.3039 1.2235 216\n",
" 6 0.2898 1.2247 209\n",
"→ K retenu : 2 (silhouette=0.4310)\n",
" n_comptes pct\n",
"cluster_carmignac_investissement \n",
"0 381 17.4\n",
"1 1813 82.6\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Investissement:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_investissement \n",
"0 0.531 1.860 1.352 -0.468 7.592 0.0 0.123 0.877 0.029\n",
"1 0.025 1.067 0.738 -1.000 3.244 92.0 0.000 1.000 0.000\n",
"\n",
"============================================================\n",
"FUND : Carmignac Portfolio Sécurité\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.7984 0.3113 180\n",
" 3 0.6484 0.4722 180\n",
" 4 0.6613 0.5310 61\n",
" 5 0.7217 0.4865 61\n",
" 6 0.7004 0.6374 44\n",
"→ K retenu : 2 (silhouette=0.7984)\n",
" n_comptes pct\n",
"cluster_carmignac_portfolio_sécurité \n",
"0 983 84.5\n",
"1 180 15.5\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Portfolio Sécurité:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_portfolio_sécurité \n",
"0 0.061 7.229 0.419 0.000 6.053 72.0 0.0 1.0 0.0\n",
"1 0.221 1.468 1.000 0.333 8.488 0.0 1.0 0.0 0.0\n",
"\n",
"============================================================\n",
"FUND : Carmignac Portfolio Flexible Bond\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.6092 0.7548 121\n",
" 3 0.3969 1.1736 75\n",
" 4 0.4146 0.9109 34\n",
" 5 0.3019 1.1830 33\n",
" 6 0.2697 1.1367 31\n",
"→ K retenu : 2 (silhouette=0.6092)\n",
" n_comptes pct\n",
"cluster_carmignac_portfolio_flexible_b \n",
"0 968 88.9\n",
"1 121 11.1\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Portfolio Flexible Bond:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_portfolio_flexible_b \n",
"0 0.060 3.924 0.568 -0.155 3.991 81.0 0.000 1.000 0.000\n",
"1 0.738 6.069 1.662 0.121 7.714 0.0 0.683 0.317 0.085\n",
"\n",
"============================================================\n",
"FUND : Carmignac Portfolio Patrimoine\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.5967 0.5513 251\n",
" 3 0.6520 0.5031 170\n",
" 4 0.6269 0.5990 99\n",
" 5 0.6057 0.7167 74\n",
" 6 0.5876 0.7718 66\n",
"→ K retenu : 3 (silhouette=0.6520)\n",
" n_comptes pct\n",
"cluster_carmignac_portfolio_patrimoine \n",
"0 238 20.8\n",
"1 737 64.4\n",
"2 170 14.8\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABM8AAAGGCAYAAABseKbNAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3XlczPkfB/DXdFFKVERFclSOkiRnWrHOde86c+W+2XVUbG5h3RK5crMshRWy1rXkvpIc684RFd33fH9/9GvW6DBNk6nxej4e3wd9v5/v5/v+zmdmmnn3OUSCIAgooBkzZuDjx49YuXIlHB0dcfjwYairq2Ps2LFwcHDAjBkzClolERERERERERFRsSOSJ3kWHx+PCRMm4O7du0hMTETFihURFRUFOzs7bNiwATo6OkURKxERERERERER0VclV/Is27Vr1/DgwQMkJSWhbt26aNasmSJjIyIiIiIiIiIiUqpCJc+IiIiIiIiIiIhUmYa8J4aEhCAkJATR0dEQi8VSx7y9vQsdGBERERERERERkbLJlTzz8fHB2rVrUa9ePVSoUAEikUjRcRERERERERERESmdXMM2W7RogSlTpqBbt25FEBIREREREREREVHxoCbPSenp6bC3t1d0LERERERERERERMWKXMmzH3/8EUeOHFF0LERERERERERERMWKXHOepaamYt++fQgJCYGVlRU0NKSr8fDwUEhwREREREREREREyiRXz7MHDx7A2toaIpEIDx8+xL179yRbeHi4omMkIlJJLi4ucHd3V3YYX9XBgwdhZWWFiIgIZYdCKmTNmjWwsrJSdhgq486dO+jTpw/s7OxgZWVVoM92ub3GBwwYgAEDBhRFqEqjzPdvZf/uCAoKgqOjIxITE5UWQ36WLl2Kn376SdlhEBGRipGr59mOHTsUHQcRkcp48eIFNm3ahAsXLuDdu3fQ1NSEpaUlOnTogN69e6N06dJFHkNycjI2bdoER0dHNG7cuMivV1IdOXIE0dHRGDx4sLJDKXZSU1OxZ88eHD16FE+ePEFaWhpMTEzQvHlzDBgwABYWFsoOUeUcPHhQqve+lpaW5DEfM2YMjIyMFHat9evXo2bNmmjTpo3U/vT0dEyaNAlaWlrw8PBA6dKlYWJiorDrKsKAAQNw5coVyc/6+vqoUqUK+vbtix49ekBNTfa/Df/77784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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Portfolio Patrimoine:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_portfolio_patrimoine \n",
"0 0.040 3.795 0.377 -1.0 5.872 48.0 0.0 1.0 0.0\n",
"1 0.057 5.614 0.460 0.0 5.617 80.0 0.0 1.0 0.0\n",
"2 0.041 4.016 0.463 1.0 5.188 90.0 0.0 1.0 0.0\n",
"\n",
"============================================================\n",
"FUND : Carmignac Emergents\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.4352 1.1739 509\n",
" 3 0.4730 0.8737 290\n",
" 4 0.4057 1.0207 140\n",
" 5 0.2767 1.3023 136\n",
" 6 0.2953 1.2352 136\n",
"→ K retenu : 3 (silhouette=0.4730)\n",
" n_comptes pct\n",
"cluster_carmignac_emergents \n",
"0 347 19.5\n",
"1 1144 64.2\n",
"2 290 16.3\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Emergents:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_emergents \n",
"0 0.070 0.027 1.000 -0.926 3.372 12.0 0.907 0.093 0.000\n",
"1 0.018 2.101 0.425 -1.000 2.718 95.0 0.000 1.000 0.000\n",
"2 0.546 2.578 1.000 -0.168 7.015 0.0 0.181 0.819 0.028\n",
"\n",
"============================================================\n",
"FUND : Carmignac Portfolio Global Bond\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.7574 0.3756 294\n",
" 3 0.8455 0.2185 202\n",
" 4 0.8210 0.3162 97\n",
" 5 0.8302 0.3349 94\n",
" 6 0.8284 0.3586 60\n",
"→ K retenu : 3 (silhouette=0.8455)\n",
" n_comptes pct\n",
"cluster_carmignac_portfolio_global_bon \n",
"0 1246 72.5\n",
"1 270 15.7\n",
"2 202 11.8\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Portfolio Global Bond:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_portfolio_global_bon \n",
"0 0.073 7.429 0.375 0.000 4.430 69.0 0.0 1.0 0.0\n",
"1 0.042 3.957 0.432 -1.000 4.338 60.0 0.0 1.0 0.0\n",
"2 0.066 3.125 0.570 0.955 4.353 71.0 0.0 1.0 0.0\n",
"\n",
"============================================================\n",
"FUND : Carmignac Portfolio Credit\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.7006 0.5926 107\n",
" 3 0.5971 0.6643 36\n",
" 4 0.4844 0.7914 17\n",
" 5 0.2672 1.1071 17\n",
" 6 0.2958 1.0764 17\n",
"→ K retenu : 2 (silhouette=0.7006)\n",
" n_comptes pct\n",
"cluster_carmignac_portfolio_credit \n",
"0 107 10.5\n",
"1 911 89.5\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Portfolio Credit:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_portfolio_credit \n",
"0 0.821 4.720 1.113 0.586 9.596 0.0 1.0 0.0 0.123\n",
"1 0.069 2.483 0.684 0.098 5.963 25.0 0.0 1.0 0.000\n",
"\n",
"============================================================\n",
"FUND : Carmignac Court Terme\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.4719 0.9125 113\n",
" 3 0.4108 0.8594 109\n",
" 4 0.3615 1.1596 108\n",
" 5 0.3464 1.2502 57\n",
" 6 0.3987 1.0217 35\n",
"→ K retenu : 2 (silhouette=0.4719)\n",
" n_comptes pct\n",
"cluster_carmignac_court_terme \n",
"0 414 78.6\n",
"1 113 21.4\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Court Terme:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_court_terme \n",
"0 0.053 7.457 0.335 -0.023 1.945 87.0 0.00 1.00 0.000\n",
"1 0.254 5.379 1.000 0.286 4.609 0.0 0.89 0.11 0.008\n",
"\n",
"============================================================\n",
"FUND : Carmignac Portfolio Emerging Patrimoine\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.5594 1.0477 252\n",
" 3 0.6004 0.7581 133\n",
" 4 0.4796 0.9787 67\n",
" 5 0.4237 1.1134 30\n",
" 6 0.4481 1.0397 35\n",
"→ K retenu : 3 (silhouette=0.6004)\n",
" n_comptes pct\n",
"cluster_carmignac_portfolio_emerging_p \n",
"0 852 74.9\n",
"1 152 13.4\n",
"2 133 11.7\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABM8AAAGGCAYAAABseKbNAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3XdcE+cfB/BPWCIyZIkMQUWDC1yI4qy4N2qrrXsrbutErXWj1roXdW+0KjiKq1ardaB1VESk1o0iyN4z9/uDH9HIMIRAGJ/363Uvzd1zz30vl0vIN88QCYIgoJA0atQIJ0+eRJUqVQrrEERERERERERERIVGrTArL8S8HBERERERERERUaEr1OQZERERERERERFRScbkGRERERERERERUS6YPCMiIiIiIiIiIspFoSbPRCJRYVZPRERERERERERUqDhhABERERERERERUS5EQiFmuP7++284ODhAS0ursA5BRERERERERERUaBRKnnl4eORcmUiEcuXKwdraGu3atUPFihULGh8REREREREREZHKKJQ8Gzx4MB4/fgyJRIJq1aoBAF68eAF1dXVUr14dL168gEgkwqFDh1CjRg2lB01ERERERERERFQUFBrzrF27dmjevDmuXbuGEydO4MSJE7h69SqaN2+Obt264erVq3B0dMy1hRoRUWFycXHBnDlzVB1GkTpx4gTs7OwQHBys6lCoFNm4cSPs7OxUHUap8fDhQ3z77bdo0KAB7OzsEBgYKPe+Od3jgwcPxuDBgwsj1FKlrD9PdnZ22LhxY5k7NgBs374dnTt3hkQiUVkMeZk2bRqmTJmi6jCIiEgOGorstHPnTuzevRu6urrSdXp6epg0aRJGjBiBoUOHYsKECRgxYoTSAiUiev36NXbs2IHr168jLCwMmpqaEIvF6NKlC/r37w9tbe1CjyEpKQk7duyAk5MTmjZtWujHK6lOnz6NiIgIDBs2TNWhFDspKSk4fPgwfvvtNzx//hypqamwsLBAixYtMHjwYGmLblKeEydOwN3dXfpYS0tL+pyPHz8eJiYmSjvWtm3bUKNGDbRv315mfVpaGqZOnQotLS24u7tDW1sbFhYWSjuuMgwePBi3b9/OcVu1atVw7ty5Io6o5HNxccHbt2+lj42MjFCtWjUMHz4cHTp0yFdd9+7dw/Xr1zF06FDo6+srO9RSJz4+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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Portfolio Emerging Patrimoine:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_portfolio_emerging_p \n",
"0 0.038 3.156 0.500 -0.613 5.213 83.0 0.000 1.000 0.000\n",
"1 0.037 0.283 1.000 -0.142 5.668 29.0 0.926 0.074 0.000\n",
"2 0.714 4.279 2.212 -0.115 9.002 0.0 0.218 0.782 0.063\n",
"\n",
"============================================================\n",
"FUND : Carmignac Portfolio Grande Europe\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.3724 1.1306 232\n",
" 3 0.3474 1.1547 218\n",
" 4 0.2732 1.3479 165\n",
" 5 0.2529 1.3471 147\n",
" 6 0.2597 1.3180 118\n",
"→ K retenu : 2 (silhouette=0.3724)\n",
" n_comptes pct\n",
"cluster_carmignac_portfolio_grande_eur \n",
"0 232 16.7\n",
"1 1156 83.3\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABNwAAAGGCAYAAACg4ZwmAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3XdYE1nbBvA7AaIiRQEFBbGDBRAbKrYVWV17W7E3UBQFe8GyWFBR1y7YFXtva8Gy9oZl7SiWxYKFVQQBKUrJfH/4kZcYwBDBQLx/15VLczJz5pmcTEienCISBEFADjk5OUEkEmX5+KlTp3JaJRERERERERERkUbQVmWnfv36yd1PTU3FgwcPcPHiRbi5ueVKYERERERERERERAVRriTc0m3duhUhISHfFRAREREREREREVFBJs7Nypo0aYLjx4/nZpVEREREREREREQFSq4m3I4dO4ZixYrlZpVEREREREREREQFikpDSjt27Ci3aIIgCHj//j2io6MxderUXAuOiIiIiIiIiIiooFEp4ebs7Cx3XyQSwcjICA4ODqhYsWKuBEZERERERERERFQQiQRBENQdBBERERERERERkaZQeQ638PBwLFq0CKNHj0ZUVBQA4Ny5c3jy5EmuBUdERERERERERFTQqJRwu3btGtq1a4e7d+/ixIkTSExMBAA8evQIy5Yty9UAiYiIiIiIiIiIChKVEm4LFizAyJEjERgYCB0dHVl5/fr1cfv27dyKjYgo33JycoK3t7e6w/ih9u3bB2tra7x69UrdoZAGWbZsGaytrdUdhsa4e/cuunfvDnt7e1hbWyM0NFTpfTO7xvv06YM+ffrkRagFCl+nuS8hIQENGjTAwYMH1R1Kpv79919Uq1YNjx8/VncoRERUQKm0aMLjx48xf/58hXIjIyN8+PDhu4MiIlKX8PBwrF27FpcuXcK7d++go6MDKysrtGrVCt26dUPhwoXzPIakpCSsXbsWDg4OqFevXp4fr6A6dOgQoqKi0L9/f3WHku98/vwZ27dvx5EjR/D06VMkJyejdOnSaNiwIfr06YPy5curO0SNs2/fPkycOFF2XyKRyJ7zoUOHwsTEJNeOtXLlSlSqVElhEauUlBSMHDkSEokEEydOROHChVG6dOlcO25uOn36NHbt2oW7d+8iLi4Ourq6qFy5Mpo3bw4XFxfo6emp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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Portfolio Grande Europe:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_portfolio_grande_eur \n",
"0 0.519 4.254 1.000 -0.034 7.587 0.0 0.398 0.602 0.034\n",
"1 0.029 1.860 0.593 -0.524 4.094 81.0 0.000 1.000 0.000\n",
"\n",
"============================================================\n",
"FUND : Carmignac Portfolio Long-Short European Equities\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.3490 1.3508 188\n",
" 3 0.3819 1.0101 118\n",
" 4 0.3969 0.9225 54\n",
" 5 0.3524 1.0438 54\n",
" 6 0.3727 1.0432 46\n",
"→ K retenu : 4 (silhouette=0.3969)\n",
" n_comptes pct\n",
"cluster_carmignac_portfolio_long-short \n",
"0 111 18.3\n",
"1 335 55.2\n",
"2 107 17.6\n",
"3 54 8.9\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Portfolio Long-Short European Equities:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_portfolio_long-short \n",
"0 0.056 3.823 0.412 -1.000 4.991 29.0 0.0 1.0 0.0\n",
"1 0.114 6.651 0.635 0.000 6.755 32.0 0.0 1.0 0.0\n",
"2 0.125 1.688 1.000 0.537 7.833 3.0 1.0 0.0 0.0\n",
"3 0.041 4.727 0.348 1.000 5.110 56.0 0.0 1.0 0.0\n",
"\n",
"============================================================\n",
"FUND : Carmignac Portfolio Climate Transition\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.6659 0.6413 156\n",
" 3 0.5623 0.7455 57\n",
" 4 0.3956 1.0145 37\n",
" 5 0.2261 1.2444 37\n",
" 6 0.2237 1.2368 18\n",
"→ K retenu : 2 (silhouette=0.6659)\n",
" n_comptes pct\n",
"cluster_carmignac_portfolio_climate_tr \n",
"0 156 12.2\n",
"1 1124 87.8\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABNwAAAGGCAYAAACg4ZwmAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3XVYlNnbB/DvDDAqEgooBooJKIJYqFgrdtfahdjdCshiAKKuLaJYGGsHrq4Ya7uKxVooxmKiqIQ0CsLz/uHL/BgJh3FwYPx+rmsu5cx5znM/nMmbEyJBEATk0cWLF7F8+XJMnjwZlpaW0NbWlrlfR0cnr00SERERERERERGpBZEiCTcLC4v/NSASSf8vCAJEIhFCQkKUEx0REREREREREVEho6nIQdu3b1d2HERERERERERERGpBoYSbiYkJypYtKzO6Dfgywi08PFwpgRERERERERERERVGYkUOatWqFaKjo7OUx8TEoFWrVt8dFBERERERERERUWGlUMItY622ryUlJaFIkSLfHRQREREREREREVFhlacppV5eXgC+bJSwcuVKFCtWTHpfWloa7t69K7OhAhERERERERER0c8mTwm3Bw8eAPgywu3x48fQ0tKS3ieRSGBhYQFHR0flRkhERERERERERFSIiARBEPJ6kLOzM+bMmQMdHZ1c6719+xalS5eGWKzQzFUiIiIiIiIiIqJCR6GEm7zq1q2LP//8ExUqVMivUxARERERERERERUo+Tr0LB9zeURESmNvbw8nJydVh/FDHTp0CObm5ggLC1N1KKRG1qxZA3Nzc1WHoTbu3r2Lfv36wcbGBubm5ggJCZH72Oye44MHD8bgwYPzI9RvunbtGszNzXHt2jVpmZOTE+zt7VUSD32Rlz5Q9fM7PDwcVlZWCAoKUlkMubl48SLq1KmD6OhoVYdCREQFRJ7WcCMiKkxevnyJTZs24fLly3j//j20tLRgZmaGDh06oG/fvihatGi+x5CcnIxNmzbB1tYWDRs2zPfzFVZHjx5FVFQUHBwcVB1KgfPp0yfs3r0bx44dw9OnT5GSkoJy5cqhSZMmGDx4MCpXrqzqENXOoUOH4OzsLP1ZIpFIf+fjxo2DkZGR0s61fv16VKtWDa1bt5YpT01NxZQpUyCRSODs7IyiRYuiXLlySjuvMv3999/Yu3cv7t27h8TERJQoUQL16tVDv3790LhxY1WHly1lv+Zcu3YNQ4YMkavuo0ePlHLO/FCQ37PWrl2L2rVro169etIyJycnnDx5Erdu3ZKp+/DhQwwdOhTFixfH9u3bYWJiotA5k5OTcejQIZw5cwaPHz9GYmIiTE1N0adPH/Tt2xcaGhrSus2bN0fFihXh6+sr8/pBREQ/LybciEgtnT9/HpMnT4ZEIkG3bt1gZmaG1NRUBAUF4ffff8d///0Hd3f3fI8jOTkZ3t7emDBhQoH68tKtWzd06tQJEolE1aEAAP766y88efKECbevREdHY8SIEbh//z5atmyJzp07Q1tbG8+ePUNAQAD27duH4OBgVYcpNXbsWIwaNUrVYSjNpEmTYGJigpSUFAQFBWH37t24cOEC/vrrL5md2r+Hr68v2rVrlyXh9vLlS7x+/RoeHh7o3bu3Us61efNmpbSTQRAEuLi44NChQ6hZsyaGDRsGIyMjRERE4O+//4aDgwN2796NunXrZnu8u7u7ymZDKPs1p2rVqliyZIlM2fLly6GtrY0xY8Yo5Rz54es+yO09S5XP7+joaBw+fBiLFi36Zt3Hjx/DwcEB2tra2LZtm8LJNgB49eoV3N3d0bhxYzg4OEBHRwf//PMP5s+fjzt37mDx4sUy9fv27YslS5Zg4sSJ31zrmoiI1B8TbkSkdl69eoWpU6eiXLly2LZtG0qXLi29b+DAgXjx4gXOnz+vugCVICkpCdra2gofr6GhIfOXeXWVnJystMSIKjg7OyMkJASrV69Gu3btZO6bMmUKVqxYoZTzfO/jKYOmpiY0NdXno0Xz5s1hZWUFAOjduzdKlCgBPz8/nDlzBp07d1a4XUEQ8OnTp1xH2WZMS9PV1VX4PF9TdoJ9y5YtOHToEIYOHQpnZ2eIRCLpfWPHjsXhw4dzfTxk3u2+sDMyMkK3bt1kyjZu3IiSJUtmKc8sPT0dqampKFKkSH6HmK289IEqn99HjhyBhoYGWrZsmWu9J0+eYOjQoShatCi2b9/+3etIGxkZ4ejRo6hevbq0rF+/fnB2dsahQ4cwbtw4mJqaSu9r164dPDw8cOLECfz666/fdW4iIir88nUNt8wfvIiIfpRNmzYhKSkJnp6eMsm2DKamphg6dGiOx+e0Tk12ayLdu3cPw4cPR8OGDWFtbQ17e3vpVJKwsDDpdCpvb2+Ym5vD3Nwca9askR4fGhqKSZMmwdbWFlZWVujZsyfOnDmT7XmvX7+OefPmoXHjxmjRokWuv4MdO3agU6dOqF27Nho0aICePXvi6NGjuV5Leno61qxZg6ZNm6J27doYPHgw/vvvvyxr3GUcGxQUBC8vLzRq1Ag2NjYYP358lrVrTp8+jVGjRqFp06aoVasWWrdujbVr1yItLU1aZ/DgwTh//jxev34t/R1lrCmU01pz2a0HNXjwYHTu3BnBwcEYOHAgateujeXLlwMAUlJSsHr1arRp0wa1atVCixYtsGTJEqSkpMi0e/nyZfTv3x/169dHnTp10K5dO2kbP9qdO3dw/vx5/Prrr1mSbcCX5Mns2bOlPz98+BBOTk5o1aoVrKys0KRJEzg7O+PDhw8yx2U8vv/77z9Mnz4dDRo0wIABAwB8Wc9w9OjRuHbtGnr27Alra2t06dJF+ns+deoUunTpIn2sPnjwINu2M/v48SM8PDzQsGFD1KlTB2PGjMG7d++yPBcyjn3x4gWcnJxQv3591KtXD87OzkhOTpZp8+DBgxgyZAgaN26MWrVqoWPHjti1a1e2v8cLFy5g0KBBqFOnDurWrYtevXrJPBfyolGjRgAgfTx+/vwZa9euRevWrVGrVi3Y29tj+fLlWR5XGb/XS5cuSX+ve/bsgbm5OZKSkuDv7y997Ds5OcHJyQmDBg0CAEyePBnm5uYya68FBgZiwIABsLGxQf369TF27FiEhoZ+M/7s1nCLioqCi4sL7OzsYGVlha5du8Lf3/+bbX38+BEbNmxAlSpVMHv27Gw/83Xv3h3W1tY5tvH1+mFhYWEwNzfH5s2bsXPnTrRq1Qq1a9eGo6MjwsPDIQgC1q5di+bNm8Pa2hpjx45FTEyMTJvf+5oDyP96oQhzc3MsWLAAR44cQadOnWBlZYVLly4B+DICsV+/ftL3k549e+LEiRM5tnH69Gl07twZtWrVQqdOnXDx4kWZegkJCfD09IS9vT1q1aqFxo0bY9iwYbh//760TuY++NZ7VnbP77w+B27evIlff/0VVlZWaNWqFQ4fPizX7+306dOwtrZG8eLFc6wTGhoKBwcHSCQSpSTbAMDAwEAm2ZahTZs20nNmZmhoCHNz8yzv40RE9HPK1z9TcdMEIlKFc+fOoUKFCjlOY1KWqKgoDB8+HCVLlsSoUaOgp6eHsLAw/P333wC+fFCfN28e5s2bhzZt2kg/oGd8YXny5An69+8PY2NjjBw5Etra2jh+/DjGjx+PNWvWSOtnmD9/PgwMDDB+/HgkJSXlGNe+ffvg4eGBdu3aYciQIfj06RMePXqEO3fuoEuXLjket2zZMmzatAktW7ZEs2bN8PDhQwwfPhyfPn3Ktr6Hhwf09PQwYcIEvH79Gtu2bcOCBQuwcuVKaR1/f39oa2tj2LBh0NbWxtWrV7F69WokJCRIk0VjxoxBfHw83r59K01W5valKjcxMTEYOXIkOnXqhK5du8LQ0BDp6ekYO3YsgoKC0KdPH1StWhWPHz/Gtm3b8Pz5c/j4+AD40h+jR4+Gubk5Jk2aBIlEghcvXuDff/9VKJbvdfbsWQDIdXRMZleuXMGrV6/Qs2dPlCpVCk+ePMG+ffvw33//Yd++fVkSIpMnT4apqSmmTp0q83794sULTJ8+Hf369UPXrl2xZcsWjBk
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Portfolio Climate Transition:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_portfolio_climate_tr \n",
"0 0.679 5.287 0.962 -0.049 7.379 7.0 0.0 1.0 0.044\n",
"1 0.025 1.496 0.584 -0.792 4.221 92.0 0.0 1.0 0.000\n",
"\n",
"============================================================\n",
"FUND : Carmignac Absolute Return Europe\n",
"============================================================\n",
" k silhouette davies_bouldin min_cluster_size\n",
" 2 0.4593 0.9283 146\n",
" 3 0.5112 0.7321 122\n",
" 4 0.4436 0.9496 72\n",
" 5 0.4150 1.0153 42\n",
" 6 0.3870 1.0866 28\n",
"→ K retenu : 3 (silhouette=0.5112)\n",
" n_comptes pct\n",
"cluster_carmignac_absolute_return_euro \n",
"0 180 19.7\n",
"1 122 13.3\n",
"2 612 67.0\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Médianes — Carmignac Absolute Return Europe:\n",
" flow_freq gross_flow_to_aum avg_n_isin_held flow_direction_balance log_aum_qty_mean months_since_last_tx_fund aum_final_to_peak aum_drawdown_last buy_on_perf_rate\n",
"cluster_carmignac_absolute_return_euro \n",
"0 0.052 0.298 1.000 -0.882 4.301 16.5 0.907 0.093 0.000\n",
"1 0.532 5.635 0.973 -0.020 7.317 35.5 0.000 1.000 0.047\n",
"2 0.038 2.433 0.488 -0.539 4.221 81.0 0.000 1.000 0.000\n",
"\n",
"============================================================\n",
"RÉSUMÉ — Clustering par fund\n",
"============================================================\n",
" Carmignac Patrimoine : K=2, sil=0.5061, n=3155\n",
" Carmignac Sécurité : K=2, sil=0.5716, n=1624\n",
" Carmignac Investissement : K=2, sil=0.4310, n=2194\n",
" Carmignac Portfolio Sécurité : K=2, sil=0.7984, n=1163\n",
" Carmignac Portfolio Flexible Bond : K=2, sil=0.6092, n=1089\n",
" Carmignac Portfolio Patrimoine : K=3, sil=0.6520, n=1145\n",
" Carmignac Emergents : K=3, sil=0.4730, n=1781\n",
" Carmignac Portfolio Global Bond : K=3, sil=0.8455, n=1718\n",
" Carmignac Portfolio Credit : K=2, sil=0.7006, n=1018\n",
" Carmignac Court Terme : K=2, sil=0.4719, n=527\n",
" Carmignac Portfolio Emerging Patrimoine : K=3, sil=0.6004, n=1137\n",
" Carmignac Portfolio Grande Europe : K=2, sil=0.3724, n=1388\n",
" Carmignac Portfolio Long-Short European : K=4, sil=0.3969, n=607\n",
" Carmignac Portfolio Climate Transition : K=2, sil=0.6659, n=1280\n",
" Carmignac Absolute Return Europe : K=3, sil=0.5112, n=914\n",
"\n",
"============================================================\n",
"ARI — cohérence clustering global x fund\n",
"============================================================\n",
" Carmignac Patrimoine : ARI=0.0241 (n=3002)\n",
" Carmignac Sécurité : ARI=0.0121 (n=1478)\n",
" Carmignac Investissement : ARI=0.0427 (n=2055)\n",
" Carmignac Portfolio Sécurité : ARI=0.0813 (n=1047)\n",
" Carmignac Portfolio Flexible Bond : ARI=-0.0456 (n=945)\n",
" Carmignac Portfolio Patrimoine : ARI=0.0116 (n=1030)\n",
" Carmignac Emergents : ARI=0.0158 (n=1641)\n",
" Carmignac Portfolio Global Bond : ARI=0.0797 (n=1585)\n",
" Carmignac Portfolio Credit : ARI=0.0087 (n=902)\n",
" Carmignac Court Terme : ARI=-0.0346 (n=424)\n",
" Carmignac Portfolio Emerging Patrimoine : ARI=-0.0337 (n=998)\n",
" Carmignac Portfolio Grande Europe : ARI=-0.0266 (n=1248)\n",
" Carmignac Portfolio Long-Short European : ARI=0.0524 (n=496)\n",
" Carmignac Portfolio Climate Transition : ARI=-0.0461 (n=1143)\n",
" Carmignac Absolute Return Europe : ARI=-0.0319 (n=788)\n"
]
}
],
"source": [
"# ============================================================\n",
"# CLUSTERING PAR FUND FAMILY (top fonds)\n",
"# ============================================================\n",
"\n",
"# ── 0. Vérification des fonds disponibles ─────────────────────────────────\n",
"print(\"=== Fonds disponibles (top 20 par AUM) ===\")\n",
"top_funds_aum = (\n",
" df_aum.groupby(FUND_COL)[AUM_VAL_COL].sum()\n",
" .sort_values(ascending=False)\n",
" .head(20)\n",
")\n",
"print(top_funds_aum.to_string())\n",
"\n",
"# ── 1. Sélection des top fonds ────────────────────────────────────────────\n",
"# Critères : top 15 par AUM total + au moins 20 clients\n",
"min_clients_per_fund = 20\n",
"n_top_funds = 15\n",
"\n",
"aum_by_fund_total = df_aum.groupby(FUND_COL)[AUM_VAL_COL].sum()\n",
"clients_by_fund = df_aum.groupby(FUND_COL)[ID_COL].nunique()\n",
"\n",
"valid_funds = (\n",
" aum_by_fund_total[\n",
" clients_by_fund >= min_clients_per_fund\n",
" ]\n",
" .sort_values(ascending=False)\n",
" .head(n_top_funds)\n",
" .index.tolist()\n",
")\n",
"print(f\"\\nFonds retenus ({len(valid_funds)}) :\")\n",
"for f in valid_funds:\n",
" print(f\" {f} : {clients_by_fund[f]} clients, AUM={aum_by_fund_total[f]:.0f}\")\n",
"\n",
"# ── 2. Construction du panel par compte x fund ────────────────────────────\n",
"df_rel_m_fund = df_rel_m.copy()\n",
"df_rel_m_fund = df_rel_m_fund.merge(\n",
" df_aum[[ID_COL, ISIN_COL, \"month\", FUND_COL]].drop_duplicates(),\n",
" on=[ID_COL, ISIN_COL, \"month\"],\n",
" how=\"left\"\n",
")\n",
"\n",
"# Panel mensuel par compte x fund\n",
"tmp_fund = df_rel_m_fund.copy()\n",
"tmp_fund[\"isin_held_flag\"] = (tmp_fund[\"aum_qty\"] > 0).astype(int)\n",
"tmp_fund[\"isin_active_flag\"] = (tmp_fund[\"gross_flow_qty\"] > 0).astype(int)\n",
"\n",
"df_month_fund = (\n",
" tmp_fund.dropna(subset=[FUND_COL])\n",
" .groupby([ID_COL, FUND_COL, \"month\"], as_index=False)\n",
" .agg(\n",
" aum_qty = (\"aum_qty\", \"sum\"),\n",
" net_flow_qty = (\"net_flow_qty\", \"sum\"),\n",
" gross_flow_qty = (\"gross_flow_qty\", \"sum\"),\n",
" sub_qty = (\"sub_qty\", \"sum\"),\n",
" red_qty = (\"red_qty\", \"sum\"),\n",
" n_tx = (\"n_tx\", \"sum\"),\n",
" n_isin_held = (\"isin_held_flag\", \"sum\"),\n",
" ret_fund_m = (\"ret_fund_m\", \"mean\"),\n",
" )\n",
" .sort_values([ID_COL, FUND_COL, \"month\"])\n",
" .reset_index(drop=True)\n",
")\n",
"\n",
"df_month_fund[\"active_month\"] = (df_month_fund[\"gross_flow_qty\"] > 0).astype(int)\n",
"df_month_fund[\"flow_direction\"] = np.where(\n",
" df_month_fund[\"gross_flow_qty\"] > 0,\n",
" df_month_fund[\"net_flow_qty\"] / df_month_fund[\"gross_flow_qty\"],\n",
" np.nan\n",
")\n",
"df_month_fund[\"sub_share\"] = np.where(\n",
" df_month_fund[\"gross_flow_qty\"] > 0,\n",
" df_month_fund[\"sub_qty\"] / df_month_fund[\"gross_flow_qty\"],\n",
" np.nan\n",
")\n",
"df_month_fund[\"aum_peak\"] = df_month_fund.groupby(\n",
" [ID_COL, FUND_COL]\n",
")[\"aum_qty\"].cummax()\n",
"df_month_fund[\"aum_drawdown\"] = np.where(\n",
" df_month_fund[\"aum_peak\"] > 0,\n",
" 1 - df_month_fund[\"aum_qty\"] / df_month_fund[\"aum_peak\"],\n",
" np.nan\n",
")\n",
"\n",
"# Lag performance pour réactivité\n",
"df_month_fund[\"ret_fund_lag1\"] = df_month_fund.groupby(\n",
" [ID_COL, FUND_COL]\n",
")[\"ret_fund_m\"].shift(1)\n",
"df_month_fund[\"buy_on_perf\"] = (\n",
" (df_month_fund[\"net_flow_qty\"] > 0) &\n",
" (df_month_fund[\"ret_fund_lag1\"] > 0)\n",
").astype(int)\n",
"df_month_fund[\"has_perf\"] = df_month_fund[\"ret_fund_lag1\"].notna().astype(int)\n",
"\n",
"print(\"\\ndf_month_fund shape:\", df_month_fund.shape)\n",
"\n",
"# ── 3. Feature engineering par compte x fund ──────────────────────────────\n",
"reference_date = df_month_fund[\"month\"].max()\n",
"\n",
"# months_since_last_tx par fund\n",
"last_active_fund = (\n",
" df_month_fund[df_month_fund[\"active_month\"] == 1]\n",
" .groupby([ID_COL, FUND_COL])[\"month\"]\n",
" .max()\n",
" .reset_index(name=\"last_active_month\")\n",
")\n",
"last_active_fund[\"months_since_last_tx_fund\"] = (\n",
" (reference_date.to_period(\"M\") -\n",
" last_active_fund[\"last_active_month\"].dt.to_period(\"M\"))\n",
" .apply(lambda x: x.n)\n",
")\n",
"\n",
"df_client_fund = (\n",
" df_month_fund.groupby([ID_COL, FUND_COL], as_index=False)\n",
" .agg(\n",
" n_months = (\"month\", \"nunique\"),\n",
" n_active_months = (\"active_month\", \"sum\"),\n",
" flow_freq = (\"active_month\", \"mean\"),\n",
" aum_qty_mean = (\"aum_qty\", \"mean\"),\n",
" aum_qty_max = (\"aum_qty\", \"max\"),\n",
" aum_qty_last = (\"aum_qty\", \"last\"),\n",
" gross_flow_qty_sum = (\"gross_flow_qty\", \"sum\"),\n",
" net_flow_qty_sum = (\"net_flow_qty\", \"sum\"),\n",
" n_tx_total = (\"n_tx\", \"sum\"),\n",
" avg_n_isin_held = (\"n_isin_held\", \"mean\"),\n",
" flow_direction_mean = (\"flow_direction\", \"mean\"),\n",
" sub_share_mean = (\"sub_share\", \"mean\"),\n",
" aum_drawdown_last = (\"aum_drawdown\", \"last\"),\n",
" buy_on_perf_months = (\"buy_on_perf\", \"sum\"),\n",
" has_perf_months = (\"has_perf\", \"sum\"),\n",
" )\n",
")\n",
"\n",
"# Merge months_since_last_tx\n",
"df_client_fund = df_client_fund.merge(\n",
" last_active_fund[[ID_COL, FUND_COL, \"months_since_last_tx_fund\"]],\n",
" on=[ID_COL, FUND_COL], how=\"left\"\n",
")\n",
"max_months = df_client_fund[\"months_since_last_tx_fund\"].max()\n",
"df_client_fund[\"months_since_last_tx_fund\"] = (\n",
" df_client_fund[\"months_since_last_tx_fund\"].fillna(max_months + 1)\n",
")\n",
"\n",
"# Ratios protégés\n",
"df_client_fund[\"gross_flow_to_aum\"] = np.where(\n",
" df_client_fund[\"aum_qty_mean\"] > 1,\n",
" df_client_fund[\"gross_flow_qty_sum\"] / df_client_fund[\"aum_qty_mean\"],\n",
" np.nan\n",
")\n",
"df_client_fund[\"flow_direction_balance\"] = np.where(\n",
" df_client_fund[\"gross_flow_qty_sum\"] > 0,\n",
" df_client_fund[\"net_flow_qty_sum\"] / df_client_fund[\"gross_flow_qty_sum\"],\n",
" np.nan\n",
")\n",
"df_client_fund[\"aum_final_to_peak\"] = np.where(\n",
" df_client_fund[\"aum_qty_max\"] > 0,\n",
" np.clip(df_client_fund[\"aum_qty_last\"] / df_client_fund[\"aum_qty_max\"], 0, 1),\n",
" np.nan\n",
")\n",
"df_client_fund[\"log_aum_qty_mean\"] = np.log1p(\n",
" df_client_fund[\"aum_qty_mean\"].clip(lower=0)\n",
")\n",
"df_client_fund[\"buy_on_perf_rate\"] = np.where(\n",
" df_client_fund[\"has_perf_months\"] >= 6,\n",
" df_client_fund[\"buy_on_perf_months\"] / df_client_fund[\"has_perf_months\"],\n",
" np.nan\n",
")\n",
"\n",
"# Filtre qualité\n",
"df_client_fund = df_client_fund[\n",
" (df_client_fund[\"n_months\"] >= 6) &\n",
" (df_client_fund[\"aum_qty_mean\"] > 0) &\n",
" (df_client_fund[FUND_COL].isin(valid_funds))\n",
"].copy()\n",
"\n",
"print(\"df_client_fund shape:\", df_client_fund.shape)\n",
"print(\"\\nComptes par fund :\")\n",
"print(df_client_fund.groupby(FUND_COL)[ID_COL].nunique().sort_values(ascending=False))\n",
"\n",
"# ── 4. Features pour le clustering par fund ───────────────────────────────\n",
"fund_features = [\n",
" \"flow_freq\",\n",
" \"gross_flow_to_aum\",\n",
" \"avg_n_isin_held\",\n",
" \"flow_direction_balance\",\n",
" \"log_aum_qty_mean\",\n",
" \"months_since_last_tx_fund\",\n",
" \"aum_final_to_peak\",\n",
" \"aum_drawdown_last\",\n",
" \"buy_on_perf_rate\",\n",
"]\n",
"\n",
"# ── 5. Clustering par fund ────────────────────────────────────────────────\n",
"FUND_RESULTS = {}\n",
"\n",
"for fund in valid_funds:\n",
" print(f\"\\n{'='*60}\")\n",
" print(f\"FUND : {fund}\")\n",
" print(f\"{'='*60}\")\n",
"\n",
" df_f = df_client_fund[df_client_fund[FUND_COL] == fund].copy()\n",
" feats = [c for c in fund_features if c in df_f.columns]\n",
"\n",
" # Preprocessing\n",
" d = df_f.copy()\n",
" d[\"flow_direction_balance\"] = d[\"flow_direction_balance\"].fillna(0)\n",
" d[\"buy_on_perf_rate\"] = d[\"buy_on_perf_rate\"].fillna(0)\n",
"\n",
" for col in [\"avg_n_isin_held\", \"months_since_last_tx_fund\",\n",
" \"aum_drawdown_last\", \"aum_final_to_peak\"]:\n",
" if col not in d.columns:\n",
" continue\n",
" vals = d[col].to_numpy(dtype=float)\n",
" med = np.nanmedian(vals)\n",
" mad = np.nanmedian(np.abs(vals - med)) * 1.4826\n",
" if mad > 0:\n",
" d[col] = np.clip(vals, med - 3*mad, med + 3*mad)\n",
" else:\n",
" d[col] = np.clip(vals, 0, np.nanpercentile(vals, 95))\n",
"\n",
" for col in [\"gross_flow_to_aum\"]:\n",
" if col not in d.columns:\n",
" continue\n",
" vals = d[col].to_numpy(dtype=float)\n",
" d[col] = np.log1p(np.clip(vals, 0, np.nanpercentile(vals, 90)))\n",
"\n",
" for col in [\"flow_freq\"]:\n",
" if col not in d.columns:\n",
" continue\n",
" vals = d[col].to_numpy(dtype=float)\n",
" d[col] = np.log1p(np.clip(vals, 0, None))\n",
"\n",
" X_f = d[feats].fillna(d[feats].median()).to_numpy()\n",
" X_f_scaled = RobustScaler().fit_transform(X_f)\n",
"\n",
" # K-selection\n",
" best_k = 2\n",
" best_sil = -1\n",
" rows_k = []\n",
" max_k = min(6, len(df_f) // 20)\n",
"\n",
" for k in range(2, max_k + 1):\n",
" km = KMeans(n_clusters=k, n_init=30, random_state=RANDOM_STATE)\n",
" labels = km.fit_predict(X_f_scaled)\n",
" # Vérifier que les clusters ne sont pas trop déséquilibrés\n",
" sizes = pd.Series(labels).value_counts()\n",
" if sizes.min() < 10:\n",
" continue\n",
" sil = silhouette_score(X_f_scaled, labels)\n",
" db = davies_bouldin_score(X_f_scaled, labels)\n",
" rows_k.append({\n",
" \"k\": k,\n",
" \"silhouette\": round(sil, 4),\n",
" \"davies_bouldin\": round(db, 4),\n",
" \"min_cluster_size\": sizes.min(),\n",
" })\n",
" if sil > best_sil:\n",
" best_sil = sil\n",
" best_k = k\n",
"\n",
" df_k = pd.DataFrame(rows_k)\n",
" print(df_k.to_string(index=False))\n",
" print(f\"→ K retenu : {best_k} (silhouette={best_sil:.4f})\")\n",
"\n",
" # Clustering final\n",
" km_final = KMeans(n_clusters=best_k, n_init=50, random_state=RANDOM_STATE)\n",
" cluster_col = f\"cluster_{fund.lower().replace(' ','_')[:30]}\"\n",
" df_f[cluster_col] = km_final.fit_predict(X_f_scaled)\n",
"\n",
" # Tailles\n",
" counts = df_f[cluster_col].value_counts().sort_index()\n",
" props = counts / counts.sum() * 100\n",
" print(pd.DataFrame({\"n_comptes\": counts, \"pct\": props.round(1)}))\n",
"\n",
" # Heatmap\n",
" profile_vars_fund = [c for c in fund_features if c in df_f.columns]\n",
" prof = plot_heatmap(\n",
" df_f, profile_vars_fund, cluster_col,\n",
" title=f\"Cluster signatures — {fund[:40]} (K={best_k})\",\n",
" figsize=(14, 4)\n",
" )\n",
" print(f\"\\nMédianes — {fund}:\")\n",
" print(prof.round(3).to_string())\n",
"\n",
" FUND_RESULTS[fund] = {\n",
" \"df\": df_f,\n",
" \"cluster_col\": cluster_col,\n",
" \"k\": best_k,\n",
" \"silhouette\": best_sil,\n",
" \"profile\": prof,\n",
" \"n\": len(df_f),\n",
" }\n",
"\n",
"# ── 6. Résumé global ──────────────────────────────────────────────────────\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(\"RÉSUMÉ — Clustering par fund\")\n",
"print(\"=\"*60)\n",
"for fund, res in FUND_RESULTS.items():\n",
" print(f\" {fund[:40]:40s} : K={res['k']}, \"\n",
" f\"sil={res['silhouette']:.4f}, n={res['n']}\")\n",
"\n",
"# ── 7. Croisement avec le clustering global ───────────────────────────────\n",
"print(\"\\n\" + \"=\"*60)\n",
"print(\"ARI — cohérence clustering global x fund\")\n",
"print(\"=\"*60)\n",
"\n",
"dfc_fund_cross = dfc[[ID_COL, \"cluster_k4\"]].copy()\n",
"\n",
"for fund, res in FUND_RESULTS.items():\n",
" cluster_col = res[\"cluster_col\"]\n",
" df_f = res[\"df\"][[ID_COL, cluster_col]].copy()\n",
" dfc_fund_cross = dfc_fund_cross.merge(df_f, on=ID_COL, how=\"left\")\n",
"\n",
" mask = dfc_fund_cross[cluster_col].notna()\n",
" if mask.sum() < 10:\n",
" continue\n",
" labels_global = dfc_fund_cross.loc[mask, \"cluster_k4\"].values\n",
" labels_fund = dfc_fund_cross.loc[mask, cluster_col].values\n",
" ari = adjusted_rand_score(labels_global, labels_fund)\n",
" print(f\" {fund[:40]:40s} : ARI={ari:.4f} (n={mask.sum()})\")"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "c51b1018-5439-4927-9d4e-7d56a22ac4f3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"======================================================================\n",
"PARTIE 2 — CLUSTERING 400 GRANDS COMPTES (Louis)\n",
"======================================================================\n",
"Comptes sélectionnés (AUM > 5M€) : 431\n",
"After filters: 427 accounts\n",
"Accounts: 427 | Features: 16\n",
"Points > 5 std after scaling: 38 (8.9%)\n",
" k inertia silhouette davies_bouldin\n",
" 2 4295.803536 0.648934 0.554878\n",
" 3 3612.735780 0.271561 1.316068\n",
" 4 3157.857186 0.201780 1.498467\n",
" 5 2952.884036 0.197975 1.433778\n",
" 6 2760.262346 0.152972 1.688634\n",
" 7 2593.416835 0.180291 1.599408\n",
" 8 2486.253809 0.171637 1.658369\n",
" 9 2404.806299 0.146315 1.714646\n",
"10 2333.195111 0.150386 1.685274\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1500x400 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"K=2 | sil=0.6489 | db=0.5549\n",
" n_comptes pct\n",
"cluster_k2 \n",
"0 389 91.1\n",
"1 38 8.9\n",
"\n",
"K=4 | sil=0.2018 | db=1.4985\n",
" n_comptes pct\n",
"cluster_k4 \n",
"0 71 16.6\n",
"1 36 8.4\n",
"2 217 50.8\n",
"3 103 24.1\n",
"\n",
"K=5 | sil=0.1985 | db=1.4319\n",
" n_comptes pct\n",
"cluster_k5 \n",
"0 67 15.7\n",
"1 29 6.8\n",
"2 90 21.1\n",
"3 229 53.6\n",
"4 12 2.8\n",
"\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1600x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"=== Médianes K=2 (Louis) ===\n",
" log_aum_qty_mean gross_flow_to_aum flow_freq n_tx_total avg_n_isin_held n_isin_total avg_holding_months_per_isin exit_rate_per_isin flow_direction_balance aum_drawdown_last aum_final_to_peak months_since_last_tx corr_flow_fund_lag3 corr_flow_fund_lag6 corr_flow_rate_lag3\n",
"cluster_k2 \n",
"0 11.204 4.335 0.763 1436.0 11.471 28.0 46.273 0.606 0.114 1.000 0.000 0.0 0.047 0.046 -0.040\n",
"1 11.126 1.506 0.043 4.0 1.380 2.5 40.357 0.292 0.580 0.303 0.697 17.5 0.006 -0.004 -0.008\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1600x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"=== Médianes K=5 (Louis) ===\n",
" log_aum_qty_mean gross_flow_to_aum flow_freq n_tx_total avg_n_isin_held n_isin_total avg_holding_months_per_isin exit_rate_per_isin flow_direction_balance aum_drawdown_last aum_final_to_peak months_since_last_tx corr_flow_fund_lag3 corr_flow_fund_lag6 corr_flow_rate_lag3\n",
"cluster_k5 \n",
"0 10.551 3.243 0.351 88.0 3.317 13.0 33.000 0.419 0.263 0.169 0.831 1.0 0.028 0.016 -0.039\n",
"1 11.579 1.013 0.043 4.0 1.460 2.0 42.429 0.333 0.783 0.180 0.820 30.0 0.013 0.020 -0.012\n",
"2 12.619 4.668 0.992 7761.5 32.634 63.0 62.937 0.621 0.017 1.000 0.000 0.0 0.160 0.130 -0.144\n",
"3 10.975 4.083 0.763 1386.0 9.485 24.0 45.412 0.643 0.116 1.000 0.000 0.0 0.020 0.025 -0.014\n",
"4 10.750 4.102 0.079 8.0 1.735 7.5 33.394 0.360 0.250 0.378 0.622 7.0 -0.000 -0.002 0.008\n",
"seg_2D\n",
"Highly active 137\n",
"Dormant 136\n",
"Small rebalancers 77\n",
"Occasional large movers 77\n",
"Name: count, dtype: int64\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 800x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"=== Taux de churn globaux ===\n",
"churn_hard 0.684\n",
"churn_soft 0.775\n",
"churn_warning 0.321\n",
"dtype: float64\n",
"\n",
"=== Churn par cluster K=2 (Louis) ===\n",
" n_clients churn_hard churn_soft churn_warning\n",
"cluster_k2 \n",
"0 389 0.740 0.823 0.342\n",
"1 38 0.105 0.289 0.105\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAGGCAYAAADmRxfNAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAATDpJREFUeJzt3XtcFGX///H37goCHhBBycyzuZ5QUdPktszDnYWpeUwTS9NSUyuz20OZiaVYage1bs+ERHnILP1q1K1lUaF1m94Qt1mJec4DaGaA4O7+/vDH3iGgwACD+no+Hj5yZ+e65jM4bPPeua4Zi8vlcgkAAAAADLCaXQAAAACAax/BAgAAAIBhBAsAAAAAhhEsAAAAABhGsAAAAABgGMECAAAAgGEECwAAAACGESwAAAAAGEawAAAAAGAYwQLANclut2vmzJlml1EgU6ZMUXBwsNllSJKGDh2qoUOHml0GitGMGTM0fPhws8vQwoULZbfbC9Xml19+UdOmTfXTTz+VUFUAShPBAkCZcujQIU2fPl1du3ZVUFCQWrdurUGDBikqKkoZGRlml4erWLx4sbZu3Wp2GYYdOXJEdrtdK1asyLHc5XJp+vTpstvtWrhwoaFtJCQkaObMmerRo4datWqlu+66S08++aQOHDhQ4D4OHz6s999/X6NGjbpq7WVRw4YN1alTJy1YsMDsUgAUA4IFgDJj+/bt6tmzpz7++GN17txZzz//vCZOnKibb75Zc+fO1axZs8wuEVexZMmS6yJY5MXlcmnGjBlas2aNHn/8cY0fP95Qf8uXL9enn36qDh066LnnntPAgQP173//W3379i3wN/irVq1SzZo1dfvttxuqpTiMGTNGCQkJhW43aNAg/etf/9KhQ4dKoCoApamc2QUAgHTpm9cJEybo5ptvVlRUlKpXr+5+b8iQITp48KC2b99eqjU5nU5lZWWpfPnypbpd5HThwgV5eHjIajX3u7AXX3xRq1ev1ujRo/Xkk08a7m/YsGGaN2+ePD093ctCQ0PVs2dPLV26VPPmzbti+6ysLG3atEmDBg0yXEtxKFeunMqVK/xpRUhIiHx9fbVhw4Zi+bkCMA9XLACUCcuXL1daWppmzZqVI1Rkq1Onjh5++OFcy7du3ar77rtPzZs3V48ePfTll1/meH/KlCnq0qVLrnZ5jQfPnrexceNG9ejRQ0FBQYqLi9MHH3wgu92uXbt2KSIiQrfffrtatWqlsWPHKjU1tcD7ePjwYY0YMUKtWrVSx44dtWjRIrlcLkmXvg3v0qWLxowZk6vdhQsX1KZNG02fPv2q2/joo4/Uv39/tWzZUrfddpuGDBmir776Kt/1s/ftyJEjOZbv3LlTdrtdO3fudC/79ddfNX78eP3tb39TUFCQ7rzzTk2YMEF//PGHpEs/v7S0NG3YsEF2u112u11Tpkxxtz9x4oSmTp2qkJAQ97/X+++/n+d2N2/erNdee0133HGHWrZsqfPnz19130vSSy+9pJiYGI0aNUoTJkwolj5bt26dI1RIUt26dXXrrbcqOTn5qu137dqlM2fOKCQkpEjbT0lJ0bPPPquQkBAFBQWpV69e2rBhQ4518joOpP8Nt/rggw/cy/L6nfr66681ePBgtW3bVsHBwerevbteffXVHOt4eHioXbt22rZtW5H2A0DZwRULAGXC559/rlq1aql169YFbrNr1y59+umnevDBB1WhQgVFR0friSee0Oeffy4/P78i1bFjxw59/PHHGjJkiPz8/FSzZk2dO3dO0qWTy8qVK2vcuHE6evSooqKiNHPmTL3++utX7dfhcGjkyJFq2bKl/vGPfyguLk4LFy6Uw+HQk08+KYvFop49e2rFihU6e/asqlSp4m772Wef6fz58+rVq9cVt7Fo0SItXLhQwcHBeuKJJ+Th4aH//Oc/2rFjhzp27Fikn0e2zMxMjRgxQpmZmQoLC1NAQIBOnDih7du369y5c6pUqZJeeeUVTZs2TS1atNDAgQMlSbVr15YknT59WgMHDpTFYtGQIUNUtWpVffnll3ruued0/vx5DRs2LMf23nrrLXl4eLi36eHhYah+I2bPnq3o6Gg9+uijevrpp3O973Q6dfbs2QL1ValSpSvui8vl0unTp3Xrrbdeta/du3fLYrGoadOmBdr2X2VkZGjo0KE6dOiQhgwZoltuuUWxsbGaMmWKzp07l2eIL6yff/5Zo0aNkt1u1xNPPCFPT08dPHhQ33//fa51mzVrpm3btun8+fOqWLGi4W0DMAfBAoDpzp8/rxMnTqhr166Fard//35t2bLFffLavn179e7dW5s3b1ZYWFiRajlw4IA2bdqkhg0bupft3btXklSlShWtXLlSFotF0qUTyujoaP3xxx+qVKnSFfu9cOGC7rjjDk2bNk2S9OCDD2r06NFatmyZhg4dqqpVq+r+++/X4sWL9fHHH2vw4MHuths3blTNmjXVpk2bfPs/ePCg3nzzTf3973/XggULcgwbyr4qYsT+/ft15MgRvfHGG7rnnnvcy8eNG+f+e+/evTVjxgzVqlVLvXv3ztH+tddek8Ph0KZNm9yhb/DgwXr66ae1aNEiDRo0SF5eXu71L1y4oPXr1+dYZoaYmBgdPXpUI0aM0DPPPJPnOseOHSvwsbtq1Sq1b98+3/c3btyoEydO6IknnrhqX8nJyfL19S3SifiaNWu0f/9+zZ071x1YBw0apKFDh+r1119Xv379DJ/gf/3118rKytKyZctUtWrVK65bq1YtOZ1OJScnq0WLFoa2C8A8BAsApsse5lKhQoVCtQsJCXGHCklq3LixKlasqMOHDxe5lttuuy1HqPir7G/cs7Vt21Zvv/22jh49qsaNG1+17yFDhrj/nv3N/fbt2xUfH68ePXqoXr16atmypTZt2uQOFmfPnlVcXJxGjBiRY9uX27p1q5xOp8aOHZtrLsKV2hVU9knmV199pU6dOsnb27vAbV0ulz799FPde++9crlcOYaPdezYUZs3b1ZSUlKO4HT//febHiqkS1daJKlevXr5rlOtWjVFRkYWqL8rHSf79+/XzJkzFRwcrD59+ly1r7Nnz8rX17dA273cl19+qWrVqum+++5zL/Pw8NDQoUP19NNP67vvvlPnzp2L1He2ypUrS5K2bdumfv36XXGOTPa6Z86cMbRNAOYiWAAwXfZJ659//lmodjVq1Mi1zNfX1z10qShuueWWfN+7+eabc7zOPhkqyPasVqtq1aqVY1n2yerRo0fdy3r37q0XX3xRR48eVc2aNRUbG6usrKxcVwAud+jQIVmtVjVo0OCqtRRFrVq1NHz4cEVGRmrTpk1q27atunTpol69el31ak1qaqrOnTunNWvWaM2aNfmu81dX+ne4vJ3D4SjYTlymatWqstlsV1zn0Ucf1RdffKHp06erUqVKOa7WZCtfvnyR5zlkO3XqlEaNGqVKlSrpjTfeuGpd2Yp6Nero0aOqU6dOrpP97OPn2LFjRer3r0JDQ7Vu3TpNmzZN8+fPV4cOHfT3v/9d99xzT67tFsdVNQDmI1gAMF3FihVVvXp1/fzzz4Vql9/J119PUvL7tj6/k9ErfUue3zeuxXlS1KNHD0VERGjTpk0aPXq0Nm7cqObNm6t+/frFto2/yu/n43Q6cy2bMmWK+vTpo23btunrr7/WSy+9pCVLlmjt2rW66aab8t1Gdl+9evXK95v4yyf9FvRqRf/+/XMEs8LYtm3bVQOMj4+Pli1bprCwMD3zzDOqWLFirvkqDoejwJP4fX19c03Y/uOPP/Too4/qjz/+UExMjAIDAwvUV5UqVQyF6IIozPFxOS8vL8XExGjnzp3avn274uLitGXLFq1Zs0YrV67M8fubvR9FnRsFoGwgWAAoEzp37qw1a9Zo9+7dxfqU6sqVK+d58lUc38gWhtPp1OHDh3MMqcl+EFrNmjXdy6pUqaK77rpLmzZtUs+ePfX999/r2WefvWr/tWvXltPp1P79+9WkSZMC15V91SX7zk7Z8jtZz77b0+OPP67vv/9egwcP1nvvvXfFOyVVrVpVFSpUkNPpNPz
"text/plain": [
"<Figure size 800x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"=== Churn par cluster K=5 (Louis) ===\n",
" n_clients churn_hard churn_soft churn_warning\n",
"cluster_k5 \n",
"0 67 0.015 0.075 0.134\n",
"1 29 0.138 0.276 0.138\n",
"2 90 0.944 0.978 0.478\n",
"3 229 0.882 0.987 0.349\n",
"4 12 0.000 0.333 0.083\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAGGCAYAAADmRxfNAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAASVlJREFUeJzt3Xl4THf///HXZCSSULIiVbuKLSR2blvRaimKUmvv2ve2aIlbq9bGWi3aUtTW3Ihaym253drb0gp1K6V+tCVKLLXFUpVITOb3hyvz7cgiyZlksjwf19Xrypw553Pec/LRnNecz+cck9VqtQoAAAAADHBxdgEAAAAAcj+CBQAAAADDCBYAAAAADCNYAAAAADCMYAEAAADAMIIFAAAAAMMIFgAAAAAMI1gAAAAAMIxgAQAAAMAwggWAXCkwMFCTJ092dhnpEhoaqpCQEGeXIUnq3bu3evfu7ewy4EADBgzQO++84+wyFBoaqhYtWmRom7179yokJEQxMTFZVBWA7ESwAJCjnD9/XhMmTFDLli0VFBSkWrVqqVu3blqxYoXi4uKcXR4eY+HChdq1a5ezyzDswoULCgwM1NKlS+2WW61WTZgwQYGBgZo/f76hfRw8eFCBgYEp/nf06NF0tXH48GF99913GjBgQLJ2d+zYYai+7NC0aVOVLl1aixYtcnYpAByggLMLAIAku3fv1htvvCE3Nzd16NBBlSpVUkJCgg4fPqxZs2bp9OnTmjJlirPLRBoWLVqk1q1bq1WrVs4uxeGsVqsmTpyotWvXaujQoRoxYoRD2u3du7eCgoLslpUuXTpd2y5dulQNGzZUmTJlHFKLEVOmTJHVas3wdq+88opmzpypESNGqHDhwllQGYDsQrAAkCNER0dr5MiRevLJJ7VixQoVK1bM9l7Pnj117tw57d69O1trSkxMVEJCggoWLJit+4W9+/fvy9XVVS4uzr3IPmXKFK1Zs0aDBw/WG2+84bB269Spo+effz7D2924cUN79uzRxIkTHVaLEa6urpnarnXr1po6dap27Nihl19+2cFVAchODIUCkCMsWbJE9+7d07Rp0+xCRZIyZcro73//e7Llu3bt0osvvqjq1aurbdu22rt3r937qY37nj9/vgIDA+2WJc3b2Lx5s9q2baugoCDt27dPGzZsUGBgoA4fPqywsDA1aNBAwcHBGjZsWIbGhkdHR6tfv34KDg5W48aNtWDBAts3vFarVS1atNCQIUOSbXf//n3Vrl1bEyZMeOw+vvrqK7388suqWbOm6tatq549e+rbb79Ndf2kz3bhwgW75UnDaQ4ePGhb9ttvv2nEiBH629/+pqCgIDVt2lQjR47UH3/8Ienh8bt37542btxoG9ITGhpq2/7KlSsaN26cGjVqZPt9ffnllynud+vWrZo7d66aNGmimjVr6u7du4/97Flp6tSpCg8P16BBgzRy5EiHt3/37l09ePAgQ9vs3r1bDx48UKNGjTK1z+joaL3++uuqV6+eatasqa5duyYL7xnpHyn9W9u6das6deqkkJAQ1apVS+3atdOKFSvs1vH19VVgYKC+/vrrTH0OADkHVywA5Aj//e9/VapUKdWqVSvd2xw+fFg7d+5Ujx49VKhQIa1atUqvv/66/vvf/8rb2ztTdRw4cEDbt29Xz5495e3trZIlS+rOnTuSHp5cFilSRMOHD9fFixe1YsUKTZ48WR9++OFj27VYLOrfv79q1qypt99+W/v27dP8+fNlsVj0xhtvyGQyqV27dlq6dKlu3bolLy8v27bffPON7t69q/bt26e5jwULFmj+/PkKCQnR66+/LldXV/344486cOCAGjdunKnjkSQ+Pl79+vVTfHy8evXqJT8/P125ckW7d+/WnTt39MQTT2jmzJl65513VKNGDXXt2lXS/w3puX79urp27SqTyaSePXvKx8dHe/fu1fjx43X37l299tprdvv75JNP5OrqattnZr8Nd4T3339fq1at0oABAzRq1Khk7ycmJurWrVvpauuJJ55I9lnGjRune/fuyWw2q3bt2hozZkyyoVEpOXLkiLy8vFSyZMl07fuvrl+/rm7duik2Nla9e/eWt7e3Nm7cqCFDhmjevHl69tlnM9zmo7777juNGjVKDRs21FtvvSVJioqK0g8//JDsS4Jq1arlibk5QH5HsADgdHfv3tWVK1fUsmXLDG135swZbdu2zXbyWr9+fXXo0EFbt25Vr169MlXL2bNntWXLFlWsWNG27OTJk5IkLy8vff755zKZTJIenlCuWrVKf/zxh5544ok0271//76aNGliu3tPjx49NHjwYC1evFi9e/eWj4+PXnrpJS1cuFDbt29X9+7dbdtu3rxZJUuWVO3atVNt/9y5c/r444/17LPPat68eXbDhjIz7v1RZ86c0YULF/TRRx/ZDdsZPny47ecOHTpo4sSJKlWqlDp06GC3/dy5c2WxWLRlyxZb6OvevbtGjRqlBQsWqFu3bnJ3d7etf//+fa1fv95umTOEh4fr4sWL6tevn+3k+FGXLl1Kd99duXKl6tevL+nh0KHWrVuradOm8vb21pkzZ7R06VL17NlTa9asUdWqVdNsKyoqKlOhQpI+++wzXb9+XeHh4apTp44kqUuXLmrfvr3CwsLUsmVLw0PPdu/ercKFC2vp0qUym81prluqVCndvHlTN27ckK+vr6H9AnAeggUAp0sa5lKoUKEMbdeoUSO7Sa6VK1dW4cKFFR0dnela6tataxcq/irpG/ckderU0fLly3Xx4kVVrlz5sW337NnT9nPSN/e7d+9WZGSk2rZtq3LlyqlmzZrasmWLLVjcunVL+/btU79+/ez2/ahdu3YpMTFRw4YNS3ZCmNZ26ZU0qfbbb79Vs2bN5OHhke5trVardu7cqRdeeEFWq9Vu+Fjjxo21detWnThxwi44vfTSS04PFdLDb/YlqVy5cqmu4+/vr2XLlqWrvb/2k1q1atldoWvZsqVat26t9u3ba86cOcnuSPWoW7duqXjx4una76P27NmjGjVq2EKF9PDf3yuvvKI5c+bo9OnTqlSpUqbaTlKkSBHFxsbqu+++U9OmTR+7riTdvHmTYAHkYgQLAE6XdNL6559/Zmi7gICAZMuKFi1qG7qUGU899VSq7z355JN2r5NOhtKzPxcXF5UqVcpuWdLJ6sWLF23LOnTooClTpujixYsqWbKkduzYoYSEhGRXAB51/vx5ubi4qEKFCo+tJTNKlSqlPn36aNmyZdqyZYvq1KmjFi1aqH379o+9WhMTE6M7d+5o7dq1Wrt2barr/FVav4dHt7NYLOn7EI/w8fF57DfpAwYM0J49ezRhwgQ98cQTKU6yLliwYKbnOTyqTJkyatmypXbu3CmLxfLY+jJ7NerSpUuqWbNmsuXly5e3vW80WPTo0UPbt2/XgAEDVLx4cf3tb3/TCy+8kGLISPocjgjBAJyHYAHA6QoXLqxixYrp119/zdB2qZ10/fVkK7UTldRORtP6ljy1oSGOGGqUpG3btgoLC9OWLVs0ePBgbd68WdWrV7ed8DlaascnMTEx2bLQ0FB17NhRX3/9tb777jtNnTpVixYtUkREhEqUKJHqPpLaat++vTp27JjiOo9OpE/v1YqXX37ZLphlxNdff/3YAOPp6anFixerV69eeuutt1S4cOFk81UsFku6J/EXLVpUbm5uaa5TokQJJSQkKDY2Ns3br3p5eRkK0emRkf7xKF9fX23atEnffvut9u7dq71792rDhg166aWXNGPGDLt1kz5HZudGAcgZCBYAcoRnnnlGa9eu1ZEjRxz6lOoiRYqkePJ16dIlh+0jPRITExUdHW03pObs2bOSZDdO3svLS82bN9eWLVvUrl07/fDDD/rHP/7x2PZLly6txMREnTlzRlWqVEl3XUlXXZLu7JQktZP1pLs9DR06VD/88IO6d++u1atXp3mnJB8fHxUqVEiJiYkO+2Y/yaxZs3T//v1Mbevv75+u9by9vfX555+re/fuGjFihD7//HO7Pnr58uVMzbFIzYULF1SwYEF5enqmuV758uW1c+f
"text/plain": [
"<Figure size 800x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAuEAAAKyCAYAAAB7WgDLAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsvXfYbkdZLn7PzOpv+9r+dt/pe1OSnIRACiogAooHKQFEQFQM0gz15Bia/lAUgggeQqSJ9OZRQOTIQRTlCBpCEYgCBkjZvX3l7e+qM78/ZuaZ9SWB7ISQouu5rn1d736/9a41fc08z/3cN1NKKTTWWGONNdZYY4011lhjd5nxu7sAjTXWWGONNdZYY4019l/Nmk14Y4011lhjjTXWWGON3cXWbMIba6yxxhprrLHGGmvsLrZmE95YY4011lhjjTXWWGN3sTWb8MYaa6yxxhprrLHGGruLrdmEN9ZYY4011lhjjTXW2F1szSa8scYaa6yxxhprrLHG7mJrNuGNNdZYY4011lhjjTV2F1uzCW+sscYaa6yxxhprrLG72JpNeGON3QPsLW95C/bs2XN3F6OxH2Ive9nL8PCHP/zuLsZ/Gnv1q1+NZz7zmXd3Me7Q3Pv+97+P+93vfvjud7/7YypVY4019l/Bmk14Y43dyfbxj38ce/bsoX9nnXUWfvInfxKXXHIJ3v/+92M8Ht8pzzl69Cje8pa34Dvf+c6dcr//KjabzfCWt7wF11xzzd1dlB+L7dmzB7/3e793i+/f/va3Y8+ePXj5y18OKeUdvv+BAwc2jO/6v7/5m785oXvs378ff/mXf4nnPOc5t7jvn/3Zn93hst1Vdvrpp+OhD30orrzyyru7KI011ti92Ly7uwCNNfaf1V74whdix44dKMsSKysr+PKXv4zXvva1eO9734u3vvWtuM997kPXPu95z8Ozn/3s23X/Y8eO4aqrrsL27dtx3/ve984u/n9am81muOqqq3DppZfiggsuOOHfveY1r4FS6sdYsh+fvfOd78Qf//Ef4wlPeAL+4A/+AJz/6P6XxzzmMXjIQx6y4btzzjnnhH77/ve/H9u3b8eFF174I5fjR7U7MvcA4Jd+6Zfw7Gc/G/v27cOuXbt+DCVrrLHG/rNbswlvrLEfkz3kIQ/BWWedRf9/znOeg6uvvhrPfe5z8fznPx+f/vSnEUURAMDzPHheMx3viTadTpEkCXzfv7uLcofsXe96F974xjfi8Y9/PF772tfeKRtwALjf/e6Hxz3ucbf7d0VR4FOf+hR+6Zd+6U4px49qd3TuPfjBD0av18MnPvEJvOhFL/oxlKyxxhr7z24NHKWxxu5Cu+iii/D85z8fBw8exF//9V/T97eGS/3nf/5nPPWpT8UDH/hAnHvuufjZn/1ZvOlNbwIAXHPNNXjSk54EAHj5y19OcICPf/zjAICvfvWreOELX4iHPexhOPPMM/HQhz4Ur33ta5Gm6YZnvOxlL8O5556Lo0eP4vnPfz7OPfdcXHjhhXj961+Pqqo2XCulxPve9z78wi/8As466yxceOGFuOSSS/Bv//ZvG6775Cc/iYsvvhhnn302zj//fLzkJS/B4cOHb7NtbBvceOONuOyyy3DeeefhwgsvxP/6X/8LSikcPnwYz3ve8/CABzwAP/ETP4F3v/vdG36f5zne/OY34+KLL8Z5552Hc845B0972tPwpS99ia45cOAALrroIgDAVVddRe32lre8ZUN77Nu3D7/xG7+Bc889F5dddhn9rY4Jv/LKK3Gf+9wHV1999YZy/PZv/zbOPPNM/Md//Mdt1vnHbe95z3vwhje8AY997GPxute97k7bgFubTqfI8/x2/eZrX/sa1tfX8eAHP/gOPXN1dRWveMUr8OAHPxhnnXUWHvvYx+ITn/jEhmuuueYa7Nmz5xaQIwt5sfMEuP1zz5rv+zj//PPxuc997g7Vo7HGGmuscb011thdbI973OPwpje9CV/84hfxi7/4i7d6zfe+9z085znPwZ49e/DCF74QQRBg7969+Nd//VcAwGmnnYYXvvCFuPLKK/GUpzwF5513HgDgAQ94AADgM5/5DNI0xVOf+lTMzc3h2muvxQc/+EEcOXLkFjjWqqpwySWX4Oyzz8Zv/dZv4eqrr8a73/1u7Ny5E0972tPoule+8pX4+Mc/joc85CF40pOehKqq8NWvfhXf/OY3yeP/tre9DW9+85vx6Ec/Gk960pOwtraGD37wg3j605+Ov/qrv0K3273N9nnJS16C0047Df/jf/wP/L//9//wtre9DXNzc/joRz+KCy+8EJdddhk+9alP4fWvfz3OOussPOhBDwIAjMdj/MVf/AUe85jH4MlPfjImkwn+8i//Es961rPwF3/xF7jvfe+LhYUFvPrVr8arX/1qPPKRj8QjH/lIANiwCSvLEpdccgnOO+88XH755RStuLk973nPwz/+4z/ila98Jf76r/8a7XYbX/jCF/C///f/xote9KINcKO7w973vvfhiiuuwGMe8xhcccUVt7oBX1tbO6F7tdttBEGw4burrroKf/iHfwjGGO5///vjJS95CX7yJ3/yNu/19a9/HYwx3O9+9zuxitQsTVM84xnPwL59+/D0pz8dO3bswGc+8xm87GUvw3A4xK/+6q/e7nve3G5r7tXt/ve/Pz73uc9hPB6j3W7/yM9urLHG/ouZaqyxxu5U+9jHPqZ2796trr322h94zXnnnace//jH0/+vvPJKtXv3bvr/e97zHrV79261urr6A+9x7bXXqt27d6uPfexjt/jbbDa7xXfveMc71J49e9TBgwfpu8svv1zt3r1bXXXVVRuuffzjH6+e8IQn0P+vvvpqtXv3bvWa17zmFveVUiqllDpw4IC6733vq972trdt+Pt1112n7ne/+93i+5ubbYPf/u3fpu/KslQPechD1J49e9Q73vEO+n4wGKizzz5bXX755RuuzbJswz0Hg4F68IMfrF7+8pfTd6urq2r37t3qyiuvvEUZbHv80R/90a3+7ad/+qdvUbf73//+6pWvfKUaDAbqp37qp9TFF1+siqL4oXX9cdru3bvVT//0T6vdu3erl770paosyx967Yn8q4+xgwcPql//9V9XH/7wh9XnPvc59d73vlc97GEPU/e5z33UP/7jP95m+S677DJ1/vnn3+L7/fv3q927d6t3vetdP/C3733ve9Xu3bvVJz/5Sfouz3P1lKc8RZ1zzjlqNBoppZT60pe+pHbv3q2+9KUv3eoz6vW5I3PP2qc+9Sm1e/du9c1vfvM2r22sscYau7k1nvDGGrsbLEkSTCaTH/h36zH+3Oc+hyc+8Ym3G0ZQ995Op1OkaYpzzz0XSil8+9vfxrZt2zZc/9SnPnXD/88777wNcJnPfvazYIzh0ksvvcWzGGMAgL/7u7+DlBKPfvSjN3hYl5aWcNJJJ+Gaa67Bc5/73Nssu4XZAIAQAmeeeSaOHDmy4ftut4tTTjkF+/fv33CtEAKAhs4Mh0NIKXHmmWfi29/+9m0+t243b48fZLt378YLX/hCvPGNb8R1112H9fV1vPvd777b8f0rKysAgB07dlCb3Jq95z3vOaH7nX766fR527Ztt2AwedzjHof//t//O6644go87GEP+6H36vf76PV6J/Tcm9s//dM/YdOmTXjMYx5D3/m+j2c84xl46Utfiq985Sv46Z/+6Tt0b2u3Z+7Za9fX13+kZzbWWGP/Na3ZhDfW2N1g0+kUi4uLP/DvP//zP4+/+Iu/wKte9Sq88Y1vxEUXXYRHPvKR+Lmf+7kT2pAfOnQIV155Jf7hH/4Bg8Fgw99uTpEYhiEWFhY2fNfr9Tb8bt++fVheXsbc3NwPfOZNN90EpRQe9ahH3erfT3RjevMDQqfTudUydjod9Pv9Dd994hOfwLvf/W7ceOONKIqCvt+xY8cJPduWc8uWLSd8/SWXXIK/+Zu/wbXXXouXvvSlGzasP8j6/f6G8t0e6/V6t4CG3Nwe//jH49ixY3j729+O+fl5/Nqv/dqtXndHcdk3t7m5OVx88cV45zvfiSNHjtx
"text/plain": [
"<Figure size 800x700 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# ============================================================\n",
"# PARTIE 2 — CLUSTERING 400 GRANDS COMPTES\n",
"# ============================================================\n",
"print(\"\\n\" + \"=\"*70)\n",
"print(\"PARTIE 2 — CLUSTERING 400 GRANDS COMPTES ()\")\n",
"print(\"=\"*70)\n",
"\n",
"# Sélection des 400+ grands comptes\n",
"ref_date = pd.Timestamp(\"2025-10-01\") # premier jour du mois dans le panel\n",
"df_ref = df_aum[df_aum[\"month\"] == ref_date]\n",
"\n",
"aum_account = (\n",
" df_ref.groupby(ID_COL)[AUM_VAL_COL].sum()\n",
" .reset_index().sort_values(AUM_VAL_COL, ascending=False)\n",
")\n",
"aum_account = aum_account[aum_account[AUM_VAL_COL] > 5_000_000]\n",
"selected_accounts = aum_account[ID_COL]\n",
"print(f\"Comptes sélectionnés (AUM > 5M€) : {len(selected_accounts)}\")\n",
"\n",
"# Filtrer df_month sur les grands comptes\n",
"df_month_400_accounts = df_month[df_month[ID_COL].isin(selected_accounts)].copy()\n",
"\n",
"# Engineered ratios\n",
"dfc_400_accounts = df_client_base[df_client_base[ID_COL].isin(selected_accounts)].copy()\n",
"\n",
"dfc_400_accounts[\"log_aum_qty_mean\"] = np.log1p(dfc_400_accounts[\"aum_qty_mean\"].clip(lower=0))\n",
"dfc_400_accounts[\"log_gross_flow_qty_mean\"] = np.log1p(dfc_400_accounts[\"gross_flow_qty_mean\"].clip(lower=0))\n",
"dfc_400_accounts[\"gross_flow_to_aum\"] = dfc_400_accounts[\"gross_flow_qty_sum\"] / (dfc_400_accounts[\"aum_qty_mean\"].abs() + EPS)\n",
"dfc_400_accounts[\"flow_direction_balance\"] = np.where(\n",
" dfc_400_accounts[\"gross_flow_qty_sum\"] > 0,\n",
" dfc_400_accounts[\"net_flow_qty_sum\"] / dfc_400_accounts[\"gross_flow_qty_sum\"], np.nan\n",
")\n",
"dfc_400_accounts[\"redemption_bias\"] = dfc_400_accounts[\"red_qty_sum\"] - dfc_400_accounts[\"sub_qty_sum\"]\n",
"dfc_400_accounts[\"exit_rate_per_isin\"] = np.where(\n",
" dfc_400_accounts[\"n_isin_total\"] > 0,\n",
" dfc_400_accounts[\"full_exit_count\"] / dfc_400_accounts[\"n_isin_total\"], np.nan\n",
")\n",
"dfc_400_accounts[\"aum_drawdown_last\"] = dfc_400_accounts[\"aum_drawdown_last\"].clip(0, 1)\n",
"dfc_400_accounts[\"aum_final_to_peak\"] = np.where(\n",
" dfc_400_accounts[\"aum_qty_max\"] > 0,\n",
" (dfc_400_accounts[\"aum_qty_last\"] / dfc_400_accounts[\"aum_qty_max\"]).clip(0, 1), np.nan\n",
")\n",
"dfc_400_accounts[\"activity_intensity\"] = dfc_400_accounts[\"n_tx_total\"] / (dfc_400_accounts[\"n_months\"] + EPS)\n",
"dfc_400_accounts[\"flow_to_aum_vol\"] = dfc_400_accounts[\"rel_flow_to_aum_vol_avg\"]\n",
"\n",
"# Corrélations flux/performance (lag 3 et 6 mois) — exploitables sur les grands comptes\n",
"def corr_lag(x, y, lag):\n",
" x = np.asarray(x, dtype=float)\n",
" y = np.asarray(y, dtype=float)\n",
" mask = np.isfinite(x) & np.isfinite(y)\n",
" x, y = x[mask], y[mask]\n",
" if len(x) <= lag + 3:\n",
" return np.nan\n",
" return pd.Series(x[lag:]).corr(pd.Series(y[:-lag]))\n",
"\n",
"rows_corr = []\n",
"for acc, g in df_month_400_accounts.groupby(ID_COL):\n",
" g = g.sort_values(\"month\")\n",
" flow = g[\"flow_to_aum_m\"].values\n",
" ret = g[\"ret_fund_m\"].values\n",
" rate = g[\"delta_rate_m\"].values\n",
" rows_corr.append({\n",
" ID_COL: acc,\n",
" \"corr_flow_fund_lag3\": corr_lag(flow, ret, 3),\n",
" \"corr_flow_fund_lag6\": corr_lag(flow, ret, 6),\n",
" \"corr_flow_rate_lag3\": corr_lag(flow, rate, 3),\n",
" })\n",
"df_corr_400_accounts = pd.DataFrame(rows_corr)\n",
"dfc_400_accounts = dfc_400_accounts.merge(df_corr_400_accounts, on=ID_COL, how=\"left\")\n",
"\n",
"# months_since_last_tx\n",
"dfc_400_accounts = add_months_since_last_tx(dfc_400_accounts, df_month_400_accounts, ID_COL)\n",
"\n",
"# Filtres qualité\n",
"dfc_400_accounts = dfc_400_accounts[(dfc_400_accounts[\"n_months\"] >= 6) & (dfc_400_accounts[\"aum_qty_mean\"] > 0)].copy()\n",
"\n",
"# Géographie\n",
"top_countries_l = dfc_400_accounts[\"country\"].fillna(\"Unknown\").value_counts().head(10).index\n",
"top_regions_l = dfc_400_accounts[\"region\"].fillna(\"Unknown\").value_counts().head(10).index\n",
"dfc_400_accounts[\"country_grp\"] = np.where(\n",
" dfc_400_accounts[\"country\"].isin(top_countries_l), dfc_400_accounts[\"country\"], \"Other\"\n",
")\n",
"dfc_400_accounts[\"region_grp\"] = np.where(\n",
" dfc_400_accounts[\"region\"].isin(top_regions_l), dfc_400_accounts[\"region\"], \"Other\"\n",
")\n",
"\n",
"print(f\"After filters: {len(dfc_400_accounts)} accounts\")\n",
"\n",
"# Feature selection — Top 400 accounts enrichi (15 variables)\n",
"base_features_400_accounts = [\n",
" \"log_aum_qty_mean\",\n",
" \"flow_freq\",\n",
" \"gross_flow_to_aum\",\n",
" \"flow_to_aum_vol\",\n",
" \"activity_intensity\",\n",
" \"n_tx_total\",\n",
" \"avg_n_isin_held\",\n",
" \"n_isin_total\",\n",
" \"avg_holding_months_per_isin\",\n",
" \"exit_rate_per_isin\",\n",
" \"flow_direction_balance\",\n",
" \"aum_drawdown_last\",\n",
" \"months_since_last_tx\",\n",
" \"corr_flow_fund_lag3\",\n",
" \"corr_flow_fund_lag6\",\n",
" \"corr_flow_rate_lag3\",\n",
"]\n",
"all_features_400_accounts = [c for c in base_features_400_accounts if c in dfc_400_accounts.columns]\n",
"\n",
"# Preprocessing — RobustScaler + winsorisation MAD \n",
"dfc_400_accounts_clean = dfc_400_accounts.copy()\n",
"\n",
"for col in [\"flow_direction_balance\", \"months_since_last_tx\",\n",
" \"corr_flow_fund_lag3\", \"corr_flow_fund_lag6\", \"corr_flow_rate_lag3\"]:\n",
" if col in dfc_400_accounts_clean.columns:\n",
" dfc_400_accounts_clean[col] = dfc_400_accounts_clean[col].fillna(0)\n",
"\n",
"for col in [\"n_isin_total\", \"avg_n_isin_held\", \"exit_rate_per_isin\",\n",
" \"avg_holding_months_per_isin\", \"months_since_last_tx\",\n",
" \"activity_intensity\", \"flow_to_aum_vol\",\n",
" \"aum_drawdown_last\", \"aum_final_to_peak\"]:\n",
" if col in dfc_400_accounts_clean.columns:\n",
" dfc_400_accounts_clean[col] = winsorize_mad(dfc_400_accounts_clean[col], n_sigma=3)\n",
"\n",
"for col in [\"gross_flow_to_aum\"]:\n",
" if col in dfc_400_accounts_clean.columns:\n",
" vals = dfc_400_accounts_clean[col].to_numpy(dtype=float)\n",
" vals = np.clip(vals, 0, np.nanpercentile(vals, 90))\n",
" dfc_400_accounts_clean[col] = np.log1p(vals)\n",
"\n",
"for col in [\"flow_freq\"]:\n",
" if col in dfc_400_accounts_clean.columns:\n",
" vals = dfc_400_accounts_clean[col].to_numpy(dtype=float)\n",
" dfc_400_accounts_clean[col] = np.log1p(np.clip(vals, 0, None))\n",
"\n",
"for col in [\"log_aum_qty_mean\", \"log_gross_flow_qty_mean\"]:\n",
" if col in dfc_400_accounts_clean.columns:\n",
" dfc_400_accounts_clean[col] = winsorize_mad(dfc_400_accounts_clean[col], n_sigma=3)\n",
"\n",
"for col in [\"n_tx_total\"]:\n",
" if col in dfc_400_accounts_clean.columns:\n",
" vals = dfc_400_accounts_clean[col].to_numpy(dtype=float)\n",
" dfc_400_accounts_clean[col] = np.log1p(np.clip(vals, 0, None))\n",
"\n",
"X_400_accounts = dfc_400_accounts_clean[all_features_400_accounts].copy()\n",
"X_400_accounts = X_400_accounts.loc[:, ~X_400_accounts.columns.duplicated()]\n",
"X_400_accounts = X_400_accounts.replace([np.inf, -np.inf], np.nan).fillna(X_400_accounts.median())\n",
"\n",
"scaler_400_accounts = RobustScaler()\n",
"X_400_accounts_scaled = scaler_400_accounts.fit_transform(X_400_accounts)\n",
"\n",
"# Diagnostic\n",
"X_df_l = pd.DataFrame(X_400_accounts_scaled, columns=X_400_accounts.columns)\n",
"extreme_l = (X_df_l.abs() > 5).any(axis=1).sum()\n",
"print(f\"Accounts: {X_400_accounts.shape[0]} | Features: {X_400_accounts.shape[1]}\")\n",
"print(f\"Points > 5 std after scaling: {extreme_l} ({extreme_l/len(X_df_l):.1%})\")\n",
"\n",
"# K-selection\n",
"rows_l = []\n",
"for k in range(2, 11):\n",
" km = KMeans(n_clusters=k, n_init=30, random_state=RANDOM_STATE)\n",
" labels = km.fit_predict(X_400_accounts_scaled)\n",
" rows_l.append({\n",
" \"k\": k, \"inertia\": km.inertia_,\n",
" \"silhouette\": silhouette_score(X_400_accounts_scaled, labels),\n",
" \"davies_bouldin\": davies_bouldin_score(X_400_accounts_scaled, labels),\n",
" })\n",
"df_kdiag_400_accounts = pd.DataFrame(rows_l)\n",
"print(df_kdiag_400_accounts.to_string(index=False))\n",
"\n",
"fig, axes = plt.subplots(1, 3, figsize=(15, 4))\n",
"for ax, col, title in zip(axes,\n",
" [\"inertia\", \"silhouette\", \"davies_bouldin\"],\n",
" [\"Elbow / Inertia\", \"Silhouette (higher=better)\", \"Davies-Bouldin (lower=better)\"]):\n",
" ax.plot(df_kdiag_400_accounts[\"k\"], df_kdiag_400_accounts[col], marker=\"o\")\n",
" ax.set_title(title); ax.set_xlabel(\"K\")\n",
"plt.suptitle(\"K-selection — 400 grands comptes (400_accounts)\")\n",
"plt.tight_layout(); plt.show()\n",
"\n",
"# Clustering K=2, 4, 5 (comme 400_accounts)\n",
"RESULTS_400_accounts = {}\n",
"for k in [2, 4, 5]:\n",
" km = KMeans(n_clusters=k, n_init=50, random_state=RANDOM_STATE)\n",
" dfc_400_accounts[f\"cluster_k{k}\"] = km.fit_predict(X_400_accounts_scaled)\n",
" RESULTS_400_accounts[k] = {\n",
" \"model\": km,\n",
" \"silhouette\": silhouette_score(X_400_accounts_scaled, dfc_400_accounts[f\"cluster_k{k}\"]),\n",
" \"davies_bouldin\": davies_bouldin_score(X_400_accounts_scaled, dfc_400_accounts[f\"cluster_k{k}\"]),\n",
" }\n",
" print(f\"K={k} | sil={RESULTS_400_accounts[k]['silhouette']:.4f} \"\n",
" f\"| db={RESULTS_400_accounts[k]['davies_bouldin']:.4f}\")\n",
" counts = dfc_400_accounts[f\"cluster_k{k}\"].value_counts().sort_index()\n",
" props = counts / counts.sum() * 100\n",
" print(pd.DataFrame({\"n_comptes\": counts, \"pct\": props.round(1)}))\n",
" print()\n",
"\n",
"# Profile vars — top 400 accounts (avec les corrélations)\n",
"profile_vars_400_accounts = [\n",
" \"log_aum_qty_mean\",\n",
" \"gross_flow_to_aum\",\n",
" \"flow_freq\",\n",
" \"n_tx_total\",\n",
" \"avg_n_isin_held\",\n",
" \"n_isin_total\",\n",
" \"avg_holding_months_per_isin\",\n",
" \"exit_rate_per_isin\",\n",
" \"flow_direction_balance\",\n",
" \"aum_drawdown_last\",\n",
" \"aum_final_to_peak\",\n",
" \"months_since_last_tx\",\n",
" \"corr_flow_fund_lag3\",\n",
" \"corr_flow_fund_lag6\",\n",
" \"corr_flow_rate_lag3\",\n",
"]\n",
"profile_vars_400_accounts = [c for c in profile_vars_400_accounts if c in dfc_400_accounts.columns]\n",
"\n",
"for k in [2, 5]:\n",
" prof_l = plot_heatmap(\n",
" dfc_400_accounts, profile_vars_400_accounts, f\"cluster_k{k}\",\n",
" title=f\"Cluster signatures — 400 grands comptes K={k} (robust z-score)\",\n",
" figsize=(16, 4)\n",
" )\n",
" print(f\"\\n=== Médianes K={k} (400_accounts) ===\")\n",
" print(prof_l.round(3).to_string())\n",
"\n",
"# Segmentation 2D (comme 400_accounts)\n",
"thr_int = dfc_400_accounts[\"gross_flow_to_aum\"].median()\n",
"thr_freq = dfc_400_accounts[\"flow_freq\"].median()\n",
"\n",
"def quadrant(row):\n",
" low_int = row[\"gross_flow_to_aum\"] < thr_int\n",
" low_frq = row[\"flow_freq\"] < thr_freq\n",
" if low_int and low_frq: return \"Dormant\"\n",
" if low_int and not low_frq: return \"Small rebalancers\"\n",
" if not low_int and low_frq: return \"Occasional large movers\"\n",
" return \"Highly active\"\n",
"\n",
"dfc_400_accounts[\"seg_2D\"] = dfc_400_accounts.apply(quadrant, axis=1)\n",
"print(dfc_400_accounts[\"seg_2D\"].value_counts())\n",
"\n",
"plt.figure(figsize=(8, 5))\n",
"for name, g in dfc_400_accounts.groupby(\"seg_2D\"):\n",
" plt.scatter(g[\"flow_freq\"], g[\"gross_flow_to_aum\"], s=15, label=name)\n",
"plt.yscale(\"log\")\n",
"plt.axvline(thr_freq, linestyle=\"--\", color=\"gray\")\n",
"plt.axhline(thr_int, linestyle=\"--\", color=\"gray\")\n",
"plt.xlabel(\"Activity frequency\")\n",
"plt.ylabel(\"Gross flow / mean AUM [log scale]\")\n",
"plt.title(\"2D behavioral segmentation — 400 grands comptes\")\n",
"plt.legend(markerscale=2)\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"# Analyse churn (comme 400_accounts)\n",
"dfc_400_accounts[\"churn_hard\"] = (dfc_400_accounts[\"aum_final_to_peak\"] < 0.10).astype(int)\n",
"dfc_400_accounts[\"churn_soft\"] = (\n",
" (dfc_400_accounts[\"aum_final_to_peak\"] < 0.40) &\n",
" (dfc_400_accounts[\"aum_drawdown_last\"] > 0.40)\n",
").astype(int)\n",
"dfc_400_accounts[\"churn_warning\"] = (\n",
" (dfc_400_accounts[\"flow_direction_balance\"] < 0) &\n",
" (dfc_400_accounts[\"aum_drawdown_last\"] > 0.20)\n",
").astype(int)\n",
"\n",
"print(\"\\n=== Taux de churn globaux ===\")\n",
"print(dfc_400_accounts[[\"churn_hard\",\"churn_soft\",\"churn_warning\"]].mean().round(3))\n",
"\n",
"for k in [2, 5]:\n",
" churn_profile = (\n",
" dfc_400_accounts.groupby(f\"cluster_k{k}\")\n",
" .agg(\n",
" n_clients = (ID_COL, \"count\"),\n",
" churn_hard = (\"churn_hard\", \"mean\"),\n",
" churn_soft = (\"churn_soft\", \"mean\"),\n",
" churn_warning = (\"churn_warning\", \"mean\"),\n",
" )\n",
" )\n",
" print(f\"\\n=== Churn par cluster K={k} (400_accounts) ===\")\n",
" print(churn_profile.round(3).to_string())\n",
"\n",
" churn_profile[[\"churn_hard\",\"churn_soft\",\"churn_warning\"]].plot(\n",
" kind=\"bar\", figsize=(8, 4)\n",
" )\n",
" plt.title(f\"Churn by cluster — K={k} (400_accounts)\")\n",
" plt.ylabel(\"Rate\"); plt.xlabel(\"Cluster\")\n",
" plt.tight_layout(); plt.show()\n",
"\n",
"# Matrice de distance inter-cluster\n",
"def plot_distance_matrix(X_scaled, labels, max_points=400, title=\"Distance matrix\"):\n",
" n = X_scaled.shape[0]\n",
" idx = np.arange(n)\n",
" if n > max_points:\n",
" rng = np.random.default_rng(42)\n",
" idx = rng.choice(idx, size=max_points, replace=False)\n",
" X_sub = X_scaled[idx]\n",
" labels_sub = np.asarray(labels)[idx]\n",
" order = np.lexsort((np.arange(len(labels_sub)), labels_sub))\n",
" X_sub = X_sub[order]; labels_sub = labels_sub[order]\n",
" D = pairwise_distances(X_sub)\n",
" plt.figure(figsize=(8, 7))\n",
" sns.heatmap(D, cmap=\"viridis\")\n",
" unique_labels, counts = np.unique(labels_sub, return_counts=True)\n",
" for b in np.cumsum(counts)[:-1]:\n",
" plt.axhline(b, color=\"red\", linewidth=2)\n",
" plt.axvline(b, color=\"red\", linewidth=2)\n",
" plt.title(title); plt.tight_layout(); plt.show()\n",
"\n",
"plot_distance_matrix(\n",
" X_400_accounts_scaled,\n",
" dfc_400_accounts[\"cluster_k5\"].values,\n",
" title=\"Distance matrix — K=5 (400_accounts)\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "d5227c4b-734f-48ec-8673-2683615edfbc",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Comptes sélectionnés (AUM > 5M€) : 431\n"
]
}
],
"source": [
"ref_date = pd.Timestamp(\"2025-10-01\") # premier jour du mois dans le panel\n",
"df_ref = df_aum[df_aum[\"month\"] == ref_date]\n",
"\n",
"aum_account = (\n",
" df_ref.groupby(ID_COL)[AUM_VAL_COL].sum()\n",
" .reset_index().sort_values(AUM_VAL_COL, ascending=False)\n",
")\n",
"aum_account = aum_account[aum_account[AUM_VAL_COL] > 5_000_000]\n",
"selected_accounts = aum_account[ID_COL]\n",
"print(f\"Comptes sélectionnés (AUM > 5M€) : {len(selected_accounts)}\")"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "f11c6fe3-d609-4dab-aecc-91a8cae0ce93",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"seg_2D\n",
"Highly active (high int, high freq) 137\n",
"Dormant (low int, low freq) 136\n",
"Small rebalancers (low int, high freq) 77\n",
"Occasional large movers (high int, low freq) 77\n",
"Name: count, dtype: int64\n",
"thr_int: 4.0037 | thr_freq: 0.7231\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 900x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 900x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1400x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1600x400 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"=== Médianes K=5 (Louis) ===\n",
" log_aum_qty_mean gross_flow_to_aum flow_freq n_tx_total avg_n_isin_held n_isin_total avg_holding_months_per_isin exit_rate_per_isin flow_direction_balance aum_drawdown_last aum_final_to_peak months_since_last_tx corr_flow_fund_lag3 corr_flow_fund_lag6 corr_flow_rate_lag3\n",
"cluster_k5 \n",
"0 10.551 3.243 0.351 88.0 3.317 13.0 33.000 0.419 0.263 0.169 0.831 1.0 0.028 0.016 -0.039\n",
"1 11.579 1.013 0.043 4.0 1.460 2.0 42.429 0.333 0.783 0.180 0.820 30.0 0.013 0.020 -0.012\n",
"2 12.619 4.668 0.992 7761.5 32.634 63.0 62.937 0.621 0.017 1.000 0.000 0.0 0.160 0.130 -0.144\n",
"3 10.975 4.083 0.763 1386.0 9.485 24.0 45.412 0.643 0.116 1.000 0.000 0.0 0.020 0.025 -0.014\n",
"4 10.750 4.102 0.079 8.0 1.735 7.5 33.394 0.360 0.250 0.378 0.622 7.0 -0.000 -0.002 0.008\n",
"\n",
"=== Taux de churn globaux ===\n",
"churn_hard 0.684\n",
"churn_soft 0.775\n",
"churn_warning 0.321\n",
"dtype: float64\n",
"\n",
"=== Churn par cluster K=2 ===\n",
" n_clients churn_hard churn_soft churn_warning\n",
"cluster_k2 \n",
"0 389 0.740 0.823 0.342\n",
"1 38 0.105 0.289 0.105\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAGGCAYAAADmRxfNAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAS7lJREFUeJzt3XlcVGX///E3MzKCmqKgZIp7jguouBa3Zal3C6aWimlit4Sp5VJmuZS3imZUaotLuZMimZZR+o2s28qiQivTW6KyEnPPBTQzUHBmfn/4Y+4IUOAAB+X1fDx41Jw513V9DpwZz3vOuc54uFwulwAAAADAAIvZBQAAAAC48hEsAAAAABhGsAAAAABgGMECAAAAgGEECwAAAACGESwAAAAAGEawAAAAAGAYwQIAAACAYQQLAAAAAIYRLABckex2u2bOnGl2GYUyefJkBQcHm12GJGno0KEaOnSo2WWgBM2YMUMRERFml6EFCxbIbrcXqc0vv/yiVq1a6aeffiqlqgCUJYIFgHLlwIEDmjZtmnr06KGgoCC1b99egwYN0qpVq3Tu3Dmzy8NlLF68WFu2bDG7DMMOHToku92uFStW5Frucrk0bdo02e12LViwwNAYu3fv1syZM9WrVy+1a9dOt9xyix555BHt27ev0H0cPHhQb731lkaOHHnZ2sujZs2aqVu3bpo/f77ZpQAoAQQLAOXG1q1b1bt3b73//vu69dZb9e9//1sTJkzQddddpzlz5mj27Nlml4jLWLJkyVURLPLjcrk0Y8YMrVu3Tg8//LDGjh1rqL/ly5frww8/1I033qinnnpKAwcO1DfffKN+/foV+hP81atXq169errhhhsM1VISHnroIe3evbvI7QYNGqT//Oc/OnDgQClUBaAsVTK7AACQLn7yOn78eF133XVatWqV6tSp435uyJAh2r9/v7Zu3VqmNTmdTmVnZ6ty5cplOi5yO3/+vDw9PWWxmPtZ2KxZs/TGG29o1KhReuSRRwz3N2zYMM2dO1c2m829LDQ0VL1799bSpUs1d+7cS7bPzs7Wpk2bNGjQIMO1lIRKlSqpUqWiH1aEhISoRo0aio+PL5HfKwDzcMYCQLmwfPlyZWRkaPbs2blCRY6GDRvqX//6V57lW7Zs0V133aXAwED16tVLn332Wa7nJ0+erO7du+dpl9/14DnzNjZu3KhevXopKChIiYmJevvtt2W327Vjxw5FR0frhhtuULt27TR69Gilp6cXehsPHjyoyMhItWvXTl27dtXChQvlcrkkXfw0vHv37nrooYfytDt//rw6dOigadOmXXaMd999VwMGDFDbtm3VqVMnDRkyRJ9//nmB6+ds26FDh3It3759u+x2u7Zv3+5e9uuvv2rs2LH6xz/+oaCgIN18880aP368/vjjD0kXf38ZGRmKj4+X3W6X3W7X5MmT3e2PHTumKVOmKCQkxP33euutt/Id97333tOLL76om266SW3bttXZs2cvu+2l6emnn1ZcXJxGjhyp8ePHl0if7du3zxUqJKlRo0a6/vrrlZqaetn2O3bs0KlTpxQSElKs8dPS0vTkk08qJCREQUFB6tOnj+Lj43Otk99+IP3vcqu3337bvSy/19QXX3yhwYMHq2PHjgoODtbtt9+uF154Idc6np6e6ty5sz766KNibQeA8oMzFgDKhU8++UQBAQFq3759odvs2LFDH374oe677z5VrVpVsbGxGjdunD755BPVrFmzWHVs27ZN77//voYMGaKaNWuqXr16OnPmjKSLB5fVq1fXmDFjdPjwYa1atUozZ87USy+9dNl+HQ6Hhg8frrZt2+qJJ55QYmKiFixYIIfDoUceeUQeHh7q3bu3VqxYodOnT8vHx8fd9uOPP9bZs2fVp0+fS46xcOFCLViwQMHBwRo3bpw8PT313//+V9u2bVPXrl2L9fvIkZWVpcjISGVlZSk8PFx+fn46duyYtm7dqjNnzuiaa67R888/r6lTp6pNmzYaOHCgJKlBgwaSpJMnT2rgwIHy8PDQkCFDVKtWLX322Wd66qmndPbsWQ0bNizXeK+88oo8PT3dY3p6ehqq34hnnnlGsbGxevDBB/XYY4/led7pdOr06dOF6uuaa6655La4XC6dPHlS119//WX72rlzpzw8PNSqVatCjf1X586d09ChQ3XgwAENGTJE9evX1+bNmzV58mSdOXMm3xBfVD///LNGjhwpu92ucePGyWazaf/+/fr222/zrNu6dWt99NFHOnv2rKpVq2Z4bADmIFgAMN3Zs2d17Ngx9ejRo0jt9u7dq4SEBPfBa5cuXdS3b1+99957Cg8PL1Yt+/bt06ZNm9SsWTP3sh9++EGS5OPjo5UrV8rDw0PSxQPK2NhY/fHHH7rmmmsu2e/58+d10003aerUqZKk++67T6NGjdKyZcs0dOhQ1apVS3fffbcWL16s999/X4MHD3a33bhxo+rVq6cOHToU2P/+/fu1aNEi/fOf/9T8+fNzXTaUc1bEiL179+rQoUN6+eWXdccdd7iXjxkzxv3/ffv21YwZMxQQEKC+ffvmav/iiy/K4XBo06ZN7tA3ePBgPfbYY1q4cKEGDRokLy8v9/rnz5/Xhg0bci0zQ1xcnA4fPqzIyEg9/vjj+a5z5MiRQu+7q1evVpcuXQp8fuPGjTp27JjGjRt32b5SU1NVo0aNYh2Ir1u3Tnv37tWcOXPcgXXQoEEaOnSoXnrpJfXv39/wAf4XX3yh7OxsLVu2TLVq1brkugEBAXI6nUpNTVWbNm0MjQvAPAQLAKbLucylatWqRWoXEhLiDhWS1KJFC1WrVk0HDx4sdi2dOnXKFSr+KucT9xwdO3bUa6+9psOHD6tFixaX7XvIkCHu/8/55H7r1q1KSkpSr1691LhxY7Vt21abNm1yB4vTp08rMTFRkZGRucb+uy1btsjpdGr06NF55iJcql1h5Rxkfv755+rWrZu8vb0L3dblcunDDz/UnXfeKZfLlevysa5du+q9995TSkpKruB09913mx4qpItnWiSpcePGBa5Tu3ZtxcTEFKq/S+0ne/fu1cyZMxUcHKx77rnnsn2dPn1aNWrUKNS4f/fZZ5+pdu3auuuuu9zLPD09NXToUD322GP6+uuvdeuttxar7xzVq1eXJH300Ufq37//JefI5Kx76tQpQ2MCMBfBAoDpcg5a//zzzyK1q1u3bp5lNWrUcF+6VBz169cv8Lnrrrsu1+Ocg6HCjGexWBQQEJBrWc7B6uHDh93L+vbtq1mzZunw4cOqV6+eNm/erOzs7DxnAP7uwIEDslgsatq06WVrKY6AgABFREQoJiZGmzZtUseOHdW9e3f16dPnsmdr0tPTdebMGa1bt07r1q0rcJ2/utTf4e/tHA5H4Tbib2rVqiWr1XrJdR588EF9+umnmjZtmq655ppcZ2tyVK5cudjzHHKcOHFCI0eO1DXXXKOXX375snXlKO7ZqMOHD6thw4Z5DvZz9p8jR44Uq9+/Cg0N1ZtvvqmpU6dq3rx5uvHGG/XPf/5Td9xxR55xS+KsGgDzESwAmK5atWqqU6eOfv755yK1K+jg668HKQV9Wl/QweilPiUv6BPXkjwo6tWrl6Kjo7Vp0yaNGjVKGzduVGBgoJo0aVJiY/xVQb8fp9OZZ9nkyZN1zz336KOPPtIXX3yhp59+WkuWLNH69et17bXXFjhGTl99+vQp8JP4v0/6LezZigEDBuQKZkXx0UcfXTbAVKlSRcuWLVN4eLgef/xxVatWLc98FYfDUehJ/DVq1MgzYfuPP/7Qgw8+qD/++ENxcXHy9/cvVF8+Pj6GQnRhFGX/+DsvLy/FxcVp+/bt2rp1qxITE5WQkKB169Zp5cqVuV6/OdtR3LlRAMoHggWAcuHWW2/VunXrtHPnzhL9lurq1avne/BVEp/IFoXT6dTBgwdzXVKT80Vo9erVcy/z8fHRLbfcok2bNql379769ttv9eSTT162/wYNGsjpdGrv3r1q2bJloevKOeuSc2enHAUdrOfc7enhhx/Wt99+q8GDB2vt2rWXvFNSrVq1VLVqVTm
"text/plain": [
"<Figure size 800x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"=== Churn par cluster K=5 ===\n",
" n_clients churn_hard churn_soft churn_warning\n",
"cluster_k5 \n",
"0 67 0.015 0.075 0.134\n",
"1 29 0.138 0.276 0.138\n",
"2 90 0.944 0.978 0.478\n",
"3 229 0.882 0.987 0.349\n",
"4 12 0.000 0.333 0.083\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAGGCAYAAADmRxfNAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAASRhJREFUeJzt3Xl8TPf+x/F3MhJJbCERVO1qLAmi9lpatFqKonZ6LVV7W9Varl4VW9RytZbWFqklRdRSrqWu9lpaoa5yqW4qSiy1JFRJIjGZ3x8emV9HIpKcSSbL6/l4eDzMmXO+5zMnX3Lec77fc1ysVqtVAAAAAGCAq7MLAAAAAJD7ESwAAAAAGEawAAAAAGAYwQIAAACAYQQLAAAAAIYRLAAAAAAYRrAAAAAAYBjBAgAAAIBhBAsAAAAAhhEsAORKZrNZU6ZMcXYZ6TJ+/HgFBgY6uwxJUr9+/dSvXz9nlwEHGjx4sN59911nl6Hx48erVatWGdpm//79CgwMVExMTBZVBSA7ESwA5Cjnz5/XpEmT1Lp1awUEBKhevXrq2bOnVq5cqfj4eGeXh0dYvHix9uzZ4+wyDLtw4YLMZrNCQkLsllutVk2aNElms1kLFiwwtI/Dhw/LbDan+uf48ePpauPo0aP65ptvNHjw4BTt7tq1y1B92aFFixYqX768lixZ4uxSADhAAWcXAADJ9u7dqzfeeEPu7u7q1KmTqlWrpsTERB09elSzZ8/Wr7/+qqlTpzq7TKRhyZIlatu2rdq0aePsUhzOarVq8uTJWr9+vYYPH65Ro0Y5pN1+/fopICDAbln58uXTtW1ISIiaNGmiChUqOKQWI6ZOnSqr1Zrh7Xr06KFZs2Zp1KhRKly4cBZUBiC7ECwA5AhRUVEaPXq0HnvsMa1cuVJ+fn629/r06aNz585p79692VpTUlKSEhMTVbBgwWzdL+zdvXtXbm5ucnV17kX2qVOnat26dRo6dKjeeOMNh7Vbv359Pf/88xneLjo6Wvv27dPkyZMdVosRbm5umdqubdu2mjZtmnbt2qWXX37ZwVUByE4MhQKQIyxfvlyxsbGaPn26XahIVqFCBf3tb39LsXzPnj168cUX5e/vr/bt22v//v127z9s3PeCBQtkNpvtliXP29i6davat2+vgIAAHThwQJs2bZLZbNbRo0cVHBysxo0bq27duhoxYkSGxoZHRUVp0KBBqlu3rpo1a6aFCxfavuG1Wq1q1aqVhg0blmK7u3fv6sknn9SkSZMeuY/PP/9cL7/8surUqaMGDRqoT58++vrrrx+6fvJnu3Dhgt3y5OE0hw8fti377bffNGrUKD311FMKCAhQixYtNHr0aP3555+S7h+/2NhYbd682TakZ/z48bbtr1y5ogkTJqhp06a2n9dnn32W6n63b9+uefPmqXnz5qpTp45u3779yM+elaZNm6awsDANGTJEo0ePdnj7t2/f1r179zK0zd69e3Xv3j01bdo0U/uMiorS66+/roYNG6pOnTrq3r17ivCekf6R2r+17du3q0uXLgoMDFS9evXUoUMHrVy50m4dHx8fmc1mffnll5n6HAByDq5YAMgR/vOf/6hcuXKqV69eurc5evSodu/erd69e6tQoUJavXq1Xn/9df3nP/9R8eLFM1XHoUOHtHPnTvXp00fFixdX2bJldevWLUn3Ty6LFi2qkSNH6uLFi1q5cqWmTJmiDz744JHtWiwWvfrqq6pTp47eeecdHThwQAsWLJDFYtEbb7whFxcXdejQQSEhIbp586a8vb1t23711Ve6ffu2OnbsmOY+Fi5cqAULFigwMFCvv/663Nzc9L///U+HDh1Ss2bNMnU8kiUkJGjQoEFKSEhQ37595evrqytXrmjv3r26deuWihQpolmzZundd99V7dq11b17d0n/P6Tn+vXr6t69u1xcXNSnTx+VKFFC+/fv18SJE3X79m3179/fbn8fffSR3NzcbPvM7LfhjjBjxgytXr1agwcP1ltvvZXi/aSkJN28eTNdbRUpUiTFZ5kwYYJiY2NlMpn05JNPauzYsSmGRqXm2LFj8vb2VtmyZdO177+6fv26evbsqbi4OPXr10/FixfX5s2bNWzYMM2fP1/PPvtshtt80DfffKO33npLTZo00dtvvy1JioyM1HfffZfiS4JatWrlibk5QH5HsADgdLdv39aVK1fUunXrDG135swZ7dixw3by2qhRI3Xq1Enbt29X3759M1XL2bNntW3bNlWtWtW27Mcff5QkeXt7a8WKFXJxcZF0/4Ry9erV+vPPP1WkSJE02717966aN29uu3tP7969NXToUC1btkz9+vVTiRIl9NJLL2nx4sXauXOnevXqZdt269atKlu2rJ588smHtn/u3DktWrRIzz77rObPn283bCgz494fdObMGV24cEEffvih3bCdkSNH2v7eqVMnTZ48WeXKlVOnTp3stp83b54sFou2bdtmC329evXSW2+9pYULF6pnz57y8PCwrX/37l1t3LjRbpkzhIWF6eLFixo0aJDt5PhBly5dSnffXbVqlRo1aiTp/tChtm3bqkWLFipevLjOnDmjkJAQ9enTR+vWrVPNmjXTbCsyMjJToUKSli5dquvXryssLEz169eXJHXr1k0dO3ZUcHCwWrdubXjo2d69e1W4cGGFhITIZDKluW65cuV048YNRUdHy8fHx9B+ATgPwQKA0yUPcylUqFCGtmvatKndJNfq1aurcOHCioqKynQtDRo0sAsVf5X8jXuy+vXr65NPPtHFixdVvXr1R7bdp08f29+Tv7nfu3evIiIi1L59e1WqVEl16tTRtm3bbMHi5s2bOnDggAYNGmS37wft2bNHSUlJGjFiRIoTwrS2S6/kSbVff/21WrZsKU9Pz3Rva7VatXv3br3wwguyWq12w8eaNWum7du369SpU3bB6aWXXnJ6qJDuf7MvSZUqVXroOiVLllRoaGi62vtrP6lXr57dFbrWrVurbdu26tixo+bOnZvijlQPunnzpkqVKpWu/T5o3759ql27ti1USPf//fXo0UNz587Vr7/+qmrVqmWq7WRFixZVXFycvvnmG7Vo0eKR60rSjRs3CBZALkawAOB0ySetd+7cydB2ZcqUSbGsWLFitqFLmfH4448/9L3HHnvM7nXyyVB69ufq6qpy5crZLUs+Wb148aJtWadOnTR16lRdvHhRZcuW1a5du5SYmJjiCsCDzp8/L1dXV1WpUuWRtWRGuXLlNGDAAIWGhmrbtm2qX7++WrVqpY4dOz7yak1MTIxu3bql9evXa/369Q9d56/S+jk8uJ3FYknfh3hAiRIlHvlN+uDBg7Vv3z5NmjRJRYoUSXWSdcGCBTM9z+FBFSpUUOvWrbV7925ZLJZH1pfZq1GXLl1SnTp1UiyvXLmy7X2jwaJ3797auXOnBg8erFKlSumpp57SCy+8kGrISP4cjgjBAJyHYAHA6QoXLiw/Pz+dPn06Q9s97KTrrydbDztRedjJaFrfkj9saIgjhhola9++vYKDg7Vt2zYNHTpUW7dulb+/v+2Ez9EednySkpJSLBs/frw6d+6sL7/8Ut98842mTZumJUuWKDw8XKVLl37oPpLb6tixozp37pzqOg9OpE/v1YqXX37ZLphlxJdffvnIAOPl5aVly5apb9++evvtt1W4cOEU81UsFku6J/EXK1ZM7u7uaa5TunRpJSYmKi4uLs3br3p7exsK0emRkf7xIB8fH23ZskVff/219u/fr/3792vTpk166aWX9P7779utm/w5Mjs3CkDOQLAAkCM888wzWr9+vY4dO+bQp1QXLVo01ZOvS5cuOWwf6ZGUlKSoqCi7ITVnz56VJLtx8t7e3nr66ae1bds2dejQQd99953+/ve/P7L98uXLKykpSWfOnFGNGjXSXVfyVZfkOzsle9jJevLdnoYPH67vvvtOvXr10tq1a9O8U1KJEiVUqFAhJSUlOeyb/WSzZ8/W3bt3M7VtyZIl07Ve8eLFtWLFCvXq1UujRo3SihUr7Pro5cuXMzXH4mEuXLigggULysvLK831KleurN2
"text/plain": [
"<Figure size 800x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAuEAAAKyCAYAAAB7WgDLAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsvXfYbkdZLn7PzOpv+9r+dt/pe1OSnIRACiogAooHKQFEQFQM0gz15Bia/lAUgggeQqSJ9OZRQOTIQRTlCBpCEYgCBkjZvX3l7e+qM78/ZuaZ9SWB7ISQouu5rn1d736/9a41fc08z/3cN1NKKTTWWGONNdZYY4011lhjd5nxu7sAjTXWWGONNdZYY4019l/Nmk14Y4011lhjjTXWWGON3cXWbMIba6yxxhprrLHGGmvsLrZmE95YY4011lhjjTXWWGN3sTWb8MYaa6yxxhprrLHGGruLrdmEN9ZYY4011lhjjTXW2F1szSa8scYaa6yxxhprrLHG7mJrNuGNNdZYY4011lhjjTV2F1uzCW+sscYaa6yxxhprrLG72JpNeGON3QPsLW95C/bs2XN3F6OxH2Ive9nL8PCHP/zuLsZ/Gnv1q1+NZz7zmXd3Me7Q3Pv+97+P+93vfvjud7/7YypVY4019l/Bmk14Y43dyfbxj38ce/bsoX9nnXUWfvInfxKXXHIJ3v/+92M8Ht8pzzl69Cje8pa34Dvf+c6dcr//KjabzfCWt7wF11xzzd1dlB+L7dmzB7/3e793i+/f/va3Y8+ePXj5y18OKeUdvv+BAwc2jO/6v7/5m785oXvs378ff/mXf4nnPOc5t7jvn/3Zn93hst1Vdvrpp+OhD30orrzyyru7KI011ti92Ly7uwCNNfaf1V74whdix44dKMsSKysr+PKXv4zXvva1eO9734u3vvWtuM997kPXPu95z8Ozn/3s23X/Y8eO4aqrrsL27dtx3/ve984u/n9am81muOqqq3DppZfiggsuOOHfveY1r4FS6sdYsh+fvfOd78Qf//Ef4wlPeAL+4A/+AJz/6P6XxzzmMXjIQx6y4btzzjnnhH77/ve/H9u3b8eFF174I5fjR7U7MvcA4Jd+6Zfw7Gc/G/v27cOuXbt+DCVrrLHG/rNbswlvrLEfkz3kIQ/BWWedRf9/znOeg6uvvhrPfe5z8fznPx+f/vSnEUURAMDzPHheMx3viTadTpEkCXzfv7uLcofsXe96F974xjfi8Y9/PF772tfeKRtwALjf/e6Hxz3ucbf7d0VR4FOf+hR+6Zd+6U4px49qd3TuPfjBD0av18MnPvEJvOhFL/oxlKyxxhr7z24NHKWxxu5Cu+iii/D85z8fBw8exF//9V/T97eGS/3nf/5nPPWpT8UDH/hAnHvuufjZn/1ZvOlNbwIAXHPNNXjSk54EAHj5y19OcICPf/zjAICvfvWreOELX4iHPexhOPPMM/HQhz4Ur33ta5Gm6YZnvOxlL8O5556Lo0eP4vnPfz7OPfdcXHjhhXj961+Pqqo2XCulxPve9z78wi/8As466yxceOGFuOSSS/Bv//ZvG6775Cc/iYsvvhhnn302zj//fLzkJS/B4cOHb7NtbBvceOONuOyyy3DeeefhwgsvxP/6X/8LSikcPnwYz3ve8/CABzwAP/ETP4F3v/vdG36f5zne/OY34+KLL8Z5552Hc845B0972tPwpS99ia45cOAALrroIgDAVVddRe32lre8ZUN77Nu3D7/xG7+Bc889F5dddhn9rY4Jv/LKK3Gf+9wHV1999YZy/PZv/zbOPPNM/Md//Mdt1vnHbe95z3vwhje8AY997GPxute97k7bgFubTqfI8/x2/eZrX/sa1tfX8eAHP/gOPXN1dRWveMUr8OAHPxhnnXUWHvvYx+ITn/jEhmuuueYa7Nmz5xaQIwt5sfMEuP1zz5rv+zj//PPxuc997g7Vo7HGGmuscb011thdbI973OPwpje9CV/84hfxi7/4i7d6zfe+9z085znPwZ49e/DCF74QQRBg7969+Nd//VcAwGmnnYYXvvCFuPLKK/GUpzwF5513HgDgAQ94AADgM5/5DNI0xVOf+lTMzc3h2muvxQc/+EEcOXLkFjjWqqpwySWX4Oyzz8Zv/dZv4eqrr8a73/1u7Ny5E0972tPoule+8pX4+Mc/joc85CF40pOehKqq8NWvfhXf/OY3yeP/tre9DW9+85vx6Ec/Gk960pOwtraGD37wg3j605+Ov/qrv0K3273N9nnJS16C0047Df/jf/wP/L//9//wtre9DXNzc/joRz+KCy+8EJdddhk+9alP4fWvfz3OOussPOhBDwIAjMdj/MVf/AUe85jH4MlPfjImkwn+8i//Es961rPwF3/xF7jvfe+LhYUFvPrVr8arX/1qPPKRj8QjH/lIANiwCSvLEpdccgnOO+88XH755RStuLk973nPwz/+4z/ila98Jf76r/8a7XYbX/jCF/C///f/xote9KINcKO7w973vvfhiiuuwGMe8xhcccUVt7oBX1tbO6F7tdttBEGw4burrroKf/iHfwjGGO5///vjJS95CX7yJ3/yNu/19a9/HYwx3O9+9zuxitQsTVM84xnPwL59+/D0pz8dO3bswGc+8xm87GUvw3A4xK/+6q/e7nve3G5r7tXt/ve/Pz73uc9hPB6j3W7/yM9urLHG/ouZaqyxxu5U+9jHPqZ2796trr322h94zXnnnace//jH0/+vvPJKtXv3bvr/e97zHrV79261urr6A+9x7bXXqt27d6uPfexjt/jbbDa7xXfveMc71J49e9TBgwfpu8svv1zt3r1bXXXVVRuuffzjH6+e8IQn0P+vvvpqtXv3bvWa17zmFveVUiqllDpw4IC6733vq972trdt+Pt1112n7ne/+93i+5ubbYPf/u3fpu/KslQPechD1J49e9Q73vEO+n4wGKizzz5bXX755RuuzbJswz0Hg4F68IMfrF7+8pfTd6urq2r37t3qyiuvvEUZbHv80R/90a3+7ad/+qdvUbf73//+6pWvfKUaDAbqp37qp9TFF1+siqL4oXX9cdru3bvVT//0T6vdu3erl770paosyx967Yn8q4+xgwcPql//9V9XH/7wh9XnPvc59d73vlc97GEPU/e5z33UP/7jP95m+S677DJ1/vnn3+L7/fv3q927d6t3vetdP/C3733ve9Xu3bvVJz/5Sfouz3P1lKc8RZ1zzjlqNBoppZT60pe+pHbv3q2+9KUv3eoz6vW5I3PP2qc+9Sm1e/du9c1vfvM2r22sscYau7k1nvDGGrsbLEkSTCaTH/h36zH+3Oc+hyc+8Ym3G0ZQ995Op1OkaYpzzz0XSil8+9vfxrZt2zZc/9SnPnXD/88777wNcJnPfvazYIzh0ksvvcWzGGMAgL/7u7+DlBKPfvSjN3hYl5aWcNJJJ+Gaa67Bc5/73Nssu4XZAIAQAmeeeSaOHDmy4ftut4tTTjkF+/fv33CtEAKAhs4Mh0NIKXHmmWfi29/+9m0+t243b48fZLt378YLX/hCvPGNb8R1112H9fV1vPvd777b8f0rKysAgB07dlCb3Jq95z3vOaH7nX766fR527Ztt2AwedzjHof//t//O6644go87GEP+6H36vf76PV6J/Tcm9s//dM/YdOmTXjMYx5D3/m+j2c84xl46Utfiq985Sv46Z/+6Tt0b2u3Z+7Za9fX13+kZzbWWGP/Na3ZhDfW2N1g0+kUi4uLP/DvP//zP4+/+Iu/wKte9Sq88Y1vxEUXXYRHPvKR+Lmf+7kT2pAfOnQIV155Jf7hH/4Bg8Fgw99uTpEYhiEWFhY2fNfr9Tb8bt++fVheXsbc3NwPfOZNN90EpRQe9ahH3erfT3RjevMDQqfTudUydjod9Pv9Dd994hOfwLvf/W7ceOONKIqCvt+xY8cJPduWc8uWLSd8/SWXXIK/+Zu/wbXXXouXvvSlGzasP8j6/f6G8t0e6/V6t4CG3Nwe//jH49ixY3j729+O+fl5/Nqv/dqtXndHcdk3t7m5OVx88cV45zvfiSNHjtx
"text/plain": [
"<Figure size 800x700 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"===== K=2 =====\n",
" n_clients aum_qty_mean_med freq_med gross_flow_to_aum_med n_tx_med holding_med exit_rate_med flow_dir_med drawdown_med months_inactive_med corr_fund_lag3_med corr_rate_lag3_med\n",
"cluster_k2 \n",
"0 389 73435.780 0.763 4.335 1436.0 46.273 0.606 0.114 1.000 0.0 0.047 -0.040\n",
"1 38 67965.743 0.043 1.506 4.0 40.357 0.292 0.580 0.303 17.5 0.006 -0.008\n",
"\n",
"===== K=5 =====\n",
" n_clients aum_qty_mean_med freq_med gross_flow_to_aum_med n_tx_med holding_med exit_rate_med flow_dir_med drawdown_med months_inactive_med corr_fund_lag3_med corr_rate_lag3_med\n",
"cluster_k5 \n",
"3 229 58391.143 0.763 4.083 1386.0 45.412 0.643 0.116 1.000 0.0 0.020 -0.014\n",
"2 90 302331.761 0.992 4.668 7761.5 62.937 0.621 0.017 1.000 0.0 0.160 -0.144\n",
"0 67 38200.766 0.351 3.243 88.0 33.000 0.419 0.263 0.169 1.0 0.028 -0.039\n",
"1 29 106782.844 0.043 1.013 4.0 42.429 0.333 0.783 0.180 30.0 0.013 -0.012\n",
"4 12 46632.822 0.079 4.102 8.0 33.394 0.360 0.250 0.378 7.0 -0.000 0.008\n"
]
}
],
"source": [
"# ============================================================\n",
"# GRAPHIQUES — Approche Louis (400 grands comptes)\n",
"# ============================================================\n",
"\n",
"# ── 1. Segmentation 2D : intensité relative vs fréquence ──────────────────\n",
"thr_int = dfc_louis[\"gross_flow_to_aum\"].median()\n",
"thr_freq = dfc_louis[\"flow_freq\"].median()\n",
"\n",
"def quadrant(row):\n",
" low_int = row[\"gross_flow_to_aum\"] < thr_int\n",
" low_frq = row[\"flow_freq\"] < thr_freq\n",
" if low_int and low_frq: return \"Dormant (low int, low freq)\"\n",
" if low_int and not low_frq: return \"Small rebalancers (low int, high freq)\"\n",
" if not low_int and low_frq: return \"Occasional large movers (high int, low freq)\"\n",
" return \"Highly active (high int, high freq)\"\n",
"\n",
"dfc_louis[\"seg_2D\"] = dfc_louis.apply(quadrant, axis=1)\n",
"print(dfc_louis[\"seg_2D\"].value_counts())\n",
"print(f\"thr_int: {thr_int:.4f} | thr_freq: {thr_freq:.4f}\")\n",
"\n",
"plt.figure(figsize=(9, 5))\n",
"for name, g in dfc_louis.groupby(\"seg_2D\"):\n",
" plt.scatter(g[\"flow_freq\"], g[\"gross_flow_to_aum\"], s=10, label=name)\n",
"plt.yscale(\"log\")\n",
"plt.axvline(thr_freq, linestyle=\"--\", color=\"gray\")\n",
"plt.axhline(thr_int, linestyle=\"--\", color=\"gray\")\n",
"plt.xlabel(\"Activity frequency (share of active months)\")\n",
"plt.ylabel(\"Gross flow / mean AUM [log scale]\")\n",
"plt.title(\"2D behavioral segmentation — 400+ grands comptes\")\n",
"plt.legend(markerscale=2)\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"# ── 2. Clusters K=5 dans l'espace 2D intensité/fréquence ──────────────────\n",
"labels_map = {\n",
" 0: \"Cluster 0 : Large and highly active movers\",\n",
" 1: \"Cluster 1 : Occasional large movers\",\n",
" 3: \"Cluster 3 : Dormant profiles\",\n",
" 4: \"Cluster 4 : Loyal clients\"\n",
"}\n",
"\n",
"plt.figure(figsize=(9, 5))\n",
"for name, g in dfc_louis[~dfc_louis[\"cluster_k5\"].isin([2])].groupby(\"cluster_k5\"):\n",
" plt.scatter(\n",
" g[\"flow_freq\"], g[\"gross_flow_to_aum\"],\n",
" s=10, label=labels_map.get(int(name), f\"Cluster {int(name)}\")\n",
" )\n",
"plt.yscale(\"log\")\n",
"plt.axvline(thr_freq, linestyle=\"--\", color=\"gray\")\n",
"plt.axhline(thr_int, linestyle=\"--\", color=\"gray\")\n",
"plt.xlabel(\"Activity frequency (share of active months)\")\n",
"plt.ylabel(\"Gross flow / mean AUM [log scale]\")\n",
"plt.title(\"K=5 — Clusters dans l'espace intensité/fréquence (hors C2 extrêmes)\")\n",
"plt.ylim(0.1, 1000)\n",
"plt.legend(markerscale=2)\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"# ── 3. Double graphique : intensité/fréquence + churn/loyalty ─────────────\n",
"if \"log_n_tx_total\" not in dfc_louis.columns:\n",
" dfc_louis[\"log_n_tx_total\"] = np.log1p(dfc_louis[\"n_tx_total\"].clip(lower=0))\n",
"\n",
"thr_log_tx = dfc_louis[\"log_n_tx_total\"].median()\n",
"thr_churn = dfc_louis[\"aum_drawdown_last\"].median()\n",
"thr_hold = dfc_louis[\"avg_holding_months_per_isin\"].median()\n",
"\n",
"color_map = {1: \"#ff7f0e\", 4: \"red\"}\n",
"\n",
"fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
"\n",
"# Graphique 1 : log_n_tx_total vs gross_flow_to_aum\n",
"for name, g in dfc_louis[~dfc_louis[\"cluster_k5\"].isin([2, 4])].groupby(\"cluster_k5\"):\n",
" axes[0].scatter(\n",
" g[\"log_n_tx_total\"], g[\"gross_flow_to_aum\"],\n",
" s=10, label=labels_map.get(int(name), f\"Cluster {int(name)}\")\n",
" )\n",
"axes[0].set_yscale(\"log\")\n",
"axes[0].axvline(thr_log_tx, linestyle=\"--\", color=\"gray\")\n",
"axes[0].axhline(thr_int, linestyle=\"--\", color=\"gray\")\n",
"axes[0].set_xlabel(\"Activity frequency (log n_tx_total)\")\n",
"axes[0].set_ylabel(\"Gross flow / mean AUM\")\n",
"axes[0].set_title(\"Intensité vs fréquence (log transactions)\")\n",
"axes[0].set_ylim(0.1, 1000)\n",
"axes[0].legend(markerscale=2)\n",
"\n",
"# Graphique 2 : avg_holding_months_per_isin vs aum_drawdown_last\n",
"for name, g in dfc_louis[~dfc_louis[\"cluster_k5\"].isin([0, 2, 3])].groupby(\"cluster_k5\"):\n",
" axes[1].scatter(\n",
" g[\"avg_holding_months_per_isin\"], g[\"aum_drawdown_last\"],\n",
" s=10,\n",
" color=color_map.get(int(name), \"gray\"),\n",
" label=labels_map.get(int(name), f\"Cluster {int(name)}\")\n",
" )\n",
"axes[1].set_yscale(\"log\")\n",
"axes[1].axvline(thr_hold, linestyle=\"--\", color=\"gray\")\n",
"axes[1].axhline(thr_churn, linestyle=\"--\", color=\"gray\")\n",
"axes[1].set_xlabel(\"avg_holding_months_per_isin\")\n",
"axes[1].set_ylabel(\"aum_drawdown_last\")\n",
"axes[1].set_title(\"Churn vs Loyalty (clusters 1 et 4)\")\n",
"axes[1].set_ylim(0.001, 1.3)\n",
"axes[1].legend(markerscale=2)\n",
"\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"# ── 4. Heatmap K=5 ────────────────────────────────────────────────────────\n",
"prof_louis_k5 = plot_heatmap(\n",
" dfc_louis, profile_vars_louis, \"cluster_k5\",\n",
" title=\"Cluster signatures — 400 grands comptes K=5 (robust z-score)\",\n",
" figsize=(16, 4)\n",
")\n",
"print(\"\\n=== Médianes K=5 (Louis) ===\")\n",
"print(prof_louis_k5.round(3).to_string())\n",
"\n",
"# ── 5. Analyse churn ──────────────────────────────────────────────────────\n",
"dfc_louis[\"churn_hard\"] = (dfc_louis[\"aum_final_to_peak\"] < 0.10).astype(int)\n",
"dfc_louis[\"churn_soft\"] = (\n",
" (dfc_louis[\"aum_final_to_peak\"] < 0.40) &\n",
" (dfc_louis[\"aum_drawdown_last\"] > 0.40)\n",
").astype(int)\n",
"dfc_louis[\"churn_warning\"] = (\n",
" (dfc_louis[\"flow_direction_balance\"] < 0) &\n",
" (dfc_louis[\"aum_drawdown_last\"] > 0.20)\n",
").astype(int)\n",
"\n",
"print(\"\\n=== Taux de churn globaux ===\")\n",
"print(dfc_louis[[\"churn_hard\", \"churn_soft\", \"churn_warning\"]].mean().round(3))\n",
"\n",
"for k in [2, 5]:\n",
" churn_profile = (\n",
" dfc_louis.groupby(f\"cluster_k{k}\")\n",
" .agg(\n",
" n_clients = (ID_COL, \"count\"),\n",
" churn_hard = (\"churn_hard\", \"mean\"),\n",
" churn_soft = (\"churn_soft\", \"mean\"),\n",
" churn_warning = (\"churn_warning\", \"mean\"),\n",
" )\n",
" )\n",
" print(f\"\\n=== Churn par cluster K={k} ===\")\n",
" print(churn_profile.round(3).to_string())\n",
"\n",
" churn_profile[[\"churn_hard\", \"churn_soft\", \"churn_warning\"]].plot(\n",
" kind=\"bar\", figsize=(8, 4),\n",
" color=[\"#d62728\", \"#ff7f0e\", \"#ffbb78\"]\n",
" )\n",
" plt.title(f\"Churn by cluster — K={k} (Louis)\")\n",
" plt.ylabel(\"Rate\")\n",
" plt.xlabel(\"Cluster\")\n",
" plt.xticks(rotation=0)\n",
" plt.tight_layout()\n",
" plt.show()\n",
"\n",
"# ── 6. Matrice de distance inter-cluster ──────────────────────────────────\n",
"def plot_distance_matrix(X_scaled, labels, max_points=400,\n",
" title=\"Distance matrix\"):\n",
" n = X_scaled.shape[0]\n",
" idx = np.arange(n)\n",
" if n > max_points:\n",
" rng = np.random.default_rng(42)\n",
" idx = rng.choice(idx, size=max_points, replace=False)\n",
" X_sub = X_scaled[idx]\n",
" labels_sub = np.asarray(labels)[idx]\n",
" order = np.lexsort((np.arange(len(labels_sub)), labels_sub))\n",
" X_sub = X_sub[order]\n",
" labels_sub = labels_sub[order]\n",
" D = pairwise_distances(X_sub)\n",
" plt.figure(figsize=(8, 7))\n",
" sns.heatmap(D, cmap=\"viridis\")\n",
" unique_labels, counts = np.unique(labels_sub, return_counts=True)\n",
" for b in np.cumsum(counts)[:-1]:\n",
" plt.axhline(b, color=\"red\", linewidth=2)\n",
" plt.axvline(b, color=\"red\", linewidth=2)\n",
" plt.title(title)\n",
" plt.tight_layout()\n",
" plt.show()\n",
"\n",
"plot_distance_matrix(\n",
" X_louis_scaled,\n",
" dfc_louis[\"cluster_k5\"].values,\n",
" title=\"Distance matrix — K=5 (Louis)\"\n",
")\n",
"\n",
"# ── 7. Tableau de profil complet par cluster ──────────────────────────────\n",
"for k in [2, 5]:\n",
" print(f\"\\n===== K={k} =====\")\n",
" prof = (\n",
" dfc_louis.groupby(f\"cluster_k{k}\")\n",
" .agg(\n",
" n_clients = (ID_COL, \"count\"),\n",
" aum_qty_mean_med = (\"aum_qty_mean\", \"median\"),\n",
" freq_med = (\"flow_freq\", \"median\"),\n",
" gross_flow_to_aum_med = (\"gross_flow_to_aum\", \"median\"),\n",
" n_tx_med = (\"n_tx_total\", \"median\"),\n",
" holding_med = (\"avg_holding_months_per_isin\",\"median\"),\n",
" exit_rate_med = (\"exit_rate_per_isin\", \"median\"),\n",
" flow_dir_med = (\"flow_direction_balance\", \"median\"),\n",
" drawdown_med = (\"aum_drawdown_last\", \"median\"),\n",
" months_inactive_med = (\"months_since_last_tx\", \"median\"),\n",
" corr_fund_lag3_med = (\"corr_flow_fund_lag3\", \"median\"),\n",
" corr_rate_lag3_med = (\"corr_flow_rate_lag3\", \"median\"),\n",
" )\n",
" .sort_values(\"n_clients\", ascending=False)\n",
" )\n",
" print(prof.round(3).to_string())"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "96e2d1b4-329f-4da7-bee2-916ee5dc3fd3",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"======================================================================\n",
"COMPARAISON — Approche globale (Sarah) vs 400 grands comptes (Louis)\n",
"======================================================================\n",
"Comptes communs aux deux approches : 293\n",
"\n",
"Croisement Sarah K=4 x Louis K=5 (n=293) :\n",
" Louis C0 Louis C1 Louis C2 Louis C3 Louis C4\n",
"Sarah C0 39.0 27.0 0.0 23.0 11.0\n",
"Sarah C1 0.0 100.0 0.0 0.0 0.0\n",
"Sarah C2 16.0 1.0 8.0 74.0 1.0\n",
"Sarah C3 30.0 44.0 0.0 11.0 15.0\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 800x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Adjusted Rand Index Sarah x Louis : 0.3394\n",
"(0 = indépendants, 1 = identiques)\n"
]
}
],
"source": [
"# ============================================================\n",
"# COMPARAISON DES DEUX APPROCHES\n",
"# ============================================================\n",
"print(\"\\n\" + \"=\"*70)\n",
"print(\"COMPARAISON — Approche globale vs 400 grands comptes\")\n",
"print(\"=\"*70)\n",
"\n",
"# Comptes communs\n",
"common_ids = set(dfc[ID_COL]).intersection(set(dfc_400_accounts[ID_COL]))\n",
"print(f\"Comptes communs aux deux approches : {len(common_ids)}\")\n",
"\n",
"# Croisement des clusterings sur les comptes communs\n",
"dfc_compare = (\n",
" dfc[dfc[ID_COL].isin(common_ids)][[ID_COL, \"cluster_k4\"]]\n",
" .rename(columns={\"cluster_k4\": \"cluster_global\"})\n",
" .merge(\n",
" dfc_400_accounts[dfc_400_accounts[ID_COL].isin(common_ids)][[ID_COL, \"cluster_k5\"]]\n",
" .rename(columns={\"cluster_k5\": \"cluster_400_accounts\"}),\n",
" on=ID_COL\n",
" )\n",
")\n",
"\n",
"print(f\"\\nCroisement K=4 x K=5 (n={len(dfc_compare)}) :\")\n",
"ct = pd.crosstab(\n",
" dfc_compare[\"cluster_global\"],\n",
" dfc_compare[\"cluster_400_accounts\"],\n",
" normalize=\"index\"\n",
").round(2) * 100\n",
"ct.index = [f\"Global C{i}\" for i in ct.index]\n",
"ct.columns = [f\"Top 400 Accounts C{i}\" for i in ct.columns]\n",
"print(ct.to_string())\n",
"\n",
"plt.figure(figsize=(8, 5))\n",
"sns.heatmap(ct, cmap=\"Blues\", annot=True, fmt=\".1f\",\n",
" cbar_kws={\"label\": \"%\"})\n",
"plt.title(\"Croisement clustering global (K=4) x 400 grands comptes (K=5)\")\n",
"plt.tight_layout(); plt.show()\n",
"\n",
"ari = adjusted_rand_score(\n",
" dfc_compare[\"cluster_global\"].values,\n",
" dfc_compare[\"cluster_400_accounts\"].values\n",
")\n",
"print(f\"\\nAdjusted Rand Index Global x Top 400 Accounts : {ari:.4f}\")\n",
"print(\"(0 = indépendants, 1 = identiques)\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}