Project_Carmignac/Clustering_FundFamily_Multimethod.ipynb

9656 lines
1.5 MiB
Plaintext
Raw Normal View History

2026-04-14 10:10:37 +02:00
{
"cells": [
{
"cell_type": "markdown",
"id": "13c6141d",
"metadata": {
"id": "13c6141d"
},
"source": [
"# Behavioral Clustering of Carmignac Investors\n",
"## Fund-Family Level Analysis\n",
"\n",
"This notebook builds a behavioral segmentation of Carmignac investors at the fund-family level.\n",
"\n",
"The main objectives are:\n",
"1. construct a monthly client × fund-family panel from repaired AUM and flow data,\n",
"2. engineer behavioral features based primarily on quantity dynamics,\n",
"3. cluster investors within the largest fund families,\n",
"4. compare several clustering algorithms,\n",
"5. interpret the resulting groups through churn-related indicators.\n",
"\n",
"The notebook is based on the initial project version and has been cleaned for reproducibility and readability."
]
},
{
"cell_type": "markdown",
"id": "28e588fe",
"metadata": {
"id": "28e588fe"
},
"source": [
"---\n",
"## 1. Imports\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "3bc1ffe0",
"metadata": {
"id": "3bc1ffe0"
},
"outputs": [],
"source": [
"import os\n",
"import re\n",
"import warnings\n",
"warnings.filterwarnings(\"ignore\")\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, AgglomerativeClustering\n",
"from sklearn.mixture import GaussianMixture\n",
"from sklearn.metrics import silhouette_score, davies_bouldin_score\n",
"from sklearn.decomposition import PCA\n",
"from sklearn.impute import SimpleImputer"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "69d2dc25",
"metadata": {
"id": "69d2dc25"
},
"outputs": [],
"source": [
"# Column names used throughout the notebook\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\""
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "455df8f5-2914-4efc-a7b8-4afacb985909",
"metadata": {},
"outputs": [],
"source": [
"EPS = 1e-9\n",
"RANDOM_STATE = 42"
]
},
{
"cell_type": "markdown",
"id": "Fk3IqzUisyYC",
"metadata": {
"id": "Fk3IqzUisyYC"
},
"source": [
"---\n",
"## 2. Utility functions\n",
"\n",
"This section defines shared helper functions used in preprocessing, feature engineering, plotting, and clustering evaluation."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "bf5b7a0a",
"metadata": {
"id": "bf5b7a0a"
},
"outputs": [],
"source": [
"# SHARED UTILITIES\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",
" \"\"\"Cluster signature heatmap using robust z-scores, capped at ±3 for readability.\"\"\"\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 for readability\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",
" \"\"\"Winsorize using MAD n-sigma rule. Falls back to p95 clip when MAD~0.\"\"\"\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",
" \"\"\"Adds months_since_last_tx[suffix] to 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\n",
"\n",
"\n",
"def add_months_since_last_tx_by_group(df, id_cols, active_col=\"active_month\", month_col=\"month\", suffix=\"\"):\n",
" col_name = f\"months_since_last_tx{suffix}\"\n",
" reference_date = df[month_col].max()\n",
"\n",
" last_active = (\n",
" df[df[active_col] == 1]\n",
" .groupby(id_cols)[month_col]\n",
" .max()\n",
" .reset_index(name=\"last_active_month\")\n",
" )\n",
"\n",
" last_active[col_name] = (\n",
" (reference_date.to_period(\"M\") - last_active[\"last_active_month\"].dt.to_period(\"M\"))\n",
" .apply(lambda x: x.n)\n",
" )\n",
"\n",
" return last_active[[*id_cols, col_name]]"
]
},
{
"cell_type": "markdown",
"id": "312153e6",
"metadata": {
"id": "312153e6"
},
"source": [
"---\n",
"## 3. Data loading\n",
"\n",
"We load four main data sources:\n",
"- repaired AUM data,\n",
"- daily transaction flows,\n",
"- NAV data for fund returns,\n",
"- interest-rate data for macro-financial enrichment."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "NMM7B-TPs6GJ",
"metadata": {
"id": "NMM7B-TPs6GJ"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(2574461, 24) (623914, 5) (2826, 2) (4880297, 18)\n"
]
}
],
"source": [
"PATH_FLOWS = \"s3://projet-bdc-data/carmignac/Flows ENSAE V2 -20251105.csv\"\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\"\n",
"PATH_AUM = \"s3://projet-bdc-carmignac-g3/paco/AUM_repaired.csv\"\n",
"\n",
"df_flows = pd.read_csv(PATH_FLOWS, sep=\";\")\n",
"df_nav = pd.read_csv(PATH_NAV, sep=\";\")\n",
"df_rates = pd.read_csv(PATH_RATES, sep=\";\")\n",
"df_aum = pd.read_csv(PATH_AUM, low_memory=False)\n",
"\n",
"print(df_flows.shape, df_nav.shape, df_rates.shape, df_aum.shape)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "011958df",
"metadata": {
"id": "011958df",
"outputId": "d3c8094a-9386-4c4a-a8dc-596e456229da"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"flows: (2514419, 25)\n",
"aum: (4824814, 19)\n",
"nav: (623914, 6)\n"
]
}
],
"source": [
"# 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",
"# Remove technical accounts (not investable)\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": "markdown",
"id": "acd89acb-a9c1-4488-a47e-db4ca76b9214",
"metadata": {
"id": "acd89acb-a9c1-4488-a47e-db4ca76b9214"
},
"source": [
"## Fund Family Study - Fund ISIN and Name"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "f5c6782a-d1bb-478a-b8d0-9343e1071722",
"metadata": {
"id": "f5c6782a-d1bb-478a-b8d0-9343e1071722",
"outputId": "44b13513-2cc4-452d-ebad-b45d60e05631"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Unique funds in AUM: 69\n",
"Unique ISINs in AUM: 387\n",
"Missing fund names in AUM: 0\n"
]
}
],
"source": [
"print(\"Unique funds in AUM:\", df_aum[FUND_COL].nunique())\n",
"print(\"Unique ISINs in AUM:\", df_aum[ISIN_COL].nunique())\n",
"print(\"Missing fund names in AUM:\", df_aum[FUND_COL].isna().sum())"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "6f12be2c-e33e-4af6-b185-1b0a2794b9f5",
"metadata": {
"id": "6f12be2c-e33e-4af6-b185-1b0a2794b9f5",
"outputId": "47220331-90d5-4b6a-ce41-24d212cfcc65",
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Nombre de couples uniques fund/isin : 387\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Product - Isin</th>\n",
" <th>Product - Fund</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FR0011269166</td>\n",
" <td>Carmignac Absolute Return Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FR0011269158</td>\n",
" <td>Carmignac Absolute Return Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>FR0011269406</td>\n",
" <td>Carmignac Absolute Return Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>FR0010149179</td>\n",
" <td>Carmignac Absolute Return Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>FR0011269547</td>\n",
" <td>Carmignac Absolute Return Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>FR001400JG56</td>\n",
" <td>Carmignac Absolute Return Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>IE00049IEN86</td>\n",
" <td>Carmignac Alts ICAV Carmignac Credit Opportuni...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>IE000L20NS05</td>\n",
" <td>Carmignac Alts ICAV Carmignac Credit Opportuni...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>IE000RU6SF09</td>\n",
" <td>Carmignac Alts ICAV European Long Short</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>FR0013467024</td>\n",
" <td>Carmignac China New Economy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>FR001400R3Z5</td>\n",
" <td>Carmignac China New Economy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>FR0014002E46</td>\n",
" <td>Carmignac China New Economy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>FR0011269331</td>\n",
" <td>Carmignac Court Terme</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>FR0010149161</td>\n",
" <td>Carmignac Court Terme</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>FR0011269323</td>\n",
" <td>Carmignac Court Terme</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>FR0000999999</td>\n",
" <td>Carmignac Court Terme</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>FR0013516028</td>\n",
" <td>Carmignac Credit 2025</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>FR0013516002</td>\n",
" <td>Carmignac Credit 2025</td>\n",
" </tr>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>FR0013516010</td>\n",
" <td>Carmignac Credit 2025</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>FR0013515970</td>\n",
" <td>Carmignac Credit 2025</td>\n",
" </tr>\n",
" <tr>\n",
" <th>20</th>\n",
" <td>FR0013515996</td>\n",
" <td>Carmignac Credit 2025</td>\n",
" </tr>\n",
" <tr>\n",
" <th>21</th>\n",
" <td>FR0013516036</td>\n",
" <td>Carmignac Credit 2025</td>\n",
" </tr>\n",
" <tr>\n",
" <th>22</th>\n",
" <td>FR0014008231</td>\n",
" <td>Carmignac Credit 2027</td>\n",
" </tr>\n",
" <tr>\n",
" <th>23</th>\n",
" <td>FR0014008223</td>\n",
" <td>Carmignac Credit 2027</td>\n",
" </tr>\n",
" <tr>\n",
" <th>24</th>\n",
" <td>FR00140081Z8</td>\n",
" <td>Carmignac Credit 2027</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25</th>\n",
" <td>FR0014008207</td>\n",
" <td>Carmignac Credit 2027</td>\n",
" </tr>\n",
" <tr>\n",
" <th>26</th>\n",
" <td>FR0014008215</td>\n",
" <td>Carmignac Credit 2027</td>\n",
" </tr>\n",
" <tr>\n",
" <th>27</th>\n",
" <td>FR00140081Y1</td>\n",
" <td>Carmignac Credit 2027</td>\n",
" </tr>\n",
" <tr>\n",
" <th>28</th>\n",
" <td>FR001400M1O8</td>\n",
" <td>Carmignac Credit 2029</td>\n",
" </tr>\n",
" <tr>\n",
" <th>29</th>\n",
" <td>FR001400M1Q3</td>\n",
" <td>Carmignac Credit 2029</td>\n",
" </tr>\n",
" <tr>\n",
" <th>30</th>\n",
" <td>FR001400KAY8</td>\n",
" <td>Carmignac Credit 2029</td>\n",
" </tr>\n",
" <tr>\n",
" <th>31</th>\n",
" <td>FR001400KAX0</td>\n",
" <td>Carmignac Credit 2029</td>\n",
" </tr>\n",
" <tr>\n",
" <th>32</th>\n",
" <td>FR001400M1P5</td>\n",
" <td>Carmignac Credit 2029</td>\n",
" </tr>\n",
" <tr>\n",
" <th>33</th>\n",
" <td>FR001400KAW2</td>\n",
" <td>Carmignac Credit 2029</td>\n",
" </tr>\n",
" <tr>\n",
" <th>34</th>\n",
" <td>FR001400KAV4</td>\n",
" <td>Carmignac Credit 2029</td>\n",
" </tr>\n",
" <tr>\n",
" <th>35</th>\n",
" <td>FR001400M1N0</td>\n",
" <td>Carmignac Credit 2029</td>\n",
" </tr>\n",
" <tr>\n",
" <th>36</th>\n",
" <td>FR001400U4X3</td>\n",
" <td>Carmignac Credit 2031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>37</th>\n",
" <td>FR001400U4Y1</td>\n",
" <td>Carmignac Credit 2031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>38</th>\n",
" <td>FR001400U4Z8</td>\n",
" <td>Carmignac Credit 2031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>39</th>\n",
" <td>FR001400U4V7</td>\n",
" <td>Carmignac Credit 2031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>40</th>\n",
" <td>FR001400U4T1</td>\n",
" <td>Carmignac Credit 2031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>41</th>\n",
" <td>FR001400U4S3</td>\n",
" <td>Carmignac Credit 2031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>42</th>\n",
" <td>FR001400U4W5</td>\n",
" <td>Carmignac Credit 2031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>43</th>\n",
" <td>FR001400U4U9</td>\n",
" <td>Carmignac Credit 2031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>44</th>\n",
" <td>FR001400XCT7</td>\n",
" <td>Carmignac Credit 2031</td>\n",
" </tr>\n",
" <tr>\n",
" <th>45</th>\n",
" <td>FR0010956607</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>46</th>\n",
" <td>FR0011269372</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>47</th>\n",
" <td>FR0011269380</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>48</th>\n",
" <td>FR0011147446</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>49</th>\n",
" <td>FR0010149302</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>50</th>\n",
" <td>FR0011269349</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>51</th>\n",
" <td>FR0011269364</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>52</th>\n",
" <td>FR001400XC60</td>\n",
" <td>Carmignac Epargne Actions Monde ISR</td>\n",
" </tr>\n",
" <tr>\n",
" <th>53</th>\n",
" <td>FR0010149112</td>\n",
" <td>Carmignac Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>54</th>\n",
" <td>FR0014000AL1</td>\n",
" <td>Carmignac Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>55</th>\n",
" <td>FR0010149278</td>\n",
" <td>Carmignac Euro-Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>56</th>\n",
" <td>FR00140051L1</td>\n",
" <td>Carmignac Global Active</td>\n",
" </tr>\n",
" <tr>\n",
" <th>57</th>\n",
" <td>FR0010149096</td>\n",
" <td>Carmignac Innovation</td>\n",
" </tr>\n",
" <tr>\n",
" <th>58</th>\n",
" <td>FR0011269182</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>59</th>\n",
" <td>FR0011269554</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>60</th>\n",
" <td>FR0011269190</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>61</th>\n",
" <td>FR0010312660</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>62</th>\n",
" <td>FR0010956615</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>63</th>\n",
" <td>FR0011269570</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>64</th>\n",
" <td>FR0010148981</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>65</th>\n",
" <td>FR001400KIF0</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>66</th>\n",
" <td>FR001400U777</td>\n",
" <td>Carmignac Investissement Latitude</td>\n",
" </tr>\n",
" <tr>\n",
" <th>67</th>\n",
" <td>FR0010147603</td>\n",
" <td>Carmignac Investissement Latitude</td>\n",
" </tr>\n",
" <tr>\n",
" <th>68</th>\n",
" <td>FR0013527827</td>\n",
" <td>Carmignac Investissement Latitude</td>\n",
" </tr>\n",
" <tr>\n",
" <th>69</th>\n",
" <td>FR0010149203</td>\n",
" <td>Carmignac Multi Expertise</td>\n",
" </tr>\n",
" <tr>\n",
" <th>70</th>\n",
" <td>FR0010956649</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>71</th>\n",
" <td>FR0011269588</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>72</th>\n",
" <td>FR0010135103</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>73</th>\n",
" <td>FR0011269067</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>74</th>\n",
" <td>FR0011269596</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>75</th>\n",
" <td>FR0010306142</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>76</th>\n",
" <td>FR0011443860</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>77</th>\n",
" <td>FR001400TXI4</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>78</th>\n",
" <td>FR0011443852</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>79</th>\n",
" <td>FR0011269075</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>80</th>\n",
" <td>LU2923680388</td>\n",
" <td>Carmignac Portfolio Absolute Return Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>81</th>\n",
" <td>LU1299301017</td>\n",
" <td>Carmignac Portfolio Active Risk Allocation</td>\n",
" </tr>\n",
" <tr>\n",
" <th>82</th>\n",
" <td>LU0807689400</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>83</th>\n",
" <td>LU2427320572</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>84</th>\n",
" <td>LU2427320499</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>85</th>\n",
" <td>LU0992630086</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>86</th>\n",
" <td>LU0553407650</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>87</th>\n",
" <td>LU0992629823</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>88</th>\n",
" <td>LU1623762256</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>89</th>\n",
" <td>LU2420651155</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>90</th>\n",
" <td>LU0807689582</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>91</th>\n",
" <td>LU0992629666</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>92</th>\n",
" <td>LU0992630169</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>93</th>\n",
" <td>LU2420651239</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>94</th>\n",
" <td>LU1623762330</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>95</th>\n",
" <td>LU0992629740</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>96</th>\n",
" <td>LU0336083810</td>\n",
" <td>Carmignac Portfolio Asia Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>97</th>\n",
" <td>LU1299307485</td>\n",
" <td>Carmignac Portfolio Capital Cube</td>\n",
" </tr>\n",
" <tr>\n",
" <th>98</th>\n",
" <td>LU1122113498</td>\n",
" <td>Carmignac Portfolio Capital Cube</td>\n",
" </tr>\n",
" <tr>\n",
" <th>99</th>\n",
" <td>LU1048598525</td>\n",
" <td>Carmignac Portfolio Capital Cube</td>\n",
" </tr>\n",
" <tr>\n",
" <th>100</th>\n",
" <td>LU1299308020</td>\n",
" <td>Carmignac Portfolio Capital Cube</td>\n",
" </tr>\n",
" <tr>\n",
" <th>101</th>\n",
" <td>LU1048598442</td>\n",
" <td>Carmignac Portfolio Capital Cube</td>\n",
" </tr>\n",
" <tr>\n",
" <th>102</th>\n",
" <td>LU1122072793</td>\n",
" <td>Carmignac Portfolio China</td>\n",
" </tr>\n",
" <tr>\n",
" <th>103</th>\n",
" <td>LU1122076430</td>\n",
" <td>Carmignac Portfolio China</td>\n",
" </tr>\n",
" <tr>\n",
" <th>104</th>\n",
" <td>LU2295992320</td>\n",
" <td>Carmignac Portfolio China New Economy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>105</th>\n",
" <td>LU2295992676</td>\n",
" <td>Carmignac Portfolio China New Economy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>106</th>\n",
" <td>LU2427321117</td>\n",
" <td>Carmignac Portfolio China New Economy</td>\n",
" </tr>\n",
" <tr>\n",
" <th>107</th>\n",
" <td>LU1623762090</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>108</th>\n",
" <td>LU0553415323</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>109</th>\n",
" <td>LU0992629310</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>110</th>\n",
" <td>LU0164455502</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>111</th>\n",
" <td>LU0992629401</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>112</th>\n",
" <td>LU0992629583</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>113</th>\n",
" <td>LU0807690754</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>114</th>\n",
" <td>LU0705572823</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>115</th>\n",
" <td>LU0992629237</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>116</th>\n",
" <td>LU0807690671</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>117</th>\n",
" <td>LU0992629153</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" </tr>\n",
" <tr>\n",
" <th>118</th>\n",
" <td>LU2772084310</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>119</th>\n",
" <td>LU1623762843</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>120</th>\n",
" <td>LU1623762926</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>121</th>\n",
" <td>LU2475941915</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>122</th>\n",
" <td>LU1932489690</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>123</th>\n",
" <td>LU2020612730</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>124</th>\n",
" <td>LU1623763064</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>125</th>\n",
" <td>LU2020612904</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>126</th>\n",
" <td>LU1623763148</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>127</th>\n",
" <td>LU2020612490</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>128</th>\n",
" <td>LU2020612813</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>129</th>\n",
" <td>LU2427321208</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" </tr>\n",
" <tr>\n",
" <th>130</th>\n",
" <td>LU2638444914</td>\n",
" <td>Carmignac Portfolio EM Debt</td>\n",
" </tr>\n",
" <tr>\n",
" <th>131</th>\n",
" <td>LU1623763221</td>\n",
" <td>Carmignac Portfolio EM Debt</td>\n",
" </tr>\n",
" <tr>\n",
" <th>132</th>\n",
" <td>LU2427320903</td>\n",
" <td>Carmignac Portfolio EM Debt</td>\n",
" </tr>\n",
" <tr>\n",
" <th>133</th>\n",
" <td>LU2277146382</td>\n",
" <td>Carmignac Portfolio EM Debt</td>\n",
" </tr>\n",
" <tr>\n",
" <th>134</th>\n",
" <td>LU2346238343</td>\n",
" <td>Carmignac Portfolio EM Debt</td>\n",
" </tr>\n",
" <tr>\n",
" <th>135</th>\n",
" <td>LU2427320812</td>\n",
" <td>Carmignac Portfolio EM Debt</td>\n",
" </tr>\n",
" <tr>\n",
" <th>136</th>\n",
" <td>LU1623763734</td>\n",
" <td>Carmignac Portfolio EM Debt</td>\n",
" </tr>\n",
" <tr>\n",
" <th>137</th>\n",
" <td>LU2420650777</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>138</th>\n",
" <td>LU0992627025</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>139</th>\n",
" <td>LU1299303575</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>140</th>\n",
" <td>LU1299303229</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>141</th>\n",
" <td>LU0992626720</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>142</th>\n",
" <td>LU0992626563</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>143</th>\n",
" <td>LU2420651072</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>144</th>\n",
" <td>LU1623762413</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>145</th>\n",
" <td>LU0992626647</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>146</th>\n",
" <td>LU0992626993</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>147</th>\n",
" <td>LU0992626480</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>148</th>\n",
" <td>LU1792391242</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>149</th>\n",
" <td>LU1299303062</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>150</th>\n",
" <td>LU0807691059</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>151</th>\n",
" <td>LU0992631563</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>152</th>\n",
" <td>LU1792392059</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>153</th>\n",
" <td>LU0992631720</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>154</th>\n",
" <td>LU0992631993</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>155</th>\n",
" <td>LU0992632025</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>156</th>\n",
" <td>LU0592699259</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>157</th>\n",
" <td>LU0807690911</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>158</th>\n",
" <td>LU0592699093</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>159</th>\n",
" <td>LU0592698954</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>160</th>\n",
" <td>LU0807690838</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>161</th>\n",
" <td>LU0992631647</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>162</th>\n",
" <td>LU0592699176</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>163</th>\n",
" <td>LU0992625755</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>164</th>\n",
" <td>LU1792392646</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>165</th>\n",
" <td>LU0992625672</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>166</th>\n",
" <td>LU1299303906</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>167</th>\n",
" <td>LU1623762686</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>168</th>\n",
" <td>LU1299304201</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>169</th>\n",
" <td>LU0992625599</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>170</th>\n",
" <td>LU1299304540</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>171</th>\n",
" <td>LU0992625326</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>172</th>\n",
" <td>LU1299304896</td>\n",
" <td>Carmignac Portfolio Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>173</th>\n",
" <td>LU2534983825</td>\n",
" <td>Carmignac Portfolio Evolution</td>\n",
" </tr>\n",
" <tr>\n",
" <th>174</th>\n",
" <td>LU2462965026</td>\n",
" <td>Carmignac Portfolio Evolution</td>\n",
" </tr>\n",
" <tr>\n",
" <th>175</th>\n",
" <td>LU1966630706</td>\n",
" <td>Carmignac Portfolio Family Governed</td>\n",
" </tr>\n",
" <tr>\n",
" <th>176</th>\n",
" <td>LU1966630961</td>\n",
" <td>Carmignac Portfolio Family Governed</td>\n",
" </tr>\n",
" <tr>\n",
" <th>177</th>\n",
" <td>LU2004385154</td>\n",
" <td>Carmignac Portfolio Family Governed</td>\n",
" </tr>\n",
" <tr>\n",
" <th>178</th>\n",
" <td>LU1873147984</td>\n",
" <td>Carmignac Portfolio Flexible Allocation 2024</td>\n",
" </tr>\n",
" <tr>\n",
" <th>179</th>\n",
" <td>LU1873148016</td>\n",
" <td>Carmignac Portfolio Flexible Allocation 2024</td>\n",
" </tr>\n",
" <tr>\n",
" <th>180</th>\n",
" <td>LU0807689749</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>181</th>\n",
" <td>LU0992631050</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>182</th>\n",
" <td>LU2490324501</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>183</th>\n",
" <td>LU0336084032</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>184</th>\n",
" <td>LU2490324410</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>185</th>\n",
" <td>LU0992631480</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>186</th>\n",
" <td>LU1299302684</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>187</th>\n",
" <td>LU2490324337</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>188</th>\n",
" <td>LU2427321547</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>189</th>\n",
" <td>LU3060210526</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>190</th>\n",
" <td>LU0807689665</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>191</th>\n",
" <td>LU0992631308</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>192</th>\n",
" <td>LU0992631217</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>193</th>\n",
" <td>LU0553411090</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>194</th>\n",
" <td>LU0807690085</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>195</th>\n",
" <td>LU0992630243</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>196</th>\n",
" <td>LU0992630599</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>197</th>\n",
" <td>LU0553413385</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>198</th>\n",
" <td>LU0992630755</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>199</th>\n",
" <td>LU0992630326</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>200</th>\n",
" <td>LU1792392307</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>201</th>\n",
" <td>LU1299302254</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>202</th>\n",
" <td>LU0992630839</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>203</th>\n",
" <td>LU0992630912</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>204</th>\n",
" <td>LU1792392216</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>205</th>\n",
" <td>LU0807689822</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>206</th>\n",
" <td>LU0807690242</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>207</th>\n",
" <td>LU2420652047</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>208</th>\n",
" <td>LU2420651825</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>209</th>\n",
" <td>LU2278973172</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>210</th>\n",
" <td>LU1299301876</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>211</th>\n",
" <td>LU0807690168</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>212</th>\n",
" <td>LU1299302098</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>213</th>\n",
" <td>LU1748451231</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>214</th>\n",
" <td>LU1623762769</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>215</th>\n",
" <td>LU0336083497</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>216</th>\n",
" <td>LU1966631266</td>\n",
" <td>Carmignac Portfolio Grandchildren</td>\n",
" </tr>\n",
" <tr>\n",
" <th>217</th>\n",
" <td>LU2004385667</td>\n",
" <td>Carmignac Portfolio Grandchildren</td>\n",
" </tr>\n",
" <tr>\n",
" <th>218</th>\n",
" <td>LU2427320739</td>\n",
" <td>Carmignac Portfolio Grandchildren</td>\n",
" </tr>\n",
" <tr>\n",
" <th>219</th>\n",
" <td>LU1966631001</td>\n",
" <td>Carmignac Portfolio Grandchildren</td>\n",
" </tr>\n",
" <tr>\n",
" <th>220</th>\n",
" <td>LU2782951763</td>\n",
" <td>Carmignac Portfolio Grandchildren</td>\n",
" </tr>\n",
" <tr>\n",
" <th>221</th>\n",
" <td>LU2420652476</td>\n",
" <td>Carmignac Portfolio Grandchildren</td>\n",
" </tr>\n",
" <tr>\n",
" <th>222</th>\n",
" <td>LU2420652393</td>\n",
" <td>Carmignac Portfolio Grandchildren</td>\n",
" </tr>\n",
" <tr>\n",
" <th>223</th>\n",
" <td>LU0553405878</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>224</th>\n",
" <td>LU2420652989</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>225</th>\n",
" <td>LU0807689079</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>226</th>\n",
" <td>LU1792392729</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>227</th>\n",
" <td>LU0807689152</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>228</th>\n",
" <td>LU2420652807</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>229</th>\n",
" <td>LU2206982626</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>230</th>\n",
" <td>LU0099161993</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>231</th>\n",
" <td>LU0992628932</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>232</th>\n",
" <td>LU2212178615</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>233</th>\n",
" <td>LU2420652633</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>234</th>\n",
" <td>LU0807688931</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>235</th>\n",
" <td>LU1623761951</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>236</th>\n",
" <td>LU2139905785</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>237</th>\n",
" <td>LU0807689236</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>238</th>\n",
" <td>LU1299301280</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>239</th>\n",
" <td>LU0992628775</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>240</th>\n",
" <td>LU0294249692</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>241</th>\n",
" <td>LU0992628858</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>242</th>\n",
" <td>LU0992629070</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>243</th>\n",
" <td>LU2154448133</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>244</th>\n",
" <td>LU2295992163</td>\n",
" <td>Carmignac Portfolio Human Xperience</td>\n",
" </tr>\n",
" <tr>\n",
" <th>245</th>\n",
" <td>LU2295992247</td>\n",
" <td>Carmignac Portfolio Human Xperience</td>\n",
" </tr>\n",
" <tr>\n",
" <th>246</th>\n",
" <td>LU2947293564</td>\n",
" <td>Carmignac Portfolio Human Xperience</td>\n",
" </tr>\n",
" <tr>\n",
" <th>247</th>\n",
" <td>LU2601234839</td>\n",
" <td>Carmignac Portfolio Human Xperience</td>\n",
" </tr>\n",
" <tr>\n",
" <th>248</th>\n",
" <td>LU3088560464</td>\n",
" <td>Carmignac Portfolio Inflation Solution</td>\n",
" </tr>\n",
" <tr>\n",
" <th>249</th>\n",
" <td>LU2715954504</td>\n",
" <td>Carmignac Portfolio Inflation Solution</td>\n",
" </tr>\n",
" <tr>\n",
" <th>250</th>\n",
" <td>LU2715954330</td>\n",
" <td>Carmignac Portfolio Inflation Solution</td>\n",
" </tr>\n",
" <tr>\n",
" <th>251</th>\n",
" <td>LU0109929157</td>\n",
" <td>Carmignac Portfolio Infotech</td>\n",
" </tr>\n",
" <tr>\n",
" <th>252</th>\n",
" <td>LU0992626134</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>253</th>\n",
" <td>LU1299311321</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>254</th>\n",
" <td>LU0992626050</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>255</th>\n",
" <td>LU0992626217</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>256</th>\n",
" <td>LU0992625839</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>257</th>\n",
" <td>LU0992625912</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>258</th>\n",
" <td>LU1299311834</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>259</th>\n",
" <td>LU3149200746</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>260</th>\n",
" <td>LU1299311677</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>261</th>\n",
" <td>LU1299311164</td>\n",
" <td>Carmignac Portfolio Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>262</th>\n",
" <td>LU1046327349</td>\n",
" <td>Carmignac Portfolio Investissement Latitude</td>\n",
" </tr>\n",
" <tr>\n",
" <th>263</th>\n",
" <td>LU1046327000</td>\n",
" <td>Carmignac Portfolio Investissement Latitude</td>\n",
" </tr>\n",
" <tr>\n",
" <th>264</th>\n",
" <td>LU1046327182</td>\n",
" <td>Carmignac Portfolio Investissement Latitude</td>\n",
" </tr>\n",
" <tr>\n",
" <th>265</th>\n",
" <td>LU1046327422</td>\n",
" <td>Carmignac Portfolio Investissement Latitude</td>\n",
" </tr>\n",
" <tr>\n",
" <th>266</th>\n",
" <td>LU1317704051</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>267</th>\n",
" <td>LU1317704135</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>268</th>\n",
" <td>LU1317704218</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>269</th>\n",
" <td>LU0992627538</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>270</th>\n",
" <td>LU0992627371</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>271</th>\n",
" <td>LU1317704309</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>272</th>\n",
" <td>LU2914157503</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>273</th>\n",
" <td>LU0992627298</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>274</th>\n",
" <td>LU0992627454</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>275</th>\n",
" <td>LU3135111204</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>276</th>\n",
" <td>LU1910837415</td>\n",
" <td>Carmignac Portfolio Long-Short Global Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>277</th>\n",
" <td>LU2278971804</td>\n",
" <td>Carmignac Portfolio Long-Short Global Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>278</th>\n",
" <td>LU1910837258</td>\n",
" <td>Carmignac Portfolio Long-Short Global Equities</td>\n",
" </tr>\n",
" <tr>\n",
" <th>279</th>\n",
" <td>LU0807690598</td>\n",
" <td>Carmignac Portfolio Market Neutral</td>\n",
" </tr>\n",
" <tr>\n",
" <th>280</th>\n",
" <td>LU0413372060</td>\n",
" <td>Carmignac Portfolio Market Neutral</td>\n",
" </tr>\n",
" <tr>\n",
" <th>281</th>\n",
" <td>LU0807690325</td>\n",
" <td>Carmignac Portfolio Market Neutral</td>\n",
" </tr>\n",
" <tr>\n",
" <th>282</th>\n",
" <td>LU0553414516</td>\n",
" <td>Carmignac Portfolio Market Neutral</td>\n",
" </tr>\n",
" <tr>\n",
" <th>283</th>\n",
" <td>LU2585800795</td>\n",
" <td>Carmignac Portfolio Merger Arbitrage</td>\n",
" </tr>\n",
" <tr>\n",
" <th>284</th>\n",
" <td>LU2585801173</td>\n",
" <td>Carmignac Portfolio Merger Arbitrage Plus</td>\n",
" </tr>\n",
" <tr>\n",
" <th>285</th>\n",
" <td>LU2585801256</td>\n",
" <td>Carmignac Portfolio Merger Arbitrage Plus</td>\n",
" </tr>\n",
" <tr>\n",
" <th>286</th>\n",
" <td>LU3016365556</td>\n",
" <td>Carmignac Portfolio Merger Arbitrage Plus</td>\n",
" </tr>\n",
" <tr>\n",
" <th>287</th>\n",
" <td>LU2585801330</td>\n",
" <td>Carmignac Portfolio Merger Arbitrage Plus</td>\n",
" </tr>\n",
" <tr>\n",
" <th>288</th>\n",
" <td>LU1163533695</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>289</th>\n",
" <td>LU0992627884</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>290</th>\n",
" <td>LU1163533851</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>291</th>\n",
" <td>LU0992627611</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>292</th>\n",
" <td>LU1792391754</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>293</th>\n",
" <td>LU1299305190</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>294</th>\n",
" <td>LU0992628692</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>295</th>\n",
" <td>LU0992627967</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>296</th>\n",
" <td>LU1792391671</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>297</th>\n",
" <td>LU0992628346</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>298</th>\n",
" <td>LU0992628429</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>299</th>\n",
" <td>LU1163533935</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>300</th>\n",
" <td>LU1299305513</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>301</th>\n",
" <td>LU1792391838</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>302</th>\n",
" <td>LU1299305786</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>303</th>\n",
" <td>LU1299305356</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>304</th>\n",
" <td>LU1163533349</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>305</th>\n",
" <td>LU1299305943</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>306</th>\n",
" <td>LU0992628189</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>307</th>\n",
" <td>LU1163533422</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>308</th>\n",
" <td>LU1163533778</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>309</th>\n",
" <td>LU0992628007</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>310</th>\n",
" <td>LU0992627702</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>311</th>\n",
" <td>LU1744630424</td>\n",
" <td>Carmignac Portfolio Patrimoine Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>312</th>\n",
" <td>LU2970252875</td>\n",
" <td>Carmignac Portfolio Patrimoine Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>313</th>\n",
" <td>LU2181689576</td>\n",
" <td>Carmignac Portfolio Patrimoine Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>314</th>\n",
" <td>LU2490324766</td>\n",
" <td>Carmignac Portfolio Patrimoine Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>315</th>\n",
" <td>LU2369619742</td>\n",
" <td>Carmignac Portfolio Patrimoine Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>316</th>\n",
" <td>LU2970252958</td>\n",
" <td>Carmignac Portfolio Patrimoine Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>317</th>\n",
" <td>LU2490324683</td>\n",
" <td>Carmignac Portfolio Patrimoine Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>318</th>\n",
" <td>LU1744628287</td>\n",
" <td>Carmignac Portfolio Patrimoine Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>319</th>\n",
" <td>LU1932476879</td>\n",
" <td>Carmignac Portfolio Patrimoine Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>320</th>\n",
" <td>LU2420653367</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>321</th>\n",
" <td>LU2490324253</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>322</th>\n",
" <td>LU0992625169</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>323</th>\n",
" <td>LU2426951195</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>324</th>\n",
" <td>LU0992625243</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>325</th>\n",
" <td>LU1299306321</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>326</th>\n",
" <td>LU1299306834</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>327</th>\n",
" <td>LU1299307055</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>328</th>\n",
" <td>LU0992624949</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>329</th>\n",
" <td>LU1299306677</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>330</th>\n",
" <td>LU1792391911</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>331</th>\n",
" <td>LU0992625086</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>332</th>\n",
" <td>LU2809794220</td>\n",
" <td>Carmignac Portfolio Tech Solutions</td>\n",
" </tr>\n",
" <tr>\n",
" <th>333</th>\n",
" <td>LU2809794493</td>\n",
" <td>Carmignac Portfolio Tech Solutions</td>\n",
" </tr>\n",
" <tr>\n",
" <th>334</th>\n",
" <td>LU2809794816</td>\n",
" <td>Carmignac Portfolio Tech Solutions</td>\n",
" </tr>\n",
" <tr>\n",
" <th>335</th>\n",
" <td>LU2812616816</td>\n",
" <td>Carmignac Portfolio Tech Solutions</td>\n",
" </tr>\n",
" <tr>\n",
" <th>336</th>\n",
" <td>LU2809794576</td>\n",
" <td>Carmignac Portfolio Tech Solutions</td>\n",
" </tr>\n",
" <tr>\n",
" <th>337</th>\n",
" <td>LU3060210443</td>\n",
" <td>Carmignac Portfolio Tech Solutions</td>\n",
" </tr>\n",
" <tr>\n",
" <th>338</th>\n",
" <td>LU2809794733</td>\n",
" <td>Carmignac Portfolio Tech Solutions</td>\n",
" </tr>\n",
" <tr>\n",
" <th>339</th>\n",
" <td>FR0010149211</td>\n",
" <td>Carmignac Profil Réactif 100</td>\n",
" </tr>\n",
" <tr>\n",
" <th>340</th>\n",
" <td>FR0010148999</td>\n",
" <td>Carmignac Profil Réactif 75</td>\n",
" </tr>\n",
" <tr>\n",
" <th>341</th>\n",
" <td>LU2799473124</td>\n",
" <td>Carmignac S.A. SICAV - PART II UCI Private Eve...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>342</th>\n",
" <td>LU2799473397</td>\n",
" <td>Carmignac S.A. SICAV - PART II UCI Private Eve...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>343</th>\n",
" <td>FR0011269109</td>\n",
" <td>Carmignac Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>344</th>\n",
" <td>FR0011269125</td>\n",
" <td>Carmignac Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>345</th>\n",
" <td>FR0011269141</td>\n",
" <td>Carmignac Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>346</th>\n",
" <td>FR0011269083</td>\n",
" <td>Carmignac Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>347</th>\n",
" <td>FR0010149120</td>\n",
" <td>Carmignac Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>348</th>\n",
" <td>FR0011269091</td>\n",
" <td>Carmignac Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>349</th>\n",
" <td>LU1720511549</td>\n",
" <td>Credit Suisse Carmignac Emerging Markets Multi...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>350</th>\n",
" <td>LU1720511895</td>\n",
" <td>Credit Suisse Carmignac Emerging Markets Multi...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>351</th>\n",
" <td>LU1720513321</td>\n",
" <td>Credit Suisse Carmignac Emerging Markets Multi...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>352</th>\n",
" <td>LU1720513677</td>\n",
" <td>Credit Suisse Carmignac Emerging Markets Multi...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>353</th>\n",
" <td>LU1720515706</td>\n",
" <td>Credit Suisse Carmignac Emerging Markets Multi...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>354</th>\n",
" <td>LU1720515615</td>\n",
" <td>Credit Suisse Carmignac Emerging Markets Multi...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>355</th>\n",
" <td>GB00BJHPHX25</td>\n",
" <td>FP Carmignac Emerging Discovery</td>\n",
" </tr>\n",
" <tr>\n",
" <th>356</th>\n",
" <td>GB00BK1W2P36</td>\n",
" <td>FP Carmignac Emerging Markets</td>\n",
" </tr>\n",
" <tr>\n",
" <th>357</th>\n",
" <td>GB00BQXJRP97</td>\n",
" <td>FP Carmignac Emerging Markets</td>\n",
" </tr>\n",
" <tr>\n",
" <th>358</th>\n",
" <td>GB00BJHPHY32</td>\n",
" <td>FP Carmignac Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>359</th>\n",
" <td>GB00BJHPX895</td>\n",
" <td>FP Carmignac Emerging Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>360</th>\n",
" <td>GB00BNDQ7P95</td>\n",
" <td>FP Carmignac European Leaders</td>\n",
" </tr>\n",
" <tr>\n",
" <th>361</th>\n",
" <td>GB00BNDQ7N71</td>\n",
" <td>FP Carmignac European Leaders</td>\n",
" </tr>\n",
" <tr>\n",
" <th>362</th>\n",
" <td>GB00BJHPXB21</td>\n",
" <td>FP Carmignac European Leaders</td>\n",
" </tr>\n",
" <tr>\n",
" <th>363</th>\n",
" <td>GB00BJHPHZ49</td>\n",
" <td>FP Carmignac European Leaders</td>\n",
" </tr>\n",
" <tr>\n",
" <th>364</th>\n",
" <td>GB00BRBXQT75</td>\n",
" <td>FP Carmignac Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>365</th>\n",
" <td>GB00BJHQ2K78</td>\n",
" <td>FP Carmignac Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>366</th>\n",
" <td>GB00BJHPZ502</td>\n",
" <td>FP Carmignac Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>367</th>\n",
" <td>GB00BJHQ2J63</td>\n",
" <td>FP Carmignac Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>368</th>\n",
" <td>GB00BJHPJ035</td>\n",
" <td>FP Carmignac Global Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>369</th>\n",
" <td>GB00BNDQ7Q03</td>\n",
" <td>FP Carmignac Global Equity Compounders</td>\n",
" </tr>\n",
" <tr>\n",
" <th>370</th>\n",
" <td>GB00BMGLBL82</td>\n",
" <td>FP Carmignac Global Equity Compounders</td>\n",
" </tr>\n",
" <tr>\n",
" <th>371</th>\n",
" <td>GB00BMGLBK75</td>\n",
" <td>FP Carmignac Global Equity Compounders</td>\n",
" </tr>\n",
" <tr>\n",
" <th>372</th>\n",
" <td>GB00BMF9P332</td>\n",
" <td>FP Carmignac Global Equity Compounders</td>\n",
" </tr>\n",
" <tr>\n",
" <th>373</th>\n",
" <td>GB00BK1W2N12</td>\n",
" <td>FP Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>374</th>\n",
" <td>LU2251305400</td>\n",
" <td>Fonditalia Carmignac Active Allocation</td>\n",
" </tr>\n",
" <tr>\n",
" <th>375</th>\n",
" <td>LU2251305319</td>\n",
" <td>Fonditalia Carmignac Active Allocation</td>\n",
" </tr>\n",
" <tr>\n",
" <th>376</th>\n",
" <td>LU2251305236</td>\n",
" <td>Fonditalia Carmignac Active Allocation</td>\n",
" </tr>\n",
" <tr>\n",
" <th>377</th>\n",
" <td>LU2250732448</td>\n",
" <td>Fonditalia Carmignac Active Allocation</td>\n",
" </tr>\n",
" <tr>\n",
" <th>378</th>\n",
" <td>LU2250732281</td>\n",
" <td>Fonditalia Carmignac Active Allocation</td>\n",
" </tr>\n",
" <tr>\n",
" <th>379</th>\n",
" <td>LU2721495427</td>\n",
" <td>LUX IM - Carmignac Emerging Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>380</th>\n",
" <td>LU2721494966</td>\n",
" <td>LUX IM - Carmignac Emerging Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>381</th>\n",
" <td>LU2721495005</td>\n",
" <td>LUX IM - Carmignac Emerging Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>382</th>\n",
" <td>LU2721495260</td>\n",
" <td>LUX IM - Carmignac Emerging Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>383</th>\n",
" <td>LU3124376941</td>\n",
" <td>LUX IM - Carmignac Emerging Flexible Bond</td>\n",
" </tr>\n",
" <tr>\n",
" <th>384</th>\n",
" <td>MAPFRECG0001</td>\n",
" <td>Mapfre Carmignac F.P.</td>\n",
" </tr>\n",
" <tr>\n",
" <th>385</th>\n",
" <td>LU2544562502</td>\n",
" <td>Solys - Carmignac Equity Selection</td>\n",
" </tr>\n",
" <tr>\n",
" <th>386</th>\n",
" <td>FR0011365873</td>\n",
" <td>UFF Grande Europe 0-100</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Product - Isin Product - Fund\n",
"0 FR0011269166 Carmignac Absolute Return Europe\n",
"1 FR0011269158 Carmignac Absolute Return Europe\n",
"2 FR0011269406 Carmignac Absolute Return Europe\n",
"3 FR0010149179 Carmignac Absolute Return Europe\n",
"4 FR0011269547 Carmignac Absolute Return Europe\n",
"5 FR001400JG56 Carmignac Absolute Return Europe\n",
"6 IE00049IEN86 Carmignac Alts ICAV Carmignac Credit Opportuni...\n",
"7 IE000L20NS05 Carmignac Alts ICAV Carmignac Credit Opportuni...\n",
"8 IE000RU6SF09 Carmignac Alts ICAV European Long Short\n",
"9 FR0013467024 Carmignac China New Economy\n",
"10 FR001400R3Z5 Carmignac China New Economy\n",
"11 FR0014002E46 Carmignac China New Economy\n",
"12 FR0011269331 Carmignac Court Terme\n",
"13 FR0010149161 Carmignac Court Terme\n",
"14 FR0011269323 Carmignac Court Terme\n",
"15 FR0000999999 Carmignac Court Terme\n",
"16 FR0013516028 Carmignac Credit 2025\n",
"17 FR0013516002 Carmignac Credit 2025\n",
"18 FR0013516010 Carmignac Credit 2025\n",
"19 FR0013515970 Carmignac Credit 2025\n",
"20 FR0013515996 Carmignac Credit 2025\n",
"21 FR0013516036 Carmignac Credit 2025\n",
"22 FR0014008231 Carmignac Credit 2027\n",
"23 FR0014008223 Carmignac Credit 2027\n",
"24 FR00140081Z8 Carmignac Credit 2027\n",
"25 FR0014008207 Carmignac Credit 2027\n",
"26 FR0014008215 Carmignac Credit 2027\n",
"27 FR00140081Y1 Carmignac Credit 2027\n",
"28 FR001400M1O8 Carmignac Credit 2029\n",
"29 FR001400M1Q3 Carmignac Credit 2029\n",
"30 FR001400KAY8 Carmignac Credit 2029\n",
"31 FR001400KAX0 Carmignac Credit 2029\n",
"32 FR001400M1P5 Carmignac Credit 2029\n",
"33 FR001400KAW2 Carmignac Credit 2029\n",
"34 FR001400KAV4 Carmignac Credit 2029\n",
"35 FR001400M1N0 Carmignac Credit 2029\n",
"36 FR001400U4X3 Carmignac Credit 2031\n",
"37 FR001400U4Y1 Carmignac Credit 2031\n",
"38 FR001400U4Z8 Carmignac Credit 2031\n",
"39 FR001400U4V7 Carmignac Credit 2031\n",
"40 FR001400U4T1 Carmignac Credit 2031\n",
"41 FR001400U4S3 Carmignac Credit 2031\n",
"42 FR001400U4W5 Carmignac Credit 2031\n",
"43 FR001400U4U9 Carmignac Credit 2031\n",
"44 FR001400XCT7 Carmignac Credit 2031\n",
"45 FR0010956607 Carmignac Emergents\n",
"46 FR0011269372 Carmignac Emergents\n",
"47 FR0011269380 Carmignac Emergents\n",
"48 FR0011147446 Carmignac Emergents\n",
"49 FR0010149302 Carmignac Emergents\n",
"50 FR0011269349 Carmignac Emergents\n",
"51 FR0011269364 Carmignac Emergents\n",
"52 FR001400XC60 Carmignac Epargne Actions Monde ISR\n",
"53 FR0010149112 Carmignac Euro-Entrepreneurs\n",
"54 FR0014000AL1 Carmignac Euro-Entrepreneurs\n",
"55 FR0010149278 Carmignac Euro-Investissement\n",
"56 FR00140051L1 Carmignac Global Active\n",
"57 FR0010149096 Carmignac Innovation\n",
"58 FR0011269182 Carmignac Investissement\n",
"59 FR0011269554 Carmignac Investissement\n",
"60 FR0011269190 Carmignac Investissement\n",
"61 FR0010312660 Carmignac Investissement\n",
"62 FR0010956615 Carmignac Investissement\n",
"63 FR0011269570 Carmignac Investissement\n",
"64 FR0010148981 Carmignac Investissement\n",
"65 FR001400KIF0 Carmignac Investissement\n",
"66 FR001400U777 Carmignac Investissement Latitude\n",
"67 FR0010147603 Carmignac Investissement Latitude\n",
"68 FR0013527827 Carmignac Investissement Latitude\n",
"69 FR0010149203 Carmignac Multi Expertise\n",
"70 FR0010956649 Carmignac Patrimoine\n",
"71 FR0011269588 Carmignac Patrimoine\n",
"72 FR0010135103 Carmignac Patrimoine\n",
"73 FR0011269067 Carmignac Patrimoine\n",
"74 FR0011269596 Carmignac Patrimoine\n",
"75 FR0010306142 Carmignac Patrimoine\n",
"76 FR0011443860 Carmignac Patrimoine\n",
"77 FR001400TXI4 Carmignac Patrimoine\n",
"78 FR0011443852 Carmignac Patrimoine\n",
"79 FR0011269075 Carmignac Patrimoine\n",
"80 LU2923680388 Carmignac Portfolio Absolute Return Europe\n",
"81 LU1299301017 Carmignac Portfolio Active Risk Allocation\n",
"82 LU0807689400 Carmignac Portfolio Asia Discovery\n",
"83 LU2427320572 Carmignac Portfolio Asia Discovery\n",
"84 LU2427320499 Carmignac Portfolio Asia Discovery\n",
"85 LU0992630086 Carmignac Portfolio Asia Discovery\n",
"86 LU0553407650 Carmignac Portfolio Asia Discovery\n",
"87 LU0992629823 Carmignac Portfolio Asia Discovery\n",
"88 LU1623762256 Carmignac Portfolio Asia Discovery\n",
"89 LU2420651155 Carmignac Portfolio Asia Discovery\n",
"90 LU0807689582 Carmignac Portfolio Asia Discovery\n",
"91 LU0992629666 Carmignac Portfolio Asia Discovery\n",
"92 LU0992630169 Carmignac Portfolio Asia Discovery\n",
"93 LU2420651239 Carmignac Portfolio Asia Discovery\n",
"94 LU1623762330 Carmignac Portfolio Asia Discovery\n",
"95 LU0992629740 Carmignac Portfolio Asia Discovery\n",
"96 LU0336083810 Carmignac Portfolio Asia Discovery\n",
"97 LU1299307485 Carmignac Portfolio Capital Cube\n",
"98 LU1122113498 Carmignac Portfolio Capital Cube\n",
"99 LU1048598525 Carmignac Portfolio Capital Cube\n",
"100 LU1299308020 Carmignac Portfolio Capital Cube\n",
"101 LU1048598442 Carmignac Portfolio Capital Cube\n",
"102 LU1122072793 Carmignac Portfolio China\n",
"103 LU1122076430 Carmignac Portfolio China\n",
"104 LU2295992320 Carmignac Portfolio China New Economy\n",
"105 LU2295992676 Carmignac Portfolio China New Economy\n",
"106 LU2427321117 Carmignac Portfolio China New Economy\n",
"107 LU1623762090 Carmignac Portfolio Climate Transition\n",
"108 LU0553415323 Carmignac Portfolio Climate Transition\n",
"109 LU0992629310 Carmignac Portfolio Climate Transition\n",
"110 LU0164455502 Carmignac Portfolio Climate Transition\n",
"111 LU0992629401 Carmignac Portfolio Climate Transition\n",
"112 LU0992629583 Carmignac Portfolio Climate Transition\n",
"113 LU0807690754 Carmignac Portfolio Climate Transition\n",
"114 LU0705572823 Carmignac Portfolio Climate Transition\n",
"115 LU0992629237 Carmignac Portfolio Climate Transition\n",
"116 LU0807690671 Carmignac Portfolio Climate Transition\n",
"117 LU0992629153 Carmignac Portfolio Climate Transition\n",
"118 LU2772084310 Carmignac Portfolio Credit\n",
"119 LU1623762843 Carmignac Portfolio Credit\n",
"120 LU1623762926 Carmignac Portfolio Credit\n",
"121 LU2475941915 Carmignac Portfolio Credit\n",
"122 LU1932489690 Carmignac Portfolio Credit\n",
"123 LU2020612730 Carmignac Portfolio Credit\n",
"124 LU1623763064 Carmignac Portfolio Credit\n",
"125 LU2020612904 Carmignac Portfolio Credit\n",
"126 LU1623763148 Carmignac Portfolio Credit\n",
"127 LU2020612490 Carmignac Portfolio Credit\n",
"128 LU2020612813 Carmignac Portfolio Credit\n",
"129 LU2427321208 Carmignac Portfolio Credit\n",
"130 LU2638444914 Carmignac Portfolio EM Debt\n",
"131 LU1623763221 Carmignac Portfolio EM Debt\n",
"132 LU2427320903 Carmignac Portfolio EM Debt\n",
"133 LU2277146382 Carmignac Portfolio EM Debt\n",
"134 LU2346238343 Carmignac Portfolio EM Debt\n",
"135 LU2427320812 Carmignac Portfolio EM Debt\n",
"136 LU1623763734 Carmignac Portfolio EM Debt\n",
"137 LU2420650777 Carmignac Portfolio Emergents\n",
"138 LU0992627025 Carmignac Portfolio Emergents\n",
"139 LU1299303575 Carmignac Portfolio Emergents\n",
"140 LU1299303229 Carmignac Portfolio Emergents\n",
"141 LU0992626720 Carmignac Portfolio Emergents\n",
"142 LU0992626563 Carmignac Portfolio Emergents\n",
"143 LU2420651072 Carmignac Portfolio Emergents\n",
"144 LU1623762413 Carmignac Portfolio Emergents\n",
"145 LU0992626647 Carmignac Portfolio Emergents\n",
"146 LU0992626993 Carmignac Portfolio Emergents\n",
"147 LU0992626480 Carmignac Portfolio Emergents\n",
"148 LU1792391242 Carmignac Portfolio Emergents\n",
"149 LU1299303062 Carmignac Portfolio Emergents\n",
"150 LU0807691059 Carmignac Portfolio Emerging Patrimoine\n",
"151 LU0992631563 Carmignac Portfolio Emerging Patrimoine\n",
"152 LU1792392059 Carmignac Portfolio Emerging Patrimoine\n",
"153 LU0992631720 Carmignac Portfolio Emerging Patrimoine\n",
"154 LU0992631993 Carmignac Portfolio Emerging Patrimoine\n",
"155 LU0992632025 Carmignac Portfolio Emerging Patrimoine\n",
"156 LU0592699259 Carmignac Portfolio Emerging Patrimoine\n",
"157 LU0807690911 Carmignac Portfolio Emerging Patrimoine\n",
"158 LU0592699093 Carmignac Portfolio Emerging Patrimoine\n",
"159 LU0592698954 Carmignac Portfolio Emerging Patrimoine\n",
"160 LU0807690838 Carmignac Portfolio Emerging Patrimoine\n",
"161 LU0992631647 Carmignac Portfolio Emerging Patrimoine\n",
"162 LU0592699176 Carmignac Portfolio Emerging Patrimoine\n",
"163 LU0992625755 Carmignac Portfolio Euro-Entrepreneurs\n",
"164 LU1792392646 Carmignac Portfolio Euro-Entrepreneurs\n",
"165 LU0992625672 Carmignac Portfolio Euro-Entrepreneurs\n",
"166 LU1299303906 Carmignac Portfolio Euro-Entrepreneurs\n",
"167 LU1623762686 Carmignac Portfolio Euro-Entrepreneurs\n",
"168 LU1299304201 Carmignac Portfolio Euro-Entrepreneurs\n",
"169 LU0992625599 Carmignac Portfolio Euro-Entrepreneurs\n",
"170 LU1299304540 Carmignac Portfolio Euro-Entrepreneurs\n",
"171 LU0992625326 Carmignac Portfolio Euro-Entrepreneurs\n",
"172 LU1299304896 Carmignac Portfolio Euro-Entrepreneurs\n",
"173 LU2534983825 Carmignac Portfolio Evolution\n",
"174 LU2462965026 Carmignac Portfolio Evolution\n",
"175 LU1966630706 Carmignac Portfolio Family Governed\n",
"176 LU1966630961 Carmignac Portfolio Family Governed\n",
"177 LU2004385154 Carmignac Portfolio Family Governed\n",
"178 LU1873147984 Carmignac Portfolio Flexible Allocation 2024\n",
"179 LU1873148016 Carmignac Portfolio Flexible Allocation 2024\n",
"180 LU0807689749 Carmignac Portfolio Flexible Bond\n",
"181 LU0992631050 Carmignac Portfolio Flexible Bond\n",
"182 LU2490324501 Carmignac Portfolio Flexible Bond\n",
"183 LU0336084032 Carmignac Portfolio Flexible Bond\n",
"184 LU2490324410 Carmignac Portfolio Flexible Bond\n",
"185 LU0992631480 Carmignac Portfolio Flexible Bond\n",
"186 LU1299302684 Carmignac Portfolio Flexible Bond\n",
"187 LU2490324337 Carmignac Portfolio Flexible Bond\n",
"188 LU2427321547 Carmignac Portfolio Flexible Bond\n",
"189 LU3060210526 Carmignac Portfolio Flexible Bond\n",
"190 LU0807689665 Carmignac Portfolio Flexible Bond\n",
"191 LU0992631308 Carmignac Portfolio Flexible Bond\n",
"192 LU0992631217 Carmignac Portfolio Flexible Bond\n",
"193 LU0553411090 Carmignac Portfolio Flexible Bond\n",
"194 LU0807690085 Carmignac Portfolio Global Bond\n",
"195 LU0992630243 Carmignac Portfolio Global Bond\n",
"196 LU0992630599 Carmignac Portfolio Global Bond\n",
"197 LU0553413385 Carmignac Portfolio Global Bond\n",
"198 LU0992630755 Carmignac Portfolio Global Bond\n",
"199 LU0992630326 Carmignac Portfolio Global Bond\n",
"200 LU1792392307 Carmignac Portfolio Global Bond\n",
"201 LU1299302254 Carmignac Portfolio Global Bond\n",
"202 LU0992630839 Carmignac Portfolio Global Bond\n",
"203 LU0992630912 Carmignac Portfolio Global Bond\n",
"204 LU1792392216 Carmignac Portfolio Global Bond\n",
"205 LU0807689822 Carmignac Portfolio Global Bond\n",
"206 LU0807690242 Carmignac Portfolio Global Bond\n",
"207 LU2420652047 Carmignac Portfolio Global Bond\n",
"208 LU2420651825 Carmignac Portfolio Global Bond\n",
"209 LU2278973172 Carmignac Portfolio Global Bond\n",
"210 LU1299301876 Carmignac Portfolio Global Bond\n",
"211 LU0807690168 Carmignac Portfolio Global Bond\n",
"212 LU1299302098 Carmignac Portfolio Global Bond\n",
"213 LU1748451231 Carmignac Portfolio Global Bond\n",
"214 LU1623762769 Carmignac Portfolio Global Bond\n",
"215 LU0336083497 Carmignac Portfolio Global Bond\n",
"216 LU1966631266 Carmignac Portfolio Grandchildren\n",
"217 LU2004385667 Carmignac Portfolio Grandchildren\n",
"218 LU2427320739 Carmignac Portfolio Grandchildren\n",
"219 LU1966631001 Carmignac Portfolio Grandchildren\n",
"220 LU2782951763 Carmignac Portfolio Grandchildren\n",
"221 LU2420652476 Carmignac Portfolio Grandchildren\n",
"222 LU2420652393 Carmignac Portfolio Grandchildren\n",
"223 LU0553405878 Carmignac Portfolio Grande Europe\n",
"224 LU2420652989 Carmignac Portfolio Grande Europe\n",
"225 LU0807689079 Carmignac Portfolio Grande Europe\n",
"226 LU1792392729 Carmignac Portfolio Grande Europe\n",
"227 LU0807689152 Carmignac Portfolio Grande Europe\n",
"228 LU2420652807 Carmignac Portfolio Grande Europe\n",
"229 LU2206982626 Carmignac Portfolio Grande Europe\n",
"230 LU0099161993 Carmignac Portfolio Grande Europe\n",
"231 LU0992628932 Carmignac Portfolio Grande Europe\n",
"232 LU2212178615 Carmignac Portfolio Grande Europe\n",
"233 LU2420652633 Carmignac Portfolio Grande Europe\n",
"234 LU0807688931 Carmignac Portfolio Grande Europe\n",
"235 LU1623761951 Carmignac Portfolio Grande Europe\n",
"236 LU2139905785 Carmignac Portfolio Grande Europe\n",
"237 LU0807689236 Carmignac Portfolio Grande Europe\n",
"238 LU1299301280 Carmignac Portfolio Grande Europe\n",
"239 LU0992628775 Carmignac Portfolio Grande Europe\n",
"240 LU0294249692 Carmignac Portfolio Grande Europe\n",
"241 LU0992628858 Carmignac Portfolio Grande Europe\n",
"242 LU0992629070 Carmignac Portfolio Grande Europe\n",
"243 LU2154448133 Carmignac Portfolio Grande Europe\n",
"244 LU2295992163 Carmignac Portfolio Human Xperience\n",
"245 LU2295992247 Carmignac Portfolio Human Xperience\n",
"246 LU2947293564 Carmignac Portfolio Human Xperience\n",
"247 LU2601234839 Carmignac Portfolio Human Xperience\n",
"248 LU3088560464 Carmignac Portfolio Inflation Solution\n",
"249 LU2715954504 Carmignac Portfolio Inflation Solution\n",
"250 LU2715954330 Carmignac Portfolio Inflation Solution\n",
"251 LU0109929157 Carmignac Portfolio Infotech\n",
"252 LU0992626134 Carmignac Portfolio Investissement\n",
"253 LU1299311321 Carmignac Portfolio Investissement\n",
"254 LU0992626050 Carmignac Portfolio Investissement\n",
"255 LU0992626217 Carmignac Portfolio Investissement\n",
"256 LU0992625839 Carmignac Portfolio Investissement\n",
"257 LU0992625912 Carmignac Portfolio Investissement\n",
"258 LU1299311834 Carmignac Portfolio Investissement\n",
"259 LU3149200746 Carmignac Portfolio Investissement\n",
"260 LU1299311677 Carmignac Portfolio Investissement\n",
"261 LU1299311164 Carmignac Portfolio Investissement\n",
"262 LU1046327349 Carmignac Portfolio Investissement Latitude\n",
"263 LU1046327000 Carmignac Portfolio Investissement Latitude\n",
"264 LU1046327182 Carmignac Portfolio Investissement Latitude\n",
"265 LU1046327422 Carmignac Portfolio Investissement Latitude\n",
"266 LU1317704051 Carmignac Portfolio Long-Short European Equities\n",
"267 LU1317704135 Carmignac Portfolio Long-Short European Equities\n",
"268 LU1317704218 Carmignac Portfolio Long-Short European Equities\n",
"269 LU0992627538 Carmignac Portfolio Long-Short European Equities\n",
"270 LU0992627371 Carmignac Portfolio Long-Short European Equities\n",
"271 LU1317704309 Carmignac Portfolio Long-Short European Equities\n",
"272 LU2914157503 Carmignac Portfolio Long-Short European Equities\n",
"273 LU0992627298 Carmignac Portfolio Long-Short European Equities\n",
"274 LU0992627454 Carmignac Portfolio Long-Short European Equities\n",
"275 LU3135111204 Carmignac Portfolio Long-Short European Equities\n",
"276 LU1910837415 Carmignac Portfolio Long-Short Global Equities\n",
"277 LU2278971804 Carmignac Portfolio Long-Short Global Equities\n",
"278 LU1910837258 Carmignac Portfolio Long-Short Global Equities\n",
"279 LU0807690598 Carmignac Portfolio Market Neutral\n",
"280 LU0413372060 Carmignac Portfolio Market Neutral\n",
"281 LU0807690325 Carmignac Portfolio Market Neutral\n",
"282 LU0553414516 Carmignac Portfolio Market Neutral\n",
"283 LU2585800795 Carmignac Portfolio Merger Arbitrage\n",
"284 LU2585801173 Carmignac Portfolio Merger Arbitrage Plus\n",
"285 LU2585801256 Carmignac Portfolio Merger Arbitrage Plus\n",
"286 LU3016365556 Carmignac Portfolio Merger Arbitrage Plus\n",
"287 LU2585801330 Carmignac Portfolio Merger Arbitrage Plus\n",
"288 LU1163533695 Carmignac Portfolio Patrimoine\n",
"289 LU0992627884 Carmignac Portfolio Patrimoine\n",
"290 LU1163533851 Carmignac Portfolio Patrimoine\n",
"291 LU0992627611 Carmignac Portfolio Patrimoine\n",
"292 LU1792391754 Carmignac Portfolio Patrimoine\n",
"293 LU1299305190 Carmignac Portfolio Patrimoine\n",
"294 LU0992628692 Carmignac Portfolio Patrimoine\n",
"295 LU0992627967 Carmignac Portfolio Patrimoine\n",
"296 LU1792391671 Carmignac Portfolio Patrimoine\n",
"297 LU0992628346 Carmignac Portfolio Patrimoine\n",
"298 LU0992628429 Carmignac Portfolio Patrimoine\n",
"299 LU1163533935 Carmignac Portfolio Patrimoine\n",
"300 LU1299305513 Carmignac Portfolio Patrimoine\n",
"301 LU1792391838 Carmignac Portfolio Patrimoine\n",
"302 LU1299305786 Carmignac Portfolio Patrimoine\n",
"303 LU1299305356 Carmignac Portfolio Patrimoine\n",
"304 LU1163533349 Carmignac Portfolio Patrimoine\n",
"305 LU1299305943 Carmignac Portfolio Patrimoine\n",
"306 LU0992628189 Carmignac Portfolio Patrimoine\n",
"307 LU1163533422 Carmignac Portfolio Patrimoine\n",
"308 LU1163533778 Carmignac Portfolio Patrimoine\n",
"309 LU0992628007 Carmignac Portfolio Patrimoine\n",
"310 LU0992627702 Carmignac Portfolio Patrimoine\n",
"311 LU1744630424 Carmignac Portfolio Patrimoine Europe\n",
"312 LU2970252875 Carmignac Portfolio Patrimoine Europe\n",
"313 LU2181689576 Carmignac Portfolio Patrimoine Europe\n",
"314 LU2490324766 Carmignac Portfolio Patrimoine Europe\n",
"315 LU2369619742 Carmignac Portfolio Patrimoine Europe\n",
"316 LU2970252958 Carmignac Portfolio Patrimoine Europe\n",
"317 LU2490324683 Carmignac Portfolio Patrimoine Europe\n",
"318 LU1744628287 Carmignac Portfolio Patrimoine Europe\n",
"319 LU1932476879 Carmignac Portfolio Patrimoine Europe\n",
"320 LU2420653367 Carmignac Portfolio Sécurité\n",
"321 LU2490324253 Carmignac Portfolio Sécurité\n",
"322 LU0992625169 Carmignac Portfolio Sécurité\n",
"323 LU2426951195 Carmignac Portfolio Sécurité\n",
"324 LU0992625243 Carmignac Portfolio Sécurité\n",
"325 LU1299306321 Carmignac Portfolio Sécurité\n",
"326 LU1299306834 Carmignac Portfolio Sécurité\n",
"327 LU1299307055 Carmignac Portfolio Sécurité\n",
"328 LU0992624949 Carmignac Portfolio Sécurité\n",
"329 LU1299306677 Carmignac Portfolio Sécurité\n",
"330 LU1792391911 Carmignac Portfolio Sécurité\n",
"331 LU0992625086 Carmignac Portfolio Sécurité\n",
"332 LU2809794220 Carmignac Portfolio Tech Solutions\n",
"333 LU2809794493 Carmignac Portfolio Tech Solutions\n",
"334 LU2809794816 Carmignac Portfolio Tech Solutions\n",
"335 LU2812616816 Carmignac Portfolio Tech Solutions\n",
"336 LU2809794576 Carmignac Portfolio Tech Solutions\n",
"337 LU3060210443 Carmignac Portfolio Tech Solutions\n",
"338 LU2809794733 Carmignac Portfolio Tech Solutions\n",
"339 FR0010149211 Carmignac Profil Réactif 100\n",
"340 FR0010148999 Carmignac Profil Réactif 75\n",
"341 LU2799473124 Carmignac S.A. SICAV - PART II UCI Private Eve...\n",
"342 LU2799473397 Carmignac S.A. SICAV - PART II UCI Private Eve...\n",
"343 FR0011269109 Carmignac Sécurité\n",
"344 FR0011269125 Carmignac Sécurité\n",
"345 FR0011269141 Carmignac Sécurité\n",
"346 FR0011269083 Carmignac Sécurité\n",
"347 FR0010149120 Carmignac Sécurité\n",
"348 FR0011269091 Carmignac Sécurité\n",
"349 LU1720511549 Credit Suisse Carmignac Emerging Markets Multi...\n",
"350 LU1720511895 Credit Suisse Carmignac Emerging Markets Multi...\n",
"351 LU1720513321 Credit Suisse Carmignac Emerging Markets Multi...\n",
"352 LU1720513677 Credit Suisse Carmignac Emerging Markets Multi...\n",
"353 LU1720515706 Credit Suisse Carmignac Emerging Markets Multi...\n",
"354 LU1720515615 Credit Suisse Carmignac Emerging Markets Multi...\n",
"355 GB00BJHPHX25 FP Carmignac Emerging Discovery\n",
"356 GB00BK1W2P36 FP Carmignac Emerging Markets\n",
"357 GB00BQXJRP97 FP Carmignac Emerging Markets\n",
"358 GB00BJHPHY32 FP Carmignac Emerging Patrimoine\n",
"359 GB00BJHPX895 FP Carmignac Emerging Patrimoine\n",
"360 GB00BNDQ7P95 FP Carmignac European Leaders\n",
"361 GB00BNDQ7N71 FP Carmignac European Leaders\n",
"362 GB00BJHPXB21 FP Carmignac European Leaders\n",
"363 GB00BJHPHZ49 FP Carmignac European Leaders\n",
"364 GB00BRBXQT75 FP Carmignac Global Bond\n",
"365 GB00BJHQ2K78 FP Carmignac Global Bond\n",
"366 GB00BJHPZ502 FP Carmignac Global Bond\n",
"367 GB00BJHQ2J63 FP Carmignac Global Bond\n",
"368 GB00BJHPJ035 FP Carmignac Global Bond\n",
"369 GB00BNDQ7Q03 FP Carmignac Global Equity Compounders\n",
"370 GB00BMGLBL82 FP Carmignac Global Equity Compounders\n",
"371 GB00BMGLBK75 FP Carmignac Global Equity Compounders\n",
"372 GB00BMF9P332 FP Carmignac Global Equity Compounders\n",
"373 GB00BK1W2N12 FP Carmignac Patrimoine\n",
"374 LU2251305400 Fonditalia Carmignac Active Allocation\n",
"375 LU2251305319 Fonditalia Carmignac Active Allocation\n",
"376 LU2251305236 Fonditalia Carmignac Active Allocation\n",
"377 LU2250732448 Fonditalia Carmignac Active Allocation\n",
"378 LU2250732281 Fonditalia Carmignac Active Allocation\n",
"379 LU2721495427 LUX IM - Carmignac Emerging Flexible Bond\n",
"380 LU2721494966 LUX IM - Carmignac Emerging Flexible Bond\n",
"381 LU2721495005 LUX IM - Carmignac Emerging Flexible Bond\n",
"382 LU2721495260 LUX IM - Carmignac Emerging Flexible Bond\n",
"383 LU3124376941 LUX IM - Carmignac Emerging Flexible Bond\n",
"384 MAPFRECG0001 Mapfre Carmignac F.P.\n",
"385 LU2544562502 Solys - Carmignac Equity Selection\n",
"386 FR0011365873 UFF Grande Europe 0-100"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Tableau unique Fund Name + ISIN, trié par ISIN puis par nom de fonds\n",
"pd.set_option(\"display.max_rows\", None)\n",
"pd.set_option(\"display.max_columns\", None)\n",
"\n",
"fund_isin_table = (\n",
" df_aum[[\"Product - Isin\", \"Product - Fund\"]]\n",
" .dropna(subset=[\"Product - Isin\",\"Product - Fund\"])\n",
" .drop_duplicates()\n",
" .sort_values([\"Product - Fund\"])\n",
" .reset_index(drop=True)\n",
")\n",
"\n",
"print(f\"Nombre de couples uniques fund/isin : {fund_isin_table.shape[0]}\")\n",
"fund_isin_table"
]
},
{
"cell_type": "markdown",
"id": "b568bbc3-55ad-4dcb-bdb0-94e9a154575d",
"metadata": {
"id": "b568bbc3-55ad-4dcb-bdb0-94e9a154575d"
},
"source": [
"---\n",
"## 4. Fund-family construction\n",
"\n",
"A conservative family mapping is built from repaired AUM data. \n",
"Two products are assigned to the same family if their names differ only by a numeric substring.\n",
"\n",
"This aggregation is useful operationally, but may merge maturity-dated products with distinct economic profiles. Family-level results should therefore be interpreted as commercial-behavioral groupings rather than pure product-level classifications."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "70c8591f-29aa-4d2f-94bb-d3a280cbe5bb",
"metadata": {
"id": "70c8591f-29aa-4d2f-94bb-d3a280cbe5bb",
"outputId": "1f62bc14-4d88-46d3-fa80-cbc1379efc17"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Nombre de couples ISIN/Fund : 387\n",
"Nombre de funds uniques : 69\n",
"Nombre de families uniques : 65\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Product - Isin</th>\n",
" <th>Product - Fund</th>\n",
" <th>fund_family</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>FR0000999999</td>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>Carmignac Court Terme</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>FR0010135103</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>FR0010147603</td>\n",
" <td>Carmignac Investissement Latitude</td>\n",
" <td>Carmignac Investissement Latitude</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>FR0010148981</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>FR0010148999</td>\n",
" <td>Carmignac Profil Réactif 75</td>\n",
" <td>Carmignac Profil Réactif &lt;NUM&gt;</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>FR0010149096</td>\n",
" <td>Carmignac Innovation</td>\n",
" <td>Carmignac Innovation</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>FR0010149112</td>\n",
" <td>Carmignac Euro-Entrepreneurs</td>\n",
" <td>Carmignac Euro-Entrepreneurs</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>FR0010149120</td>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>Carmignac Sécurité</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>FR0010149161</td>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>Carmignac Court Terme</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>FR0010149179</td>\n",
" <td>Carmignac Absolute Return Europe</td>\n",
" <td>Carmignac Absolute Return Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>FR0010149203</td>\n",
" <td>Carmignac Multi Expertise</td>\n",
" <td>Carmignac Multi Expertise</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>FR0010149211</td>\n",
" <td>Carmignac Profil Réactif 100</td>\n",
" <td>Carmignac Profil Réactif &lt;NUM&gt;</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>FR0010149278</td>\n",
" <td>Carmignac Euro-Investissement</td>\n",
" <td>Carmignac Euro-Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>FR0010149302</td>\n",
" <td>Carmignac Emergents</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>FR0010306142</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>FR0010312660</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>FR0010956607</td>\n",
" <td>Carmignac Emergents</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>FR0010956615</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>Carmignac Investissement</td>\n",
" </tr>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>FR0010956649</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>FR0011147446</td>\n",
" <td>Carmignac Emergents</td>\n",
" <td>Carmignac Emergents</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Product - Isin Product - Fund \\\n",
"0 FR0000999999 Carmignac Court Terme \n",
"1 FR0010135103 Carmignac Patrimoine \n",
"2 FR0010147603 Carmignac Investissement Latitude \n",
"3 FR0010148981 Carmignac Investissement \n",
"4 FR0010148999 Carmignac Profil Réactif 75 \n",
"5 FR0010149096 Carmignac Innovation \n",
"6 FR0010149112 Carmignac Euro-Entrepreneurs \n",
"7 FR0010149120 Carmignac Sécurité \n",
"8 FR0010149161 Carmignac Court Terme \n",
"9 FR0010149179 Carmignac Absolute Return Europe \n",
"10 FR0010149203 Carmignac Multi Expertise \n",
"11 FR0010149211 Carmignac Profil Réactif 100 \n",
"12 FR0010149278 Carmignac Euro-Investissement \n",
"13 FR0010149302 Carmignac Emergents \n",
"14 FR0010306142 Carmignac Patrimoine \n",
"15 FR0010312660 Carmignac Investissement \n",
"16 FR0010956607 Carmignac Emergents \n",
"17 FR0010956615 Carmignac Investissement \n",
"18 FR0010956649 Carmignac Patrimoine \n",
"19 FR0011147446 Carmignac Emergents \n",
"\n",
" fund_family \n",
"0 Carmignac Court Terme \n",
"1 Carmignac Patrimoine \n",
"2 Carmignac Investissement Latitude \n",
"3 Carmignac Investissement \n",
"4 Carmignac Profil Réactif <NUM> \n",
"5 Carmignac Innovation \n",
"6 Carmignac Euro-Entrepreneurs \n",
"7 Carmignac Sécurité \n",
"8 Carmignac Court Terme \n",
"9 Carmignac Absolute Return Europe \n",
"10 Carmignac Multi Expertise \n",
"11 Carmignac Profil Réactif <NUM> \n",
"12 Carmignac Euro-Investissement \n",
"13 Carmignac Emergents \n",
"14 Carmignac Patrimoine \n",
"15 Carmignac Investissement \n",
"16 Carmignac Emergents \n",
"17 Carmignac Investissement \n",
"18 Carmignac Patrimoine \n",
"19 Carmignac Emergents "
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import re\n",
"import numpy as np\n",
"import pandas as pd\n",
"\n",
"# =========================================================\n",
"# 1) Fonction conservative de construction de famille\n",
"# - même nom => même famille\n",
"# - différence purement numérique => même famille\n",
"# - sinon famille différente\n",
"# =========================================================\n",
"\n",
"\n",
"def build_fund_family_numeric_only(fund_name):\n",
" if pd.isna(fund_name): # si le nom du fund est manquant\n",
" return np.nan # on retourne NaN\n",
"\n",
" s = str(fund_name).strip() # transforme en string + enlève espaces début/fin\n",
"\n",
" family = re.sub(r\"\\d+\", \"<NUM>\", s) # remplace tous les nombres par \"<NUM>\"\n",
" # ex: \"Credit 2027\" -> \"Credit <NUM>\"\n",
"\n",
" family = re.sub(r\"\\s+\", \" \", family).strip()\n",
" # remplace espaces multiples par 1 seul + nettoie\n",
"\n",
" return family # retourne la famille construite\n",
"\n",
"fund_family_table = (\n",
" df_aum[[ISIN_COL, FUND_COL]] # on garde seulement ISIN et nom du fund\n",
" .dropna(subset=[ISIN_COL, FUND_COL]) # enlève lignes avec valeurs manquantes\n",
" .drop_duplicates() # enlève doublons (même ISIN + fund)\n",
" .sort_values([ISIN_COL, FUND_COL]) # trie pour lisibilité\n",
" .reset_index(drop=True) # reset index propre\n",
")\n",
"\n",
"fund_family_table[\"fund_family\"] = fund_family_table[FUND_COL].apply(build_fund_family_numeric_only)\n",
"## applique la fonction à chaque nom de fund pour créer la colonne \"fund_family\"\n",
"\n",
"print(\"Nombre de couples ISIN/Fund :\", fund_family_table.shape[0])\n",
"print(\"Nombre de funds uniques :\", fund_family_table[FUND_COL].nunique())\n",
"print(\"Nombre de families uniques :\", fund_family_table[\"fund_family\"].nunique())\n",
"\n",
"fund_family_table.head(20)"
]
},
{
"cell_type": "markdown",
"id": "d34f5ecf",
"metadata": {
"id": "d34f5ecf"
},
"source": [
"---\n",
"## 5. Monthly panel construction\n",
"\n",
"We construct a monthly relational panel at the client × ISIN × month level by combining:\n",
"- monthly AUM snapshots,\n",
"- monthly aggregated flows,\n",
"- monthly fund returns,\n",
"- monthly interest-rate changes."
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "25f3dce4",
"metadata": {
"id": "25f3dce4",
"outputId": "ed7bd124-4467-407a-faaa-b71605a38afc"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"df_rel_m shape: (5184382, 20)\n"
]
}
],
"source": [
"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, FUND_COL, \"month\"])\n",
" .groupby([ID_COL, ISIN_COL, FUND_COL, \"month\"], as_index=False)\n",
" .agg(\n",
" aum_qty=(AUM_QTY_COL, \"sum\"),\n",
" aum_val=(AUM_VAL_COL, \"sum\"),\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\", suffixes=(\"\", \"_flow\"))\n",
")\n",
"\n",
"for c in [\"aum_qty\", \"aum_val\", \"net_flow_qty\", \"gross_flow_qty\", \"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",
"\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",
"\n",
"df_rel_m[\"flow_to_aum_rel\"] = np.where(\n",
" df_rel_m[\"aum_qty\"].abs() > 0,\n",
" df_rel_m[\"net_flow_qty\"] / df_rel_m[\"aum_qty\"].abs(),\n",
" np.nan\n",
")\n",
"\n",
"df_rel_m[\"turnover_rel\"] = np.where(\n",
" df_rel_m[\"aum_qty\"].abs() > 0,\n",
" df_rel_m[\"gross_flow_qty\"] / df_rel_m[\"aum_qty\"].abs(),\n",
" np.nan\n",
")\n",
"\n",
"print(\"df_rel_m shape:\", df_rel_m.shape)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "0e95eaaa-3c49-44b9-b049-fee5ecba66ef",
"metadata": {
"id": "0e95eaaa-3c49-44b9-b049-fee5ecba66ef",
"outputId": "23c47670-bfbf-455f-db68-70d5be25ab37"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Panel with NAV/rates: (5184382, 22)\n"
]
}
],
"source": [
"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)\n",
" .tail(1)\n",
")\n",
"\n",
"df_nav_m[\"ret_fund_m\"] = df_nav_m.groupby(NAV_ISIN_COL)[NAV_PRICE_COL].pct_change()\n",
"\n",
"df_nav_m = df_nav_m.rename(columns={NAV_ISIN_COL: ISIN_COL})[\n",
" [ISIN_COL, \"month\", \"ret_fund_m\"]\n",
"]\n",
"\n",
"df_rates_m = (\n",
" df_rates\n",
" .dropna(subset=[\"month\", RATE_VAL_COL])\n",
" .sort_values(RATE_DATE_COL)\n",
" .groupby(\"month\", as_index=False)\n",
" .tail(1)\n",
")\n",
"\n",
"df_rates_m[\"delta_rate_m\"] = df_rates_m[RATE_VAL_COL].diff()\n",
"df_rates_m = df_rates_m[[\"month\", \"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(df_rates_m, on=\"month\", how=\"left\")\n",
"\n",
"for c in [\"ret_fund_m\", \"delta_rate_m\"]:\n",
" df_rel_m[c] = df_rel_m[c].fillna(0)\n",
"\n",
"print(\"Panel with NAV/rates:\", df_rel_m.shape)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "f4c2a3fd-2595-445b-95f5-bd544355e23d",
"metadata": {
"id": "f4c2a3fd-2595-445b-95f5-bd544355e23d",
"outputId": "82a32568-c7b5-4a3d-8b43-401e85f4405c"
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Registrar Account - ID</th>\n",
" <th>Product - Isin</th>\n",
" <th>month</th>\n",
" <th>Product - Fund</th>\n",
" <th>aum_qty</th>\n",
" <th>aum_val</th>\n",
" <th>asset_type</th>\n",
" <th>region</th>\n",
" <th>country</th>\n",
" <th>net_flow_qty</th>\n",
" <th>gross_flow_qty</th>\n",
" <th>sub_qty</th>\n",
" <th>red_qty</th>\n",
" <th>n_tx</th>\n",
" <th>region_flow</th>\n",
" <th>country_flow</th>\n",
" <th>active_rel_month</th>\n",
" <th>holding_rel_month</th>\n",
" <th>flow_to_aum_rel</th>\n",
" <th>turnover_rel</th>\n",
" <th>ret_fund_m</th>\n",
" <th>delta_rate_m</th>\n",
" <th>fund_family</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>5184372</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2020-11-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>-0.004</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5184373</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2020-12-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.004</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5184374</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2021-01-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>-0.007</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5184375</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2021-02-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.001</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5184376</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2021-03-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>-0.003</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5184377</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2021-04-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5184378</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2021-05-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5184379</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2021-06-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.001</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5184380</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2021-07-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>-0.001</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5184381</th>\n",
" <td>88928</td>\n",
" <td>LU0099161993</td>\n",
" <td>2021-08-01</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>Equity</td>\n",
" <td>Luxembourg</td>\n",
" <td>Luxembourg</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>-0.003</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Registrar Account - ID Product - Isin month \\\n",
"5184372 88928 LU0099161993 2020-11-01 \n",
"5184373 88928 LU0099161993 2020-12-01 \n",
"5184374 88928 LU0099161993 2021-01-01 \n",
"5184375 88928 LU0099161993 2021-02-01 \n",
"5184376 88928 LU0099161993 2021-03-01 \n",
"5184377 88928 LU0099161993 2021-04-01 \n",
"5184378 88928 LU0099161993 2021-05-01 \n",
"5184379 88928 LU0099161993 2021-06-01 \n",
"5184380 88928 LU0099161993 2021-07-01 \n",
"5184381 88928 LU0099161993 2021-08-01 \n",
"\n",
" Product - Fund aum_qty aum_val asset_type \\\n",
"5184372 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"5184373 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"5184374 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"5184375 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"5184376 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"5184377 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"5184378 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"5184379 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"5184380 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"5184381 Carmignac Portfolio Grande Europe 0.0 0.0 Equity \n",
"\n",
" region country net_flow_qty gross_flow_qty sub_qty \\\n",
"5184372 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"5184373 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"5184374 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"5184375 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"5184376 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"5184377 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"5184378 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"5184379 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"5184380 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"5184381 Luxembourg Luxembourg 0.0 0.0 0.0 \n",
"\n",
" red_qty n_tx region_flow country_flow active_rel_month \\\n",
"5184372 0.0 0.0 NaN NaN 0 \n",
"5184373 0.0 0.0 NaN NaN 0 \n",
"5184374 0.0 0.0 NaN NaN 0 \n",
"5184375 0.0 0.0 NaN NaN 0 \n",
"5184376 0.0 0.0 NaN NaN 0 \n",
"5184377 0.0 0.0 NaN NaN 0 \n",
"5184378 0.0 0.0 NaN NaN 0 \n",
"5184379 0.0 0.0 NaN NaN 0 \n",
"5184380 0.0 0.0 NaN NaN 0 \n",
"5184381 0.0 0.0 NaN NaN 0 \n",
"\n",
" holding_rel_month flow_to_aum_rel turnover_rel ret_fund_m \\\n",
"5184372 0 NaN NaN 0.0 \n",
"5184373 0 NaN NaN 0.0 \n",
"5184374 0 NaN NaN 0.0 \n",
"5184375 0 NaN NaN 0.0 \n",
"5184376 0 NaN NaN 0.0 \n",
"5184377 0 NaN NaN 0.0 \n",
"5184378 0 NaN NaN 0.0 \n",
"5184379 0 NaN NaN 0.0 \n",
"5184380 0 NaN NaN 0.0 \n",
"5184381 0 NaN NaN 0.0 \n",
"\n",
" delta_rate_m fund_family \n",
"5184372 -0.004 Carmignac Portfolio Grande Europe \n",
"5184373 0.004 Carmignac Portfolio Grande Europe \n",
"5184374 -0.007 Carmignac Portfolio Grande Europe \n",
"5184375 0.001 Carmignac Portfolio Grande Europe \n",
"5184376 -0.003 Carmignac Portfolio Grande Europe \n",
"5184377 0.000 Carmignac Portfolio Grande Europe \n",
"5184378 0.000 Carmignac Portfolio Grande Europe \n",
"5184379 0.001 Carmignac Portfolio Grande Europe \n",
"5184380 -0.001 Carmignac Portfolio Grande Europe \n",
"5184381 -0.003 Carmignac Portfolio Grande Europe "
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Merge families\n",
"\n",
"df_rel_m = df_rel_m.merge(\n",
" fund_family_table[[ISIN_COL, FUND_COL, \"fund_family\"]],\n",
" on=[ISIN_COL, FUND_COL],\n",
" how=\"left\")\n",
"df_rel_m.tail(10)"
]
},
{
"cell_type": "markdown",
"id": "RV-iU2QTtX-A",
"metadata": {
"id": "RV-iU2QTtX-A"
},
"source": [
"---\n",
"## 6. Aggregation to the client × fund-family × month level\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "f4fb4a9f-b354-42d0-8699-bf6fc1e26bb9",
"metadata": {
"id": "f4fb4a9f-b354-42d0-8699-bf6fc1e26bb9",
"outputId": "871d89b5-4b34-4573-e3fc-59b5b03cb145"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"df_family_month shape: (3805010, 23)\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Registrar Account - ID</th>\n",
" <th>fund_family</th>\n",
" <th>month</th>\n",
" <th>aum_qty</th>\n",
" <th>aum_val</th>\n",
" <th>net_flow_qty</th>\n",
" <th>gross_flow_qty</th>\n",
" <th>sub_qty</th>\n",
" <th>red_qty</th>\n",
" <th>n_tx</th>\n",
" <th>n_isin_held</th>\n",
" <th>n_isin_active</th>\n",
" <th>ret_fund_m</th>\n",
" <th>delta_rate_m</th>\n",
" <th>region</th>\n",
" <th>country</th>\n",
" <th>active_month</th>\n",
" <th>flow_to_aum_m</th>\n",
" <th>turnover_m</th>\n",
" <th>sub_share_m</th>\n",
" <th>red_share_m</th>\n",
" <th>aum_peak_to_date</th>\n",
" <th>aum_drawdown</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-01-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.064516</td>\n",
" <td>-0.058</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-02-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.022</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-03-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.014</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-04-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.077</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-05-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.053</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-06-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.045455</td>\n",
" <td>0.020</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-07-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.042</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-08-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.008</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-09-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.012</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-10-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.007</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Registrar Account - ID fund_family month \\\n",
"0 100000014 Carmignac Portfolio Climate Transition 2015-01-01 \n",
"1 100000014 Carmignac Portfolio Climate Transition 2015-02-01 \n",
"2 100000014 Carmignac Portfolio Climate Transition 2015-03-01 \n",
"3 100000014 Carmignac Portfolio Climate Transition 2015-04-01 \n",
"4 100000014 Carmignac Portfolio Climate Transition 2015-05-01 \n",
"5 100000014 Carmignac Portfolio Climate Transition 2015-06-01 \n",
"6 100000014 Carmignac Portfolio Climate Transition 2015-07-01 \n",
"7 100000014 Carmignac Portfolio Climate Transition 2015-08-01 \n",
"8 100000014 Carmignac Portfolio Climate Transition 2015-09-01 \n",
"9 100000014 Carmignac Portfolio Climate Transition 2015-10-01 \n",
"\n",
" aum_qty aum_val net_flow_qty gross_flow_qty sub_qty red_qty n_tx \\\n",
"0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"6 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"8 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"\n",
" n_isin_held n_isin_active ret_fund_m delta_rate_m region \\\n",
"0 0 0 0.064516 -0.058 Switzerland \n",
"1 0 0 0.000000 -0.022 Switzerland \n",
"2 0 0 0.000000 -0.014 Switzerland \n",
"3 0 0 0.000000 -0.077 Switzerland \n",
"4 0 0 0.000000 -0.053 Switzerland \n",
"5 0 0 0.045455 0.020 Switzerland \n",
"6 0 0 0.000000 -0.042 Switzerland \n",
"7 0 0 0.000000 -0.008 Switzerland \n",
"8 0 0 0.000000 -0.012 Switzerland \n",
"9 0 0 0.000000 -0.007 Switzerland \n",
"\n",
" country active_month flow_to_aum_m turnover_m sub_share_m \\\n",
"0 Switzerland 0 NaN NaN NaN \n",
"1 Switzerland 0 NaN NaN NaN \n",
"2 Switzerland 0 NaN NaN NaN \n",
"3 Switzerland 0 NaN NaN NaN \n",
"4 Switzerland 0 NaN NaN NaN \n",
"5 Switzerland 0 NaN NaN NaN \n",
"6 Switzerland 0 NaN NaN NaN \n",
"7 Switzerland 0 NaN NaN NaN \n",
"8 Switzerland 0 NaN NaN NaN \n",
"9 Switzerland 0 NaN NaN NaN \n",
"\n",
" red_share_m aum_peak_to_date aum_drawdown \n",
"0 NaN 0.0 NaN \n",
"1 NaN 0.0 NaN \n",
"2 NaN 0.0 NaN \n",
"3 NaN 0.0 NaN \n",
"4 NaN 0.0 NaN \n",
"5 NaN 0.0 NaN \n",
"6 NaN 0.0 NaN \n",
"7 NaN 0.0 NaN \n",
"8 NaN 0.0 NaN \n",
"9 NaN 0.0 NaN "
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Aggregation: compte × famille × mois\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_family_month = (\n",
" tmp\n",
" .dropna(subset=[ID_COL, \"fund_family\", \"month\"])\n",
" .groupby([ID_COL, \"fund_family\", \"month\"], as_index=False) #groupe sur family fund pas code isin\n",
" .agg(\n",
" aum_qty=(\"aum_qty\", \"sum\"), #somme sur les membres de la famille\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",
" ret_fund_m=(\"ret_fund_m\", \"mean\"),\n",
" delta_rate_m=(\"delta_rate_m\", \"first\"),\n",
" region=(\"region\", \"first\"),\n",
" country=(\"country\", \"first\")\n",
" )\n",
" .sort_values([ID_COL, \"fund_family\", \"month\"])\n",
" .reset_index(drop=True)\n",
")\n",
"\n",
"df_family_month[\"active_month\"] = (df_family_month[\"gross_flow_qty\"] > 0).astype(int)\n",
"\n",
"df_family_month[\"flow_to_aum_m\"] = np.where(\n",
" df_family_month[\"aum_qty\"].abs() > 0,\n",
" df_family_month[\"net_flow_qty\"] / df_family_month[\"aum_qty\"].abs(),\n",
" np.nan\n",
")\n",
"\n",
"df_family_month[\"turnover_m\"] = np.where(\n",
" df_family_month[\"aum_qty\"].abs() > 0,\n",
" df_family_month[\"gross_flow_qty\"] / df_family_month[\"aum_qty\"].abs(),\n",
" np.nan\n",
")\n",
"\n",
"df_family_month[\"sub_share_m\"] = np.where(\n",
" df_family_month[\"gross_flow_qty\"] > 0,\n",
" df_family_month[\"sub_qty\"] / df_family_month[\"gross_flow_qty\"],\n",
" np.nan\n",
")\n",
"\n",
"df_family_month[\"red_share_m\"] = np.where(\n",
" df_family_month[\"gross_flow_qty\"] > 0,\n",
" df_family_month[\"red_qty\"] / df_family_month[\"gross_flow_qty\"],\n",
" np.nan\n",
")\n",
"\n",
"df_family_month[\"aum_peak_to_date\"] = df_family_month.groupby([ID_COL, \"fund_family\"])[\"aum_qty\"].cummax()\n",
"\n",
"df_family_month[\"aum_drawdown\"] = np.where(\n",
" df_family_month[\"aum_peak_to_date\"] > 0,\n",
" 1 - df_family_month[\"aum_qty\"] / df_family_month[\"aum_peak_to_date\"],\n",
" np.nan\n",
")\n",
"\n",
"print(\"df_family_month shape:\", df_family_month.shape)\n",
"df_family_month.head(10)"
]
},
{
"cell_type": "markdown",
"id": "9121da21",
"metadata": {
"id": "9121da21"
},
"source": [
"---\n",
"## 7. Client-level portfolio totals\n",
"\n",
"To assess how important a given fund family is within the investor portfolio, we compute the total client AUM by month and derive the family share in the portfolio.\n",
"\n",
"This variable is useful for distinguishing:\n",
"- marginal positions,\n",
"- core strategic allocations,\n",
"- and family relationships that dominate the client portfolio.\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "b7fdb2fe-26ce-4881-903d-01fd6e473ac4",
"metadata": {
"id": "b7fdb2fe-26ce-4881-903d-01fd6e473ac4",
"outputId": "ab61cc1b-0587-4f0c-dba4-b66df3ad983d"
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Registrar Account - ID</th>\n",
" <th>fund_family</th>\n",
" <th>month</th>\n",
" <th>aum_qty</th>\n",
" <th>aum_val</th>\n",
" <th>net_flow_qty</th>\n",
" <th>gross_flow_qty</th>\n",
" <th>sub_qty</th>\n",
" <th>red_qty</th>\n",
" <th>n_tx</th>\n",
" <th>n_isin_held</th>\n",
" <th>n_isin_active</th>\n",
" <th>ret_fund_m</th>\n",
" <th>delta_rate_m</th>\n",
" <th>region</th>\n",
" <th>country</th>\n",
" <th>active_month</th>\n",
" <th>flow_to_aum_m</th>\n",
" <th>turnover_m</th>\n",
" <th>sub_share_m</th>\n",
" <th>red_share_m</th>\n",
" <th>aum_peak_to_date</th>\n",
" <th>aum_drawdown</th>\n",
" <th>total_client_aum_qty</th>\n",
" <th>total_client_aum_val</th>\n",
" <th>family_share_of_client_aum</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-01-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.064516</td>\n",
" <td>-0.058</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-02-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.022</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-03-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.014</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-04-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.077</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-05-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.053</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-06-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.045455</td>\n",
" <td>0.020</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-07-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.042</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-08-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.008</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-09-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.012</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-10-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.007</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Registrar Account - ID fund_family month \\\n",
"0 100000014 Carmignac Portfolio Climate Transition 2015-01-01 \n",
"1 100000014 Carmignac Portfolio Climate Transition 2015-02-01 \n",
"2 100000014 Carmignac Portfolio Climate Transition 2015-03-01 \n",
"3 100000014 Carmignac Portfolio Climate Transition 2015-04-01 \n",
"4 100000014 Carmignac Portfolio Climate Transition 2015-05-01 \n",
"5 100000014 Carmignac Portfolio Climate Transition 2015-06-01 \n",
"6 100000014 Carmignac Portfolio Climate Transition 2015-07-01 \n",
"7 100000014 Carmignac Portfolio Climate Transition 2015-08-01 \n",
"8 100000014 Carmignac Portfolio Climate Transition 2015-09-01 \n",
"9 100000014 Carmignac Portfolio Climate Transition 2015-10-01 \n",
"\n",
" aum_qty aum_val net_flow_qty gross_flow_qty sub_qty red_qty n_tx \\\n",
"0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"6 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"8 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"\n",
" n_isin_held n_isin_active ret_fund_m delta_rate_m region \\\n",
"0 0 0 0.064516 -0.058 Switzerland \n",
"1 0 0 0.000000 -0.022 Switzerland \n",
"2 0 0 0.000000 -0.014 Switzerland \n",
"3 0 0 0.000000 -0.077 Switzerland \n",
"4 0 0 0.000000 -0.053 Switzerland \n",
"5 0 0 0.045455 0.020 Switzerland \n",
"6 0 0 0.000000 -0.042 Switzerland \n",
"7 0 0 0.000000 -0.008 Switzerland \n",
"8 0 0 0.000000 -0.012 Switzerland \n",
"9 0 0 0.000000 -0.007 Switzerland \n",
"\n",
" country active_month flow_to_aum_m turnover_m sub_share_m \\\n",
"0 Switzerland 0 NaN NaN NaN \n",
"1 Switzerland 0 NaN NaN NaN \n",
"2 Switzerland 0 NaN NaN NaN \n",
"3 Switzerland 0 NaN NaN NaN \n",
"4 Switzerland 0 NaN NaN NaN \n",
"5 Switzerland 0 NaN NaN NaN \n",
"6 Switzerland 0 NaN NaN NaN \n",
"7 Switzerland 0 NaN NaN NaN \n",
"8 Switzerland 0 NaN NaN NaN \n",
"9 Switzerland 0 NaN NaN NaN \n",
"\n",
" red_share_m aum_peak_to_date aum_drawdown total_client_aum_qty \\\n",
"0 NaN 0.0 NaN 0.0 \n",
"1 NaN 0.0 NaN 0.0 \n",
"2 NaN 0.0 NaN 0.0 \n",
"3 NaN 0.0 NaN 0.0 \n",
"4 NaN 0.0 NaN 0.0 \n",
"5 NaN 0.0 NaN 0.0 \n",
"6 NaN 0.0 NaN 0.0 \n",
"7 NaN 0.0 NaN 0.0 \n",
"8 NaN 0.0 NaN 0.0 \n",
"9 NaN 0.0 NaN 0.0 \n",
"\n",
" total_client_aum_val family_share_of_client_aum \n",
"0 0.0 NaN \n",
"1 0.0 NaN \n",
"2 0.0 NaN \n",
"3 0.0 NaN \n",
"4 0.0 NaN \n",
"5 0.0 NaN \n",
"6 0.0 NaN \n",
"7 0.0 NaN \n",
"8 0.0 NaN \n",
"9 0.0 NaN "
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Compute total client AUM by month across all ISINs.\n",
"# This provides the denominator for the portfolio share of each family.\n",
"\n",
"df_client_total_month = ( #1 client all funds\n",
" df_rel_m\n",
" .groupby([ID_COL, \"month\"], as_index=False) #client * mois\n",
" .agg(\n",
" total_client_aum_qty=(\"aum_qty\", \"sum\"),\n",
" total_client_aum_val=(\"aum_val\", \"sum\")\n",
" )\n",
")\n",
"\n",
"df_family_month = df_family_month.merge(\n",
" df_client_total_month,\n",
" on=[ID_COL, \"month\"],\n",
" how=\"left\"\n",
")\n",
"\n",
"df_family_month[\"family_share_of_client_aum\"] = np.where(\n",
" df_family_month[\"total_client_aum_val\"].abs() > 0,\n",
" df_family_month[\"aum_val\"] / df_family_month[\"total_client_aum_val\"].abs(),\n",
" np.nan\n",
")\n",
"\n",
"df_family_month.head(10)"
]
},
{
"cell_type": "markdown",
"id": "TVopCIU6uAMa",
"metadata": {
"id": "TVopCIU6uAMa"
},
"source": [
"---\n",
"## 8. Temporal feature engineering at the client × family × month level\n",
"\n",
"We now create dynamic indicators of investor behavior within each fund family.\n",
"\n",
"These variables aim to capture:\n",
"- activity and inactivity periods,\n",
"- entry and full-exit events,\n",
"- persistence of trading intensity,\n",
"- and recent relationship deterioration.\n",
"\n",
"Because the panel is monthly, these indicators should be interpreted as medium-frequency behavioral proxies rather than precise transaction-level events."
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "d4a01bcc",
"metadata": {
"id": "d4a01bcc",
"outputId": "8f810678-78c5-4e4a-b0a5-9ff0003f1553"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(3805010, 44)\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Registrar Account - ID</th>\n",
" <th>fund_family</th>\n",
" <th>month</th>\n",
" <th>aum_qty</th>\n",
" <th>aum_val</th>\n",
" <th>net_flow_qty</th>\n",
" <th>gross_flow_qty</th>\n",
" <th>sub_qty</th>\n",
" <th>red_qty</th>\n",
" <th>n_tx</th>\n",
" <th>n_isin_held</th>\n",
" <th>n_isin_active</th>\n",
" <th>ret_fund_m</th>\n",
" <th>delta_rate_m</th>\n",
" <th>region</th>\n",
" <th>country</th>\n",
" <th>active_month</th>\n",
" <th>flow_to_aum_m</th>\n",
" <th>turnover_m</th>\n",
" <th>sub_share_m</th>\n",
" <th>red_share_m</th>\n",
" <th>aum_peak_to_date</th>\n",
" <th>aum_drawdown</th>\n",
" <th>total_client_aum_qty</th>\n",
" <th>total_client_aum_val</th>\n",
" <th>family_share_of_client_aum</th>\n",
" <th>prev_aum</th>\n",
" <th>entry_event</th>\n",
" <th>full_exit_event</th>\n",
" <th>ret_fund_m_lag1</th>\n",
" <th>buy_on_perf</th>\n",
" <th>sell_on_perf</th>\n",
" <th>ret_fund_mean3_lag1</th>\n",
" <th>ret_fund_mean6_lag1</th>\n",
" <th>buy_on_perf_mean3</th>\n",
" <th>sell_on_perf_mean3</th>\n",
" <th>buy_on_perf_mean6</th>\n",
" <th>sell_on_perf_mean6</th>\n",
" <th>turnover_m_mean3</th>\n",
" <th>flow_to_aum_m_mean3</th>\n",
" <th>turnover_m_mean6</th>\n",
" <th>flow_to_aum_m_mean6</th>\n",
" <th>turnover_m_mean12</th>\n",
" <th>flow_to_aum_m_mean12</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-01-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.064516</td>\n",
" <td>-0.058</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-02-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.022</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.064516</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.064516</td>\n",
" <td>0.064516</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-03-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.014</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.032258</td>\n",
" <td>0.032258</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-04-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.077</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.021505</td>\n",
" <td>0.021505</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-05-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.053</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0.016129</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-06-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.045455</td>\n",
" <td>0.020</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0.012903</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-07-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.042</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.045455</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.015152</td>\n",
" <td>0.018328</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-08-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.008</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.015152</td>\n",
" <td>0.007576</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-09-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.012</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.015152</td>\n",
" <td>0.007576</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>2015-10-01</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>-0.007</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>0.0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>0.007576</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Registrar Account - ID fund_family month \\\n",
"0 100000014 Carmignac Portfolio Climate Transition 2015-01-01 \n",
"1 100000014 Carmignac Portfolio Climate Transition 2015-02-01 \n",
"2 100000014 Carmignac Portfolio Climate Transition 2015-03-01 \n",
"3 100000014 Carmignac Portfolio Climate Transition 2015-04-01 \n",
"4 100000014 Carmignac Portfolio Climate Transition 2015-05-01 \n",
"5 100000014 Carmignac Portfolio Climate Transition 2015-06-01 \n",
"6 100000014 Carmignac Portfolio Climate Transition 2015-07-01 \n",
"7 100000014 Carmignac Portfolio Climate Transition 2015-08-01 \n",
"8 100000014 Carmignac Portfolio Climate Transition 2015-09-01 \n",
"9 100000014 Carmignac Portfolio Climate Transition 2015-10-01 \n",
"\n",
" aum_qty aum_val net_flow_qty gross_flow_qty sub_qty red_qty n_tx \\\n",
"0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"6 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"8 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
"\n",
" n_isin_held n_isin_active ret_fund_m delta_rate_m region \\\n",
"0 0 0 0.064516 -0.058 Switzerland \n",
"1 0 0 0.000000 -0.022 Switzerland \n",
"2 0 0 0.000000 -0.014 Switzerland \n",
"3 0 0 0.000000 -0.077 Switzerland \n",
"4 0 0 0.000000 -0.053 Switzerland \n",
"5 0 0 0.045455 0.020 Switzerland \n",
"6 0 0 0.000000 -0.042 Switzerland \n",
"7 0 0 0.000000 -0.008 Switzerland \n",
"8 0 0 0.000000 -0.012 Switzerland \n",
"9 0 0 0.000000 -0.007 Switzerland \n",
"\n",
" country active_month flow_to_aum_m turnover_m sub_share_m \\\n",
"0 Switzerland 0 NaN NaN NaN \n",
"1 Switzerland 0 NaN NaN NaN \n",
"2 Switzerland 0 NaN NaN NaN \n",
"3 Switzerland 0 NaN NaN NaN \n",
"4 Switzerland 0 NaN NaN NaN \n",
"5 Switzerland 0 NaN NaN NaN \n",
"6 Switzerland 0 NaN NaN NaN \n",
"7 Switzerland 0 NaN NaN NaN \n",
"8 Switzerland 0 NaN NaN NaN \n",
"9 Switzerland 0 NaN NaN NaN \n",
"\n",
" red_share_m aum_peak_to_date aum_drawdown total_client_aum_qty \\\n",
"0 NaN 0.0 NaN 0.0 \n",
"1 NaN 0.0 NaN 0.0 \n",
"2 NaN 0.0 NaN 0.0 \n",
"3 NaN 0.0 NaN 0.0 \n",
"4 NaN 0.0 NaN 0.0 \n",
"5 NaN 0.0 NaN 0.0 \n",
"6 NaN 0.0 NaN 0.0 \n",
"7 NaN 0.0 NaN 0.0 \n",
"8 NaN 0.0 NaN 0.0 \n",
"9 NaN 0.0 NaN 0.0 \n",
"\n",
" total_client_aum_val family_share_of_client_aum prev_aum entry_event \\\n",
"0 0.0 NaN NaN 0 \n",
"1 0.0 NaN 0.0 0 \n",
"2 0.0 NaN 0.0 0 \n",
"3 0.0 NaN 0.0 0 \n",
"4 0.0 NaN 0.0 0 \n",
"5 0.0 NaN 0.0 0 \n",
"6 0.0 NaN 0.0 0 \n",
"7 0.0 NaN 0.0 0 \n",
"8 0.0 NaN 0.0 0 \n",
"9 0.0 NaN 0.0 0 \n",
"\n",
" full_exit_event ret_fund_m_lag1 buy_on_perf sell_on_perf \\\n",
"0 0 NaN 0 0 \n",
"1 0 0.064516 0 0 \n",
"2 0 0.000000 0 0 \n",
"3 0 0.000000 0 0 \n",
"4 0 0.000000 0 0 \n",
"5 0 0.000000 0 0 \n",
"6 0 0.045455 0 0 \n",
"7 0 0.000000 0 0 \n",
"8 0 0.000000 0 0 \n",
"9 0 0.000000 0 0 \n",
"\n",
" ret_fund_mean3_lag1 ret_fund_mean6_lag1 buy_on_perf_mean3 \\\n",
"0 NaN NaN 0 \n",
"1 0.064516 0.064516 0 \n",
"2 0.032258 0.032258 0 \n",
"3 0.021505 0.021505 0 \n",
"4 0.000000 0.016129 0 \n",
"5 0.000000 0.012903 0 \n",
"6 0.015152 0.018328 0 \n",
"7 0.015152 0.007576 0 \n",
"8 0.015152 0.007576 0 \n",
"9 0.000000 0.007576 0 \n",
"\n",
" sell_on_perf_mean3 buy_on_perf_mean6 sell_on_perf_mean6 \\\n",
"0 0 0 0 \n",
"1 0 0 0 \n",
"2 0 0 0 \n",
"3 0 0 0 \n",
"4 0 0 0 \n",
"5 0 0 0 \n",
"6 0 0 0 \n",
"7 0 0 0 \n",
"8 0 0 0 \n",
"9 0 0 0 \n",
"\n",
" turnover_m_mean3 flow_to_aum_m_mean3 turnover_m_mean6 \\\n",
"0 NaN NaN NaN \n",
"1 NaN NaN NaN \n",
"2 NaN NaN NaN \n",
"3 NaN NaN NaN \n",
"4 NaN NaN NaN \n",
"5 NaN NaN NaN \n",
"6 NaN NaN NaN \n",
"7 NaN NaN NaN \n",
"8 NaN NaN NaN \n",
"9 NaN NaN NaN \n",
"\n",
" flow_to_aum_m_mean6 turnover_m_mean12 flow_to_aum_m_mean12 \n",
"0 NaN NaN NaN \n",
"1 NaN NaN NaN \n",
"2 NaN NaN NaN \n",
"3 NaN NaN NaN \n",
"4 NaN NaN NaN \n",
"5 NaN NaN NaN \n",
"6 NaN NaN NaN \n",
"7 NaN NaN NaN \n",
"8 NaN NaN NaN \n",
"9 NaN NaN NaN "
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Level client × famille × mois + comportement\n",
"\n",
"tmp = df_family_month.sort_values([ID_COL, \"fund_family\", \"month\"]).reset_index(drop=True)\n",
"tmp[\"prev_aum\"] = tmp.groupby([ID_COL, \"fund_family\"])[\"aum_qty\"].shift(1)\n",
"tmp[\"entry_event\"] = (\n",
" (tmp[\"prev_aum\"].fillna(0) <= 0) & (tmp[\"aum_qty\"] > 0)\n",
").astype(int)\n",
"\n",
"tmp[\"full_exit_event\"] = (\n",
" (tmp[\"prev_aum\"] > 0) & (tmp[\"aum_qty\"] <= 0)\n",
").astype(int)\n",
"\n",
"tmp[\"ret_fund_m_lag1\"] = tmp.groupby([ID_COL, \"fund_family\"])[\"ret_fund_m\"].shift(1)\n",
"\n",
"tmp[\"buy_on_perf\"] = (\n",
" (tmp[\"net_flow_qty\"] > 0) & (tmp[\"ret_fund_m_lag1\"] > 0)\n",
").astype(int)\n",
"\n",
"tmp[\"sell_on_perf\"] = (\n",
" (tmp[\"net_flow_qty\"] < 0) & (tmp[\"ret_fund_m_lag1\"] < 0)\n",
").astype(int)\n",
"\n",
"tmp[\"ret_fund_mean3_lag1\"] = (\n",
" tmp.groupby([ID_COL, \"fund_family\"])[\"ret_fund_m\"]\n",
" .transform(lambda s: s.shift(1).rolling(3, min_periods=1).mean())\n",
")\n",
"\n",
"tmp[\"ret_fund_mean6_lag1\"] = (\n",
" tmp.groupby([ID_COL, \"fund_family\"])[\"ret_fund_m\"]\n",
" .transform(lambda s: s.shift(1).rolling(6, min_periods=1).mean())\n",
")\n",
"\n",
"tmp[\"buy_on_perf_mean3\"] = (\n",
" (tmp[\"net_flow_qty\"] > 0) & (tmp[\"ret_fund_mean3_lag1\"] > 0)\n",
").astype(int)\n",
"\n",
"tmp[\"sell_on_perf_mean3\"] = (\n",
" (tmp[\"net_flow_qty\"] < 0) & (tmp[\"ret_fund_mean3_lag1\"] < 0)\n",
").astype(int)\n",
"\n",
"tmp[\"buy_on_perf_mean6\"] = (\n",
" (tmp[\"net_flow_qty\"] > 0) & (tmp[\"ret_fund_mean6_lag1\"] > 0)\n",
").astype(int)\n",
"\n",
"tmp[\"sell_on_perf_mean6\"] = (\n",
" (tmp[\"net_flow_qty\"] < 0) & (tmp[\"ret_fund_mean6_lag1\"] < 0)\n",
").astype(int)\n",
"\n",
"for w in [3, 6, 12]:\n",
" tmp[f\"turnover_m_mean{w}\"] = (\n",
" tmp.groupby([ID_COL, \"fund_family\"])[\"turnover_m\"]\n",
" .transform(lambda s: s.rolling(w, min_periods=1).mean())\n",
" )\n",
"\n",
" tmp[f\"flow_to_aum_m_mean{w}\"] = (\n",
" tmp.groupby([ID_COL, \"fund_family\"])[\"flow_to_aum_m\"]\n",
" .transform(lambda s: s.rolling(w, min_periods=1).mean())\n",
" )\n",
"\n",
"print(tmp.shape)\n",
"tmp.head(10)"
]
},
{
"cell_type": "markdown",
"id": "YiyQOCE0uIGC",
"metadata": {
"id": "YiyQOCE0uIGC"
},
"source": [
"---\n",
"## 9. Base feature table at the client × fund-family level\n",
"\n",
"The monthly panel is now collapsed into one observation per client-family pair.\n",
"\n",
"At this stage, we summarize:\n",
"- duration and activity,\n",
"- average exposure,\n",
"- aggregate flow behavior,\n",
"- exit frequency,\n",
"- and smoothed turnover dynamics.\n",
"\n",
"This table will serve as the foundation for the final clustering features."
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "965cd530-9985-4d57-938c-cef531459c39",
"metadata": {
"id": "965cd530-9985-4d57-938c-cef531459c39",
"outputId": "c8e1f83f-3f22-421e-a692-d1c688891e11"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"df_family_client_base shape: (53891, 49)\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Registrar Account - ID</th>\n",
" <th>fund_family</th>\n",
" <th>n_months</th>\n",
" <th>n_active_months</th>\n",
" <th>flow_freq</th>\n",
" <th>family_aum_qty_mean</th>\n",
" <th>family_aum_qty_median</th>\n",
" <th>family_aum_qty_max</th>\n",
" <th>family_aum_qty_last</th>\n",
" <th>family_aum_val_mean</th>\n",
" <th>family_aum_val_last</th>\n",
" <th>net_flow_qty_sum</th>\n",
" <th>gross_flow_qty_sum</th>\n",
" <th>gross_flow_qty_mean</th>\n",
" <th>sub_qty_sum</th>\n",
" <th>red_qty_sum</th>\n",
" <th>n_tx_total</th>\n",
" <th>avg_n_isin_held</th>\n",
" <th>max_n_isin_held</th>\n",
" <th>net_flow_qty_vol</th>\n",
" <th>flow_to_aum_mean</th>\n",
" <th>flow_to_aum_vol</th>\n",
" <th>turnover_mean</th>\n",
" <th>turnover_vol</th>\n",
" <th>sub_share_mean</th>\n",
" <th>red_share_mean</th>\n",
" <th>aum_drawdown_last</th>\n",
" <th>aum_drawdown_max</th>\n",
" <th>entry_count</th>\n",
" <th>full_exit_count</th>\n",
" <th>buy_on_perf_rate</th>\n",
" <th>sell_on_perf_rate</th>\n",
" <th>buy_on_perf_mean3_rate</th>\n",
" <th>sell_on_perf_mean3_rate</th>\n",
" <th>buy_on_perf_mean6_rate</th>\n",
" <th>sell_on_perf_mean6_rate</th>\n",
" <th>turnover_mean3_avg</th>\n",
" <th>turnover_mean6_avg</th>\n",
" <th>turnover_mean12_avg</th>\n",
" <th>flow_to_aum_mean3_avg</th>\n",
" <th>flow_to_aum_mean6_avg</th>\n",
" <th>flow_to_aum_mean12_avg</th>\n",
" <th>family_share_of_client_aum_mean</th>\n",
" <th>family_share_of_client_aum_max</th>\n",
" <th>ret_fund_m_mean</th>\n",
" <th>delta_rate_m_mean</th>\n",
" <th>region</th>\n",
" <th>country</th>\n",
" <th>months_since_last_tx_family</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>80</td>\n",
" <td>0</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.0000</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.001500</td>\n",
" <td>-0.008925</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>100000016</td>\n",
" <td>Carmignac Emergents</td>\n",
" <td>80</td>\n",
" <td>0</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.0000</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.000520</td>\n",
" <td>-0.008925</td>\n",
" <td>United Kingdom</td>\n",
" <td>United Kingdom</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>100000016</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>80</td>\n",
" <td>0</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.0000</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.002345</td>\n",
" <td>-0.008925</td>\n",
" <td>United Kingdom</td>\n",
" <td>United Kingdom</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>100000028</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>80</td>\n",
" <td>2</td>\n",
" <td>0.025</td>\n",
" <td>9.529013</td>\n",
" <td>0.0</td>\n",
" <td>109.235</td>\n",
" <td>0.0</td>\n",
" <td>1577.952730</td>\n",
" <td>0.0</td>\n",
" <td>-109.238</td>\n",
" <td>109.238</td>\n",
" <td>1.365475</td>\n",
" <td>0.0</td>\n",
" <td>-109.238</td>\n",
" <td>3.0</td>\n",
" <td>0.1000</td>\n",
" <td>1</td>\n",
" <td>10.559919</td>\n",
" <td>-0.021356</td>\n",
" <td>0.060405</td>\n",
" <td>0.021356</td>\n",
" <td>0.060405</td>\n",
" <td>0.0</td>\n",
" <td>-1.0</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.019933</td>\n",
" <td>0.021247</td>\n",
" <td>0.021228</td>\n",
" <td>-0.019933</td>\n",
" <td>-0.021247</td>\n",
" <td>-0.021228</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>0.002345</td>\n",
" <td>-0.008925</td>\n",
" <td>United Kingdom</td>\n",
" <td>United Kingdom</td>\n",
" <td>121.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>100000038</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>80</td>\n",
" <td>0</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.0000</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.003393</td>\n",
" <td>-0.008925</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>100000038</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>80</td>\n",
" <td>0</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.0000</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.001500</td>\n",
" <td>-0.008925</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>100000038</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" <td>56</td>\n",
" <td>0</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.0000</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.005728</td>\n",
" <td>-0.004304</td>\n",
" <td>Switzerland</td>\n",
" <td>Switzerland</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>100000042</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>80</td>\n",
" <td>0</td>\n",
" <td>0.000</td>\n",
" <td>57.760063</td>\n",
" <td>0.0</td>\n",
" <td>660.115</td>\n",
" <td>0.0</td>\n",
" <td>5579.536269</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.0875</td>\n",
" <td>1</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>1</td>\n",
" <td>1</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>1.0</td>\n",
" <td>1.0</td>\n",
" <td>0.001500</td>\n",
" <td>-0.008925</td>\n",
" <td>United Kingdom</td>\n",
" <td>United Kingdom</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>100000044</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>80</td>\n",
" <td>0</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.0000</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.001500</td>\n",
" <td>-0.008925</td>\n",
" <td>France</td>\n",
" <td>France</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>100000047</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>80</td>\n",
" <td>0</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.000</td>\n",
" <td>0.0</td>\n",
" <td>0.0000</td>\n",
" <td>0</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>0.000000</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0</td>\n",
" <td>0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>0.002345</td>\n",
" <td>-0.008925</td>\n",
" <td>United Kingdom</td>\n",
" <td>United Kingdom</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Registrar Account - ID fund_family n_months \\\n",
"0 100000014 Carmignac Portfolio Climate Transition 80 \n",
"1 100000016 Carmignac Emergents 80 \n",
"2 100000016 Carmignac Patrimoine 80 \n",
"3 100000028 Carmignac Patrimoine 80 \n",
"4 100000038 Carmignac Patrimoine 80 \n",
"5 100000038 Carmignac Portfolio Climate Transition 80 \n",
"6 100000038 Carmignac Portfolio Emerging Patrimoine 56 \n",
"7 100000042 Carmignac Portfolio Climate Transition 80 \n",
"8 100000044 Carmignac Portfolio Climate Transition 80 \n",
"9 100000047 Carmignac Patrimoine 80 \n",
"\n",
" n_active_months flow_freq family_aum_qty_mean family_aum_qty_median \\\n",
"0 0 0.000 0.000000 0.0 \n",
"1 0 0.000 0.000000 0.0 \n",
"2 0 0.000 0.000000 0.0 \n",
"3 2 0.025 9.529013 0.0 \n",
"4 0 0.000 0.000000 0.0 \n",
"5 0 0.000 0.000000 0.0 \n",
"6 0 0.000 0.000000 0.0 \n",
"7 0 0.000 57.760063 0.0 \n",
"8 0 0.000 0.000000 0.0 \n",
"9 0 0.000 0.000000 0.0 \n",
"\n",
" family_aum_qty_max family_aum_qty_last family_aum_val_mean \\\n",
"0 0.000 0.0 0.000000 \n",
"1 0.000 0.0 0.000000 \n",
"2 0.000 0.0 0.000000 \n",
"3 109.235 0.0 1577.952730 \n",
"4 0.000 0.0 0.000000 \n",
"5 0.000 0.0 0.000000 \n",
"6 0.000 0.0 0.000000 \n",
"7 660.115 0.0 5579.536269 \n",
"8 0.000 0.0 0.000000 \n",
"9 0.000 0.0 0.000000 \n",
"\n",
" family_aum_val_last net_flow_qty_sum gross_flow_qty_sum \\\n",
"0 0.0 0.000 0.000 \n",
"1 0.0 0.000 0.000 \n",
"2 0.0 0.000 0.000 \n",
"3 0.0 -109.238 109.238 \n",
"4 0.0 0.000 0.000 \n",
"5 0.0 0.000 0.000 \n",
"6 0.0 0.000 0.000 \n",
"7 0.0 0.000 0.000 \n",
"8 0.0 0.000 0.000 \n",
"9 0.0 0.000 0.000 \n",
"\n",
" gross_flow_qty_mean sub_qty_sum red_qty_sum n_tx_total avg_n_isin_held \\\n",
"0 0.000000 0.0 0.000 0.0 0.0000 \n",
"1 0.000000 0.0 0.000 0.0 0.0000 \n",
"2 0.000000 0.0 0.000 0.0 0.0000 \n",
"3 1.365475 0.0 -109.238 3.0 0.1000 \n",
"4 0.000000 0.0 0.000 0.0 0.0000 \n",
"5 0.000000 0.0 0.000 0.0 0.0000 \n",
"6 0.000000 0.0 0.000 0.0 0.0000 \n",
"7 0.000000 0.0 0.000 0.0 0.0875 \n",
"8 0.000000 0.0 0.000 0.0 0.0000 \n",
"9 0.000000 0.0 0.000 0.0 0.0000 \n",
"\n",
" max_n_isin_held net_flow_qty_vol flow_to_aum_mean flow_to_aum_vol \\\n",
"0 0 0.000000 NaN 0.000000 \n",
"1 0 0.000000 NaN 0.000000 \n",
"2 0 0.000000 NaN 0.000000 \n",
"3 1 10.559919 -0.021356 0.060405 \n",
"4 0 0.000000 NaN 0.000000 \n",
"5 0 0.000000 NaN 0.000000 \n",
"6 0 0.000000 NaN 0.000000 \n",
"7 1 0.000000 0.000000 0.000000 \n",
"8 0 0.000000 NaN 0.000000 \n",
"9 0 0.000000 NaN 0.000000 \n",
"\n",
" turnover_mean turnover_vol sub_share_mean red_share_mean \\\n",
"0 NaN 0.000000 NaN NaN \n",
"1 NaN 0.000000 NaN NaN \n",
"2 NaN 0.000000 NaN NaN \n",
"3 0.021356 0.060405 0.0 -1.0 \n",
"4 NaN 0.000000 NaN NaN \n",
"5 NaN 0.000000 NaN NaN \n",
"6 NaN 0.000000 NaN NaN \n",
"7 0.000000 0.000000 NaN NaN \n",
"8 NaN 0.000000 NaN NaN \n",
"9 NaN 0.000000 NaN NaN \n",
"\n",
" aum_drawdown_last aum_drawdown_max entry_count full_exit_count \\\n",
"0 NaN NaN 0 0 \n",
"1 NaN NaN 0 0 \n",
"2 NaN NaN 0 0 \n",
"3 1.0 1.0 1 1 \n",
"4 NaN NaN 0 0 \n",
"5 NaN NaN 0 0 \n",
"6 NaN NaN 0 0 \n",
"7 1.0 1.0 1 1 \n",
"8 NaN NaN 0 0 \n",
"9 NaN NaN 0 0 \n",
"\n",
" buy_on_perf_rate sell_on_perf_rate buy_on_perf_mean3_rate \\\n",
"0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 \n",
"5 0.0 0.0 0.0 \n",
"6 0.0 0.0 0.0 \n",
"7 0.0 0.0 0.0 \n",
"8 0.0 0.0 0.0 \n",
"9 0.0 0.0 0.0 \n",
"\n",
" sell_on_perf_mean3_rate buy_on_perf_mean6_rate sell_on_perf_mean6_rate \\\n",
"0 0.0 0.0 0.0 \n",
"1 0.0 0.0 0.0 \n",
"2 0.0 0.0 0.0 \n",
"3 0.0 0.0 0.0 \n",
"4 0.0 0.0 0.0 \n",
"5 0.0 0.0 0.0 \n",
"6 0.0 0.0 0.0 \n",
"7 0.0 0.0 0.0 \n",
"8 0.0 0.0 0.0 \n",
"9 0.0 0.0 0.0 \n",
"\n",
" turnover_mean3_avg turnover_mean6_avg turnover_mean12_avg \\\n",
"0 NaN NaN NaN \n",
"1 NaN NaN NaN \n",
"2 NaN NaN NaN \n",
"3 0.019933 0.021247 0.021228 \n",
"4 NaN NaN NaN \n",
"5 NaN NaN NaN \n",
"6 NaN NaN NaN \n",
"7 0.000000 0.000000 0.000000 \n",
"8 NaN NaN NaN \n",
"9 NaN NaN NaN \n",
"\n",
" flow_to_aum_mean3_avg flow_to_aum_mean6_avg flow_to_aum_mean12_avg \\\n",
"0 NaN NaN NaN \n",
"1 NaN NaN NaN \n",
"2 NaN NaN NaN \n",
"3 -0.019933 -0.021247 -0.021228 \n",
"4 NaN NaN NaN \n",
"5 NaN NaN NaN \n",
"6 NaN NaN NaN \n",
"7 0.000000 0.000000 0.000000 \n",
"8 NaN NaN NaN \n",
"9 NaN NaN NaN \n",
"\n",
" family_share_of_client_aum_mean family_share_of_client_aum_max \\\n",
"0 NaN NaN \n",
"1 NaN NaN \n",
"2 NaN NaN \n",
"3 1.0 1.0 \n",
"4 NaN NaN \n",
"5 NaN NaN \n",
"6 NaN NaN \n",
"7 1.0 1.0 \n",
"8 NaN NaN \n",
"9 NaN NaN \n",
"\n",
" ret_fund_m_mean delta_rate_m_mean region country \\\n",
"0 0.001500 -0.008925 Switzerland Switzerland \n",
"1 0.000520 -0.008925 United Kingdom United Kingdom \n",
"2 0.002345 -0.008925 United Kingdom United Kingdom \n",
"3 0.002345 -0.008925 United Kingdom United Kingdom \n",
"4 0.003393 -0.008925 Switzerland Switzerland \n",
"5 0.001500 -0.008925 Switzerland Switzerland \n",
"6 0.005728 -0.004304 Switzerland Switzerland \n",
"7 0.001500 -0.008925 United Kingdom United Kingdom \n",
"8 0.001500 -0.008925 France France \n",
"9 0.002345 -0.008925 United Kingdom United Kingdom \n",
"\n",
" months_since_last_tx_family \n",
"0 0.0 \n",
"1 0.0 \n",
"2 0.0 \n",
"3 121.0 \n",
"4 0.0 \n",
"5 0.0 \n",
"6 0.0 \n",
"7 0.0 \n",
"8 0.0 \n",
"9 0.0 "
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Aggregate the monthly family panel into one observation per client × family pair\n",
"\n",
"months_since_last_tx = add_months_since_last_tx_by_group(\n",
" tmp,\n",
" id_cols=[ID_COL, \"fund_family\"],\n",
" active_col=\"active_month\",\n",
" month_col=\"month\",\n",
" suffix=\"_family\"\n",
")\n",
"#Calculate, for each couple client*family of funds, how many months have passed since the last activity.\n",
"\n",
"# Aggregate the monthly family panel into one observation per client × family pair\n",
"df_family_client_base = ( #1client *1 fund family\n",
" tmp\n",
" .groupby([ID_COL, \"fund_family\"], as_index=False)\n",
" .agg(\n",
" n_months=(\"month\", \"nunique\"),\n",
" n_active_months=(\"active_month\", \"sum\"),\n",
" flow_freq=(\"active_month\", \"mean\"),\n",
"\n",
" family_aum_qty_mean=(\"aum_qty\", \"mean\"),\n",
" family_aum_qty_median=(\"aum_qty\", \"median\"),\n",
" family_aum_qty_max=(\"aum_qty\", \"max\"),\n",
" family_aum_qty_last=(\"aum_qty\", \"last\"),\n",
"\n",
" family_aum_val_mean=(\"aum_val\", \"mean\"),\n",
" family_aum_val_last=(\"aum_val\", \"last\"),\n",
"\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",
"\n",
" sub_qty_sum=(\"sub_qty\", \"sum\"),\n",
" red_qty_sum=(\"red_qty\", \"sum\"),\n",
" n_tx_total=(\"n_tx\", \"sum\"),\n",
"\n",
" avg_n_isin_held=(\"n_isin_held\", \"mean\"),\n",
" max_n_isin_held=(\"n_isin_held\", \"max\"),\n",
"\n",
" net_flow_qty_vol=(\"net_flow_qty\", \"std\"),\n",
" flow_to_aum_mean=(\"flow_to_aum_m\", \"mean\"),\n",
" flow_to_aum_vol=(\"flow_to_aum_m\", \"std\"),\n",
" turnover_mean=(\"turnover_m\", \"mean\"),\n",
" turnover_vol=(\"turnover_m\", \"std\"),\n",
"\n",
" sub_share_mean=(\"sub_share_m\", \"mean\"),\n",
" red_share_mean=(\"red_share_m\", \"mean\"),\n",
"\n",
" aum_drawdown_last=(\"aum_drawdown\", \"last\"),\n",
" aum_drawdown_max=(\"aum_drawdown\", \"max\"),\n",
"\n",
" entry_count=(\"entry_event\", \"sum\"),\n",
" full_exit_count=(\"full_exit_event\", \"sum\"),\n",
"\n",
" buy_on_perf_rate=(\"buy_on_perf\", \"mean\"),\n",
" sell_on_perf_rate=(\"sell_on_perf\", \"mean\"),\n",
" buy_on_perf_mean3_rate=(\"buy_on_perf_mean3\", \"mean\"),\n",
" sell_on_perf_mean3_rate=(\"sell_on_perf_mean3\", \"mean\"),\n",
" buy_on_perf_mean6_rate=(\"buy_on_perf_mean6\", \"mean\"),\n",
" sell_on_perf_mean6_rate=(\"sell_on_perf_mean6\", \"mean\"),\n",
"\n",
" turnover_mean3_avg=(\"turnover_m_mean3\", \"mean\"),\n",
" turnover_mean6_avg=(\"turnover_m_mean6\", \"mean\"),\n",
" turnover_mean12_avg=(\"turnover_m_mean12\", \"mean\"),\n",
"\n",
" flow_to_aum_mean3_avg=(\"flow_to_aum_m_mean3\", \"mean\"),\n",
" flow_to_aum_mean6_avg=(\"flow_to_aum_m_mean6\", \"mean\"),\n",
" flow_to_aum_mean12_avg=(\"flow_to_aum_m_mean12\", \"mean\"),\n",
"\n",
" family_share_of_client_aum_mean=(\"family_share_of_client_aum\", \"mean\"),\n",
" family_share_of_client_aum_max=(\"family_share_of_client_aum\", \"max\"),\n",
"\n",
" ret_fund_m_mean=(\"ret_fund_m\", \"mean\"),\n",
" delta_rate_m_mean=(\"delta_rate_m\", \"mean\"),\n",
"\n",
" region=(\"region\", \"last\"),\n",
" country=(\"country\", \"last\"),\n",
" )\n",
" .merge(months_since_last_tx, on=[ID_COL, \"fund_family\"], how=\"left\")\n",
")\n",
"\n",
"for col in [\n",
" \"net_flow_qty_vol\",\n",
" \"flow_to_aum_vol\",\n",
" \"turnover_vol\",\n",
" \"months_since_last_tx_family\"\n",
"]:\n",
" if col in df_family_client_base.columns:\n",
" df_family_client_base[col] = df_family_client_base[col].fillna(0)\n",
"\n",
"print(\"df_family_client_base shape:\", df_family_client_base.shape)\n",
"df_family_client_base.head(10)"
]
},
{
"cell_type": "markdown",
"id": "ac6b1959",
"metadata": {
"id": "ac6b1959"
},
"source": [
"---\n",
"## Top 15 Fund Families\n",
"We restrict the clustering analysis to the 15 largest fund families, measured primarily by total final AUM and client coverage.\n",
"---"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "9cabda05",
"metadata": {
"id": "9cabda05",
"outputId": "8a16e391-ad83-4088-eac2-02cd172926ff"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Top 15 families:\n",
"01 - Carmignac Patrimoine\n",
"02 - Carmignac Sécurité\n",
"03 - Carmignac Investissement\n",
"04 - Carmignac Credit <NUM>\n",
"05 - Carmignac Portfolio Sécurité\n",
"06 - Carmignac Portfolio Flexible Bond\n",
"07 - Carmignac Portfolio Credit\n",
"08 - Carmignac Emergents\n",
"09 - Carmignac Court Terme\n",
"10 - Carmignac Portfolio Long-Short European Equities\n",
"11 - Carmignac Portfolio Grande Europe\n",
"12 - Carmignac Portfolio Emergents\n",
"13 - Carmignac Portfolio Global Bond\n",
"14 - Carmignac Portfolio Patrimoine\n",
"15 - Carmignac Portfolio Emerging Patrimoine\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>fund_family</th>\n",
" <th>n_clients</th>\n",
" <th>total_family_aum</th>\n",
" <th>avg_family_aum</th>\n",
" <th>total_gross_flow</th>\n",
" <th>total_tx</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>6183</td>\n",
" <td>6.668324e+09</td>\n",
" <td>2.730239e+06</td>\n",
" <td>1.199596e+07</td>\n",
" <td>49953.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>2825</td>\n",
" <td>5.359539e+09</td>\n",
" <td>3.274706e+06</td>\n",
" <td>5.239893e+06</td>\n",
" <td>36860.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Carmignac Investissement</td>\n",
" <td>4982</td>\n",
" <td>4.111151e+09</td>\n",
" <td>9.593080e+05</td>\n",
" <td>1.304787e+06</td>\n",
" <td>20269.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Carmignac Credit &lt;NUM&gt;</td>\n",
" <td>436</td>\n",
" <td>4.082249e+09</td>\n",
" <td>4.098273e+06</td>\n",
" <td>5.065680e+06</td>\n",
" <td>6893.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>1264</td>\n",
" <td>2.688287e+09</td>\n",
" <td>2.178355e+06</td>\n",
" <td>1.756042e+07</td>\n",
" <td>13177.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" <td>1431</td>\n",
" <td>2.483972e+09</td>\n",
" <td>1.498464e+06</td>\n",
" <td>1.029621e+06</td>\n",
" <td>12046.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" <td>1135</td>\n",
" <td>2.356507e+09</td>\n",
" <td>1.132726e+06</td>\n",
" <td>4.493724e+06</td>\n",
" <td>8018.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>Carmignac Emergents</td>\n",
" <td>4231</td>\n",
" <td>1.095901e+09</td>\n",
" <td>3.089076e+05</td>\n",
" <td>2.353374e+06</td>\n",
" <td>12011.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>1331</td>\n",
" <td>9.948195e+08</td>\n",
" <td>3.681887e+05</td>\n",
" <td>2.222615e+05</td>\n",
" <td>5745.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" <td>689</td>\n",
" <td>7.283139e+08</td>\n",
" <td>1.129733e+06</td>\n",
" <td>3.032355e+06</td>\n",
" <td>4884.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>2950</td>\n",
" <td>5.882891e+08</td>\n",
" <td>2.852247e+05</td>\n",
" <td>2.061285e+06</td>\n",
" <td>9341.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" <td>650</td>\n",
" <td>5.466360e+08</td>\n",
" <td>6.443657e+05</td>\n",
" <td>1.722755e+06</td>\n",
" <td>9211.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" <td>2114</td>\n",
" <td>5.445575e+08</td>\n",
" <td>4.059678e+05</td>\n",
" <td>3.476952e+06</td>\n",
" <td>18356.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" <td>1234</td>\n",
" <td>5.127245e+08</td>\n",
" <td>7.907827e+05</td>\n",
" <td>5.253474e+06</td>\n",
" <td>9133.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" <td>1673</td>\n",
" <td>3.315211e+08</td>\n",
" <td>4.169396e+05</td>\n",
" <td>3.368469e+06</td>\n",
" <td>13732.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" fund_family n_clients \\\n",
"0 Carmignac Patrimoine 6183 \n",
"1 Carmignac Sécurité 2825 \n",
"2 Carmignac Investissement 4982 \n",
"3 Carmignac Credit <NUM> 436 \n",
"4 Carmignac Portfolio Sécurité 1264 \n",
"5 Carmignac Portfolio Flexible Bond 1431 \n",
"6 Carmignac Portfolio Credit 1135 \n",
"7 Carmignac Emergents 4231 \n",
"8 Carmignac Court Terme 1331 \n",
"9 Carmignac Portfolio Long-Short European Equities 689 \n",
"10 Carmignac Portfolio Grande Europe 2950 \n",
"11 Carmignac Portfolio Emergents 650 \n",
"12 Carmignac Portfolio Global Bond 2114 \n",
"13 Carmignac Portfolio Patrimoine 1234 \n",
"14 Carmignac Portfolio Emerging Patrimoine 1673 \n",
"\n",
" total_family_aum avg_family_aum total_gross_flow total_tx \n",
"0 6.668324e+09 2.730239e+06 1.199596e+07 49953.0 \n",
"1 5.359539e+09 3.274706e+06 5.239893e+06 36860.0 \n",
"2 4.111151e+09 9.593080e+05 1.304787e+06 20269.0 \n",
"3 4.082249e+09 4.098273e+06 5.065680e+06 6893.0 \n",
"4 2.688287e+09 2.178355e+06 1.756042e+07 13177.0 \n",
"5 2.483972e+09 1.498464e+06 1.029621e+06 12046.0 \n",
"6 2.356507e+09 1.132726e+06 4.493724e+06 8018.0 \n",
"7 1.095901e+09 3.089076e+05 2.353374e+06 12011.0 \n",
"8 9.948195e+08 3.681887e+05 2.222615e+05 5745.0 \n",
"9 7.283139e+08 1.129733e+06 3.032355e+06 4884.0 \n",
"10 5.882891e+08 2.852247e+05 2.061285e+06 9341.0 \n",
"11 5.466360e+08 6.443657e+05 1.722755e+06 9211.0 \n",
"12 5.445575e+08 4.059678e+05 3.476952e+06 18356.0 \n",
"13 5.127245e+08 7.907827e+05 5.253474e+06 9133.0 \n",
"14 3.315211e+08 4.169396e+05 3.368469e+06 13732.0 "
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Table of 15 top families (by AUM & nbr of clients)\n",
"\n",
"top_family_table = (\n",
" df_family_client_base\n",
" .groupby(\"fund_family\", as_index=False)\n",
" .agg(\n",
" n_clients=(ID_COL, \"nunique\"),\n",
" total_family_aum=(\"family_aum_val_last\", \"sum\"),\n",
" avg_family_aum=(\"family_aum_val_mean\", \"mean\"),\n",
" total_gross_flow=(\"gross_flow_qty_sum\", \"sum\"),\n",
" total_tx=(\"n_tx_total\", \"sum\")\n",
" )\n",
" .sort_values([\"total_family_aum\", \"n_clients\"], ascending=[False, False])\n",
" .reset_index(drop=True)\n",
")\n",
"\n",
"top_15_families = top_family_table.head(15)[\"fund_family\"].tolist()\n",
"\n",
"print(\"Top 15 families:\")\n",
"for i, fam in enumerate(top_15_families, 1):\n",
" print(f\"{i:02d} - {fam}\")\n",
"\n",
"top_family_table.head(15)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "3be8b56b",
"metadata": {
"id": "3be8b56b",
"outputId": "52534b70-a2df-437b-f142-120f791708b3"
},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1200x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3XlcVdX+//HXgQRRDqjIVIGICgrirKnklAOZkjY4pIkDWipppmZ6NVORlCsOOXe1hEukVnbNW2nKYIPlhFOSsyJWOKQpoVdB4PeHP87XIyiDerB6Px+P83i01157rc/e58C9fPysdQx5eXl5iIiIiIiIiIiIWJBVWQcgIiIiIiIiIiJ/P0pKiYiIiIiIiIiIxSkpJSIiIiIiIiIiFqeklIiIiIiIiIiIWJySUiIiIiIiIiIiYnFKSomIiIiIiIiIiMUpKSUiIiIiIiIiIhanpJSIiIiIiIiIiFicklIiIiIiIiIiImJxSkqJiIiIiMXNmjULb29vrK2tadCggcXnNxgMTJkypch+Z86c4fnnn8fJyQmDwcC8efPue2w38/LyYsCAAabjzZs3YzAY2Lx5s6ltwIABeHl5WTyurl27WnTOB4XBYOCVV14p6zCK5fr164wbNw4PDw+srKzo3r37XY1X2GetuD9LIiKFUVJKREREpAwZDIZivW5OQtwvS5YsoUePHnh6emIwGMySITeLjo6+bZynT58ucp6NGzcybtw4AgMDWbFiBW+//fY9vpN757XXXuOrr75iwoQJxMbG8uSTT5Z1SCLF9v777zNr1iyef/55YmJieO2118o6pFL58MMPLZ4QFhHLeKisAxARERH5O4uNjTU7/ve//82mTZsKtNepU+e+xxIZGckff/xBs2bNSE9PL7L/tGnTqF69ullbpUqVirwuMTERKysr3nvvPWxsbEobrkUkJibSrVs3xo4dWybzHzp0CCurO/878rJly8jNzbVQRPJnkpiYyCOPPMLcuXPv2xz/+9//eOih+/tn5Ycffsj+/fsZNWrUfZ1HRCxPSSkRERGRMvTiiy+aHW/dupVNmzYVaLeEr7/+2lQlZW9vX2T/zp0706RJkxLPc/bsWezs7B74hBTciLU4ibb7xdbWtsg+5cqVs0AkYklXr17FxsamyIRkUSzx+S1fvvx9HV9E/tq0fE9ERETkAXf58mXGjBmDh4cHtra2+Pr6EhUVRV5enlm//L1u4uLi8PX1pXz58jRu3JhvvvmmWPNUq1YNg8FQotj++OMPcnJyit3fYDCwYsUKLl++bFryFx0dTWpqqum/C7vm5j1rpkyZgsFg4OjRowwYMIBKlSrh6OjIwIEDuXLlitm1165d47XXXsPZ2Rmj0cjTTz/Nzz//XGSc+UsU8/LyWLRokSlWgAsXLjB27FgCAgKwt7fHwcGBzp07s3fvXrMx8vd/+uijj5g6dSqPPPIIRqOR559/nkuXLnHt2jVGjRqFi4sL9vb2DBw4kGvXrpmNceueUoUpbJ+f3Nxc5s2bh7+/P+XLl8fV1ZWXX36Z33//3azfzp07CQoKomrVqtjZ2VG9enUGDRpU5PPJt3HjRho0aED58uXx8/Pj008/NZ07fvw4BoOh0Cqd77//HoPBwMqVK2879s3PLyIigkcffZTy5cvTvn17jh49atb3ds+pbdu2tG3bttAxS/ue5CvOz9kvv/zCoEGDcHV1xdbWFn9/f95///1C73PVqlVMmjSJRx55hAoVKpCRkXHbZ1PU74T8n6ekpCRSUlKKvQx4/fr1tGnTBqPRiIODA02bNuXDDz+84zWF7SlVkvsu6v1t27YtX3zxBSdPnjTdx82f9wULFuDv70+FChWoXLkyTZo0KTJmEXlwqFJKRERE5AGWl5fH008/TVJSEqGhoTRo0ICvvvqK119/nV9++aXAH/xff/01q1evZuTIkdja2rJ48WKefPJJtm/fTt26de9pbO3atSMzMxMbGxuCgoKYPXs2tWrVuuM1sbGx/Otf/2L79u0sX74cgJYtW5Zq/p49e1K9enVmzJjBrl27WL58OS4uLkRGRpr6DB48mA8++IA+ffrQsmVLEhMT6dKlS5Fjt27dmtjYWPr160fHjh0JCQkxnTt+/Dhr166lR48eVK9enTNnzvDuu+/Spk0bfvrpJx5++GGzsWbMmIGdnR3jx4/n6NGjLFiwgHLlymFlZcXvv//OlClT2Lp1K9HR0VSvXp3JkyeX6nnc7OWXXyY6OpqBAwcycuRITpw4wcKFC9m9ezdbtmyhXLlynD17lk6dOuHs7Mz48eOpVKkSqampZomlOzly5Ai9evVi6NCh9O/fnxUrVtCjRw82bNhAx44d8fb2JjAwkLi4uAJ7GcXFxWE0GunWrVuR88ycORMrKyvGjh3LpUuX+Oc//0nfvn3Ztm1bqZ4N3P17UpyfszNnztC8eXNTstjZ2Zn169cTGhpKRkZGgaVo4eHh2NjYMHbsWK5du3bbSsLi/E5wdnYmNjaWiIgIMjMzmTFjBnDnZcDR0dEMGjQIf39/JkyYQKVKldi9ezcbNmygT58+xX62Jb3vot7fiRMncunSJX7++WfT77v8Ss5ly5YxcuRInn/+eV599VWuXr3Kvn372LZtW4liFpEylCciIiIiD4ywsLC8m/8v2tq1a/OAvOnTp5v1e/755/MMBkPe0aNHTW1AHpC3c+dOU9vJkyfzypcvn/fMM8+UKI6KFSvm9e/fv9Bzq1evzhswYEBeTExM3n/+85+8SZMm5VWoUCGvatWqeWlpaUWO3b9//7yKFSuatZ04cSIPyFuxYkWB/kDeW2+9ZTp+66238oC8QYMGmfV75pln8pycnEzHe/bsyQPyhg8fbtavT58+Bca8HSAvLCzMrO3q1at5OTk5BeK3tbXNmzZtmqktKSkpD8irW7duXlZWlqn9hRdeyDMYDHmdO3c2G6NFixZ51apVM2urVq2a2fuQP2ZSUpKprX///mbXffvtt3lAXlxcnNlYGzZsMGv/z3/+kwfk7dixo8jncKtq1arlAXlr1qwxtV26dCnP3d09r2HDhqa2d999Nw/IO3DggKktKysrr2rVqrf9fN16r3Xq1Mm7du2aqf2dd97JA/J+/PFHs3gKG69NmzZ5bdq0KTDm3bwnxf05Cw0NzXN3d8/77bffzK7v3bt3nqOjY96VK1fMYvL29ja13UlJfie0adMmz9/fv8gxL168mGc0GvMee+yxvP/9739m53Jzc03/fetnLS+v4M9nSe+7OO9vly5dCsybl5eX161bt2Ldn4g8uLR8T0REROQB9uWXX2Jtbc3IkSPN2seMGUNeXh7r1683a2/RogWNGzc2HXt6etKtWze++uqrEi2zu5OePXuyYsUKQkJC6N69O+Hh4Xz11VecP3+eiIiIezJHcQwdOtTsuFWrVpw/f9607OnLL78EKPDs7nazZFtbW9NePzk5OZw/fx57e3t8fX3ZtWtXgf4hISFm+z499thj5OXlFVgm99hjj3Hq1CmuX79+V/F9/PHHODo60rFjR3777TfTq3Hjxtjb25OUlAT836b0n3/+OdnZ2SWe5+GHH+aZZ54xHTs4OBASEsLu3btN38LYs2dPypcvT1xcnKnfV199xW+//VbsfdMGDhxoVjXUqlUr4EbFWmnd7XtS1M9ZXl4ea9asITg4mLy8PLP3ISgoiEuXLhX4rPTv3x87O7siYy/p74Ti2LRpE3/88Qfjx48vsEdUSZb0lua+7+b9rVSpEj///DM7duwodowi8mBRUkpERETkAXby5EkefvhhjEajWXv+MpyTJ0+atRe2fM7Hx4crV65w7ty5+xbn448/zmOPPUZ8fPx9m+NWnp6eZseVK1cGMO2bdPLkSaysrKhRo4ZZP19f37uaNzc3l7lz51KrVi1sbW2pWrUqzs7O7Nu3j0uXLhUZp6OjIwAeHh4F2nNzcwsdoySOHDnCpUuXcHFxwdnZ2eyVmZnJ2bNnAWjTpg3PPfccU6dOpWrVqnTr1o0VK1bcdg+lW9WsWbNAwsLHxwe4sacR3EgaBAcHm+3xExcXxyOPPMITTzxRrHm
"text/plain": [
"<Figure size 1200x600 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# 29 - Visualisation des top 15 families\n",
"\n",
"top15_plot = top_family_table.head(15).copy()\n",
"\n",
"plt.figure(figsize=(12, 6))\n",
"sns.barplot(data=top15_plot, y=\"fund_family\", x=\"total_family_aum\")\n",
"plt.title(\"Top 15 fund families by total AUM\")\n",
"plt.xlabel(\"Total family AUM\")\n",
"plt.ylabel(\"Fund family\")\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"plt.figure(figsize=(12, 6))\n",
"sns.barplot(data=top15_plot, y=\"fund_family\", x=\"n_clients\")\n",
"plt.title(\"Top 15 fund families by number of clients\")\n",
"plt.xlabel(\"Number of clients\")\n",
"plt.ylabel(\"Fund family\")\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "9b5257a3",
"metadata": {
"id": "9b5257a3"
},
"source": [
"---\n",
"## 10. Performance-sensitive features\n",
"\n",
"We enrich the base table with features that describe the relationship between investor flows and past family performance.\n",
"\n",
"These variables are intended to capture behaviors such as:\n",
"- performance chasing,\n",
"- reactive buying after positive returns,\n",
"- or weak sensitivity to past performance.\n"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "3ae47862",
"metadata": {
"id": "3ae47862",
"outputId": "e03a7458-4af9-4038-b31c-21f8a627b84b"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Performance features merged. Shape: (53891, 53)\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Registrar Account - ID</th>\n",
" <th>fund_family</th>\n",
" <th>corr_flow_ret_3m</th>\n",
" <th>corr_flow_ret_6m</th>\n",
" <th>buy_after_good_perf_share_3m</th>\n",
" <th>buy_after_good_perf_share_6m</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>100000014</td>\n",
" <td>Carmignac Portfolio Climate Transition</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>100000016</td>\n",
" <td>Carmignac Emergents</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>100000016</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>100000028</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>0.258199</td>\n",
" <td>0.258199</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>100000038</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>0.000000</td>\n",
" <td>0.000000</td>\n",
" <td>0.0</td>\n",
" <td>0.0</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Registrar Account - ID fund_family \\\n",
"0 100000014 Carmignac Portfolio Climate Transition \n",
"1 100000016 Carmignac Emergents \n",
"2 100000016 Carmignac Patrimoine \n",
"3 100000028 Carmignac Patrimoine \n",
"4 100000038 Carmignac Patrimoine \n",
"\n",
" corr_flow_ret_3m corr_flow_ret_6m buy_after_good_perf_share_3m \\\n",
"0 0.000000 0.000000 0.0 \n",
"1 0.000000 0.000000 0.0 \n",
"2 0.000000 0.000000 0.0 \n",
"3 0.258199 0.258199 0.0 \n",
"4 0.000000 0.000000 0.0 \n",
"\n",
" buy_after_good_perf_share_6m \n",
"0 0.0 \n",
"1 0.0 \n",
"2 0.0 \n",
"3 0.0 \n",
"4 0.0 "
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Additional performance features for family clustering\n",
"\n",
"# Helper function: correlation between two series if enough valid observations exist\n",
"def safe_corr(x, y, min_obs=6):\n",
" x = pd.Series(x, dtype=float)\n",
" y = pd.Series(y, dtype=float)\n",
" mask = x.notna() & y.notna()\n",
" x = x[mask]\n",
" y = y[mask]\n",
" if len(x) < min_obs or x.nunique() <= 1 or y.nunique() <= 1:\n",
" return np.nan\n",
" return x.corr(y)\n",
"\n",
"tmp_perf = tmp.copy()\n",
"\n",
"# Past family returns already available in tmp:\n",
"# ret_fund_mean3_lag1 and ret_fund_mean6_lag1\n",
"# Build performance-sensitive features at the client × family level\n",
"tmp_perf[\"buy_flag\"] = (tmp_perf[\"net_flow_qty\"] > 0).astype(int)\n",
"tmp_perf[\"good_perf_3m\"] = (tmp_perf[\"ret_fund_mean3_lag1\"] > 0).astype(int)\n",
"tmp_perf[\"good_perf_6m\"] = (tmp_perf[\"ret_fund_mean6_lag1\"] > 0).astype(int)\n",
"\n",
"perf_rows = []\n",
"for (acc, fam), g in tmp_perf.groupby([ID_COL, \"fund_family\"]):\n",
" g = g.sort_values(\"month\")\n",
"\n",
" buy_months = g[\"buy_flag\"].sum()\n",
"\n",
" perf_rows.append({\n",
" ID_COL: acc,\n",
" \"fund_family\": fam,\n",
" \"corr_flow_ret_3m\": safe_corr(g[\"flow_to_aum_m\"], g[\"ret_fund_mean3_lag1\"], min_obs=6),\n",
" \"corr_flow_ret_6m\": safe_corr(g[\"flow_to_aum_m\"], g[\"ret_fund_mean6_lag1\"], min_obs=6),\n",
" \"buy_after_good_perf_share_3m\": (\n",
" ((g[\"buy_flag\"] == 1) & (g[\"good_perf_3m\"] == 1)).sum() / buy_months\n",
" if buy_months > 0 else np.nan\n",
" ),\n",
" \"buy_after_good_perf_share_6m\": (\n",
" ((g[\"buy_flag\"] == 1) & (g[\"good_perf_6m\"] == 1)).sum() / buy_months\n",
" if buy_months > 0 else np.nan\n",
" ),\n",
" })\n",
"\n",
"df_family_perf = pd.DataFrame(perf_rows)\n",
"\n",
"# Merge into final family-level table\n",
"df_family_client_base = df_family_client_base.merge(\n",
" df_family_perf,\n",
" on=[ID_COL, \"fund_family\"],\n",
" how=\"left\"\n",
")\n",
"\n",
"for col in [\"corr_flow_ret_3m\", \"corr_flow_ret_6m\",\n",
" \"buy_after_good_perf_share_3m\", \"buy_after_good_perf_share_6m\"]:\n",
" if col in df_family_client_base.columns:\n",
" df_family_client_base[col] = df_family_client_base[col].fillna(0)\n",
"\n",
"print(\"Performance features merged. Shape:\", df_family_client_base.shape)\n",
"df_family_client_base[\n",
" [ID_COL, \"fund_family\", \"corr_flow_ret_3m\", \"corr_flow_ret_6m\",\n",
" \"buy_after_good_perf_share_3m\", \"buy_after_good_perf_share_6m\"]\n",
"].head()"
]
},
{
"cell_type": "markdown",
"id": "6b781457",
"metadata": {
"id": "6b781457"
},
"source": [
"---\n",
"## 11. Final clustering features\n",
"\n",
"We keep the same family-level features as in the initial notebook, in order to preserve continuity with the previous version of the analysis.\n",
"\n",
"However, their construction is now made more explicit:\n",
"- behavioral ratios rely primarily on quantities,\n",
"- value-based variables are retained for economic interpretation,\n",
"- performance-sensitive variables remain separate and are only imputed at the preprocessing stage."
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "2d120f23",
"metadata": {
"id": "2d120f23",
"outputId": "ee6e596a-46b5-4ae1-dd5f-0fde463c7915"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Number of clustering features: 15\n",
"['flow_freq', 'gross_flow_to_aum_family', 'avg_n_isin_held', 'exit_rate_per_isin_family', 'flow_direction_balance', 'log_family_aum_val_mean', 'months_since_last_tx_family', 'family_share_of_client_aum_mean', 'turnover_mean3_avg', 'turnover_mean6_avg', 'turnover_mean12_avg', 'corr_flow_ret_3m', 'corr_flow_ret_6m', 'buy_after_good_perf_share_3m', 'buy_after_good_perf_share_6m']\n"
]
}
],
"source": [
"# Final clustering features\n",
"\n",
"# Derived ratios closer to the initial notebook\n",
"df_family_client_base[\"log_family_aum_val_mean\"] = np.log1p(\n",
" df_family_client_base[\"family_aum_val_mean\"].clip(lower=0)\n",
")\n",
"\n",
"df_family_client_base[\"gross_flow_to_aum_family\"] = np.where(\n",
" df_family_client_base[\"family_aum_qty_mean\"].abs() > 1,\n",
" df_family_client_base[\"gross_flow_qty_sum\"] / df_family_client_base[\"family_aum_qty_mean\"].abs(),\n",
" np.nan\n",
")\n",
"\n",
"df_family_client_base[\"flow_direction_balance\"] = np.where(\n",
" df_family_client_base[\"gross_flow_qty_sum\"] > 0,\n",
" df_family_client_base[\"net_flow_qty_sum\"] / df_family_client_base[\"gross_flow_qty_sum\"],\n",
" np.nan\n",
")\n",
"\n",
"df_family_client_base[\"exit_rate_per_isin_family\"] = np.where(\n",
" df_family_client_base[\"avg_n_isin_held\"] > 0,\n",
" df_family_client_base[\"full_exit_count\"] / df_family_client_base[\"avg_n_isin_held\"],\n",
" np.nan\n",
")\n",
"\n",
"df_family_client_base[\"family_aum_final_to_peak\"] = np.where(\n",
" df_family_client_base[\"family_aum_qty_max\"] > 0,\n",
" df_family_client_base[\"family_aum_qty_last\"] / df_family_client_base[\"family_aum_qty_max\"],\n",
" np.nan\n",
")\n",
"\n",
"df_family_client_base[\"aum_drawdown_last\"] = df_family_client_base[\"aum_drawdown_last\"].clip(0, 1)\n",
"df_family_client_base[\"family_aum_final_to_peak\"] = df_family_client_base[\"family_aum_final_to_peak\"].clip(0, 1)\n",
"\n",
"# Compact but rich feature list : Final feature list kept\n",
"family_cluster_features = [\n",
" \"flow_freq\",\n",
" \"gross_flow_to_aum_family\",\n",
" \"avg_n_isin_held\",\n",
" \"exit_rate_per_isin_family\",\n",
" \"flow_direction_balance\",\n",
" \"log_family_aum_val_mean\",\n",
" \"months_since_last_tx_family\",\n",
" \"family_share_of_client_aum_mean\",\n",
" \"turnover_mean3_avg\",\n",
" \"turnover_mean6_avg\",\n",
" \"turnover_mean12_avg\",\n",
" \"corr_flow_ret_3m\",\n",
" \"corr_flow_ret_6m\",\n",
" \"buy_after_good_perf_share_3m\",\n",
" \"buy_after_good_perf_share_6m\",\n",
"]\n",
"\n",
"print(\"Number of clustering features:\", len(family_cluster_features))\n",
"print(family_cluster_features)"
]
},
{
"cell_type": "markdown",
"id": "e455f9cf",
"metadata": {
"id": "e455f9cf"
},
"source": [
"---\n",
"## 12. Clustering preprocessing\n",
"\n",
"Before clustering, the feature matrix is prepared as follows:\n",
"\n",
"1. feature-wise median imputation,\n",
"2. MAD-based winsorization on selected skewed variables,\n",
"3. clipping of bounded variables when relevant,\n",
"4. robust scaling.\n",
"\n",
"This preprocessing aims to reduce the influence of outliers while preserving the relative behavioral structure of the data."
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "8b43106b",
"metadata": {
"id": "8b43106b"
},
"outputs": [],
"source": [
"# Robust clustering helpers\n",
"\n",
"from sklearn.decomposition import PCA\n",
"from sklearn.impute import SimpleImputer\n",
"\n",
"def prepare_family_matrix(df_family, features, winsorize_cols=None):\n",
" X = df_family[features].copy()\n",
"\n",
" # Median imputation\n",
" imputer = SimpleImputer(strategy=\"median\")\n",
" X_imp = pd.DataFrame(imputer.fit_transform(X), columns=features, index=X.index)\n",
"\n",
" # Broad winsorization, inspired by the original notebook\n",
" if winsorize_cols is None:\n",
" winsorize_cols = [\n",
" \"gross_flow_to_aum_family\",\n",
" \"avg_n_isin_held\",\n",
" \"exit_rate_per_isin_family\",\n",
" \"months_since_last_tx_family\",\n",
" \"family_share_of_client_aum_mean\",\n",
" \"turnover_mean3_avg\",\n",
" \"turnover_mean6_avg\",\n",
" \"turnover_mean12_avg\",\n",
" ]\n",
"\n",
" for col in winsorize_cols:\n",
" if col in X_imp.columns:\n",
" X_imp[col] = winsorize_mad(X_imp[col], n_sigma=3)\n",
"\n",
" # Variables bounded by construction\n",
" for col in [\n",
" \"flow_freq\",\n",
" \"family_share_of_client_aum_mean\",\n",
" \"buy_after_good_perf_share_3m\",\n",
" \"buy_after_good_perf_share_6m\",\n",
" \"family_aum_final_to_peak\"\n",
" ]:\n",
" if col in X_imp.columns:\n",
" X_imp[col] = np.clip(X_imp[col], 0, 1)\n",
"\n",
" # Correlations should live in [-1, 1]\n",
" for col in [\"corr_flow_ret_3m\", \"corr_flow_ret_6m\", \"flow_direction_balance\"]:\n",
" if col in X_imp.columns:\n",
" X_imp[col] = np.clip(X_imp[col], -1, 1)\n",
"\n",
" # Same logic as in the original notebook:\n",
" # clip and log-transform gross flow intensity\n",
" if \"gross_flow_to_aum_family\" in X_imp.columns:\n",
" vals = X_imp[\"gross_flow_to_aum_family\"].to_numpy(dtype=float)\n",
" vals = np.clip(vals, 0, np.nanpercentile(vals, 90))\n",
" X_imp[\"gross_flow_to_aum_family\"] = np.log1p(vals)\n",
"\n",
" scaler = RobustScaler()\n",
" X_scaled = scaler.fit_transform(X_imp)\n",
"\n",
" return X_imp, X_scaled, imputer, scaler\n",
"\n",
"\n",
"def fit_clustering_model(X_scaled, k, method=\"kmeans\", random_state=42):\n",
" \"\"\"Fit one clustering model and return the fitted model and labels.\"\"\"\n",
" if method == \"kmeans\":\n",
" model = KMeans(n_clusters=k, random_state=random_state, n_init=30)\n",
" labels = model.fit_predict(X_scaled)\n",
" inertia = model.inertia_\n",
"\n",
" elif method == \"gmm\":\n",
" model = GaussianMixture(\n",
" n_components=k,\n",
" covariance_type=\"full\",\n",
" random_state=random_state,\n",
" n_init=5\n",
" )\n",
" labels = model.fit_predict(X_scaled)\n",
"\n",
" # proxy inertia for plotting consistency: within-cluster SSE around empirical centroids\n",
" inertia = 0.0\n",
" for cl in np.unique(labels):\n",
" pts = X_scaled[labels == cl]\n",
" center = pts.mean(axis=0)\n",
" inertia += ((pts - center) ** 2).sum()\n",
"\n",
" elif method == \"agglo\":\n",
" model = AgglomerativeClustering(n_clusters=k, linkage=\"ward\")\n",
" labels = model.fit_predict(X_scaled)\n",
"\n",
" # proxy inertia for plotting consistency\n",
" inertia = 0.0\n",
" for cl in np.unique(labels):\n",
" pts = X_scaled[labels == cl]\n",
" center = pts.mean(axis=0)\n",
" inertia += ((pts - center) ** 2).sum()\n",
"\n",
" else:\n",
" raise ValueError(f\"Unknown method: {method}\")\n",
"\n",
" return model, labels, inertia\n",
"\n",
"\n",
"def evaluate_k_range(\n",
" X_scaled,\n",
" k_min=2,\n",
" k_max=6,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" method=\"kmeans\",\n",
" random_state=42\n",
"):\n",
" n = X_scaled.shape[0]\n",
" k_max = min(k_max, max(2, n - 1))\n",
"\n",
" rows = []\n",
" for k in range(k_min, k_max + 1):\n",
" if k >= n:\n",
" continue\n",
"\n",
" _, labels, inertia = fit_clustering_model(\n",
" X_scaled,\n",
" k=k,\n",
" method=method,\n",
" random_state=random_state\n",
" )\n",
"\n",
" cluster_sizes = pd.Series(labels).value_counts().sort_index()\n",
" min_size = int(cluster_sizes.min())\n",
" min_size_required = max(min_cluster_size, int(np.ceil(min_cluster_share * n)))\n",
"\n",
" valid = (min_size >= min_size_required)\n",
"\n",
" if valid and len(np.unique(labels)) >= 2:\n",
" sil = silhouette_score(X_scaled, labels)\n",
" dbi = davies_bouldin_score(X_scaled, labels)\n",
" else:\n",
" sil = np.nan\n",
" dbi = np.nan\n",
"\n",
" rows.append({\n",
" \"k\": k,\n",
" \"silhouette\": sil,\n",
" \"davies_bouldin\": dbi,\n",
" \"min_cluster_size\": min_size,\n",
" \"min_cluster_required\": min_size_required,\n",
" \"inertia\": inertia,\n",
" \"valid_k\": valid\n",
" })\n",
"\n",
" return pd.DataFrame(rows)\n",
"\n",
"\n",
"def choose_best_k(metrics_df):\n",
" valid = metrics_df[metrics_df[\"valid_k\"]].dropna(subset=[\"silhouette\"]).copy()\n",
" if len(valid) == 0:\n",
" return None\n",
" return int(valid.sort_values([\"silhouette\", \"davies_bouldin\"], ascending=[False, True]).iloc[0][\"k\"])\n",
"\n",
"\n",
"def compare_methods_for_family(\n",
" df_base,\n",
" family_name,\n",
" features,\n",
" methods=(\"kmeans\", \"gmm\", \"agglo\"),\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=42\n",
"):\n",
" rows = []\n",
"\n",
" for method in methods:\n",
" res = run_family_clustering(\n",
" df_base=df_base,\n",
" family_name=family_name,\n",
" features=features,\n",
" method=method,\n",
" k_min=k_min,\n",
" k_max=k_max,\n",
" min_clients=min_clients,\n",
" min_cluster_size=min_cluster_size,\n",
" min_cluster_share=min_cluster_share,\n",
" random_state=random_state,\n",
" make_plots=False\n",
" )\n",
"\n",
" if res is None:\n",
" rows.append({\n",
" \"method\": method,\n",
" \"family\": family_name,\n",
" \"n_clients\": np.nan,\n",
" \"best_k\": np.nan,\n",
" \"silhouette\": np.nan,\n",
" \"davies_bouldin\": np.nan,\n",
" \"min_cluster_size\": np.nan,\n",
" \"status\": \"skip\"\n",
" })\n",
" continue\n",
"\n",
" best_row = res[\"metrics_df\"].loc[res[\"metrics_df\"][\"k\"] == res[\"best_k\"]].iloc[0]\n",
" rows.append({\n",
" \"method\": method,\n",
" \"family\": family_name,\n",
" \"n_clients\": res[\"n_clients\"],\n",
" \"best_k\": res[\"best_k\"],\n",
" \"silhouette\": best_row[\"silhouette\"],\n",
" \"davies_bouldin\": best_row[\"davies_bouldin\"],\n",
" \"min_cluster_size\": int(best_row[\"min_cluster_size\"]),\n",
" \"status\": \"ok\"\n",
" })\n",
"\n",
" return pd.DataFrame(rows)\n"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "ceb97cfd",
"metadata": {
"id": "ceb97cfd"
},
"outputs": [],
"source": [
"# Family clustering pipeline\n",
"\n",
"def run_family_clustering(\n",
" df_base,\n",
" family_name,\n",
" features,\n",
" method=\"kmeans\",\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=42,\n",
" make_plots=True\n",
"):\n",
" df_family = df_base[df_base[\"fund_family\"] == family_name].copy()\n",
"\n",
" # Quality filters\n",
" df_family = df_family[\n",
" (df_family[\"n_months\"] >= 6) &\n",
" (df_family[\"family_aum_val_mean\"] > 0)\n",
" ].copy()\n",
"\n",
" # Stronger quantile filtering\n",
" for col in [\"family_aum_val_mean\", \"gross_flow_qty_sum\", \"n_tx_total\"]:\n",
" if col in df_family.columns and df_family[col].notna().sum() > 0:\n",
" cap = df_family[col].quantile(0.99)\n",
" df_family = df_family[df_family[col] <= cap].copy()\n",
"\n",
" n_clients = df_family[ID_COL].nunique()\n",
" if n_clients < min_clients:\n",
" print(f\"[SKIP] {family_name} ({method}): only {n_clients} usable clients.\")\n",
" return None\n",
"\n",
" X_imp, X_scaled, imputer, scaler = prepare_family_matrix(df_family, features)\n",
"\n",
" metrics_df = evaluate_k_range(\n",
" X_scaled,\n",
" k_min=k_min,\n",
" k_max=k_max,\n",
" min_cluster_size=min_cluster_size,\n",
" min_cluster_share=min_cluster_share,\n",
" method=method,\n",
" random_state=random_state\n",
" )\n",
"\n",
" if len(metrics_df) == 0:\n",
" print(f\"[SKIP] {family_name} ({method}): no K evaluated.\")\n",
" return None\n",
"\n",
" best_k = choose_best_k(metrics_df)\n",
" if best_k is None:\n",
" print(f\"[SKIP] {family_name} ({method}): no valid K with cluster size constraints.\")\n",
" return None\n",
"\n",
" model, labels, _ = fit_clustering_model(\n",
" X_scaled,\n",
" k=best_k,\n",
" method=method,\n",
" random_state=random_state\n",
" )\n",
"\n",
" df_family[\"cluster\"] = labels\n",
"\n",
" cluster_sizes = (\n",
" df_family[\"cluster\"]\n",
" .value_counts()\n",
" .sort_index()\n",
" .rename_axis(\"cluster\")\n",
" .reset_index(name=\"n_clients\")\n",
" )\n",
"\n",
" cluster_profile = (\n",
" df_family.groupby(\"cluster\")[features]\n",
" .median()\n",
" .sort_index()\n",
" ) # median feature values by cluster\n",
"\n",
" # Churn proxies at family level\n",
" df_family[\"churn_hard\"] = (df_family[\"family_aum_final_to_peak\"] < 0.10).astype(int)\n",
" df_family[\"churn_soft\"] = (\n",
" (df_family[\"family_aum_final_to_peak\"] < 0.40) &\n",
" (df_family[\"aum_drawdown_last\"] > 0.40)\n",
" ).astype(int)\n",
" df_family[\"churn_warning\"] = (\n",
" (df_family[\"flow_direction_balance\"] < 0) &\n",
" (df_family[\"aum_drawdown_last\"] > 0.20)\n",
" ).astype(int)\n",
"\n",
" churn_profile = (\n",
" df_family.groupby(\"cluster\")[[\"churn_hard\", \"churn_soft\", \"churn_warning\"]]\n",
" .mean()\n",
" .sort_index()\n",
" )\n",
"\n",
" # PCA for visualization only\n",
" pca = PCA(n_components=2, random_state=random_state)\n",
" coords = pca.fit_transform(X_scaled)\n",
" df_family[\"pca1\"] = coords[:, 0]\n",
" df_family[\"pca2\"] = coords[:, 1]\n",
"\n",
" result = {\n",
" \"family\": family_name,\n",
" \"method\": method,\n",
" \"n_clients\": n_clients,\n",
" \"best_k\": best_k,\n",
" \"metrics_df\": metrics_df,\n",
" \"df_family\": df_family,\n",
" \"cluster_profile\": cluster_profile,\n",
" \"cluster_sizes\": cluster_sizes,\n",
" \"churn_profile\": churn_profile,\n",
" \"features\": features,\n",
" \"pca_explained_var\": pca.explained_variance_ratio_,\n",
" }\n",
"\n",
" if make_plots:\n",
" fig, axes = plt.subplots(1, 3, figsize=(15, 4))\n",
" axes[0].plot(metrics_df[\"k\"], metrics_df[\"silhouette\"], marker=\"o\")\n",
" axes[0].set_title(f\"{family_name} - {method} - Silhouette\")\n",
" axes[0].set_xlabel(\"k\")\n",
"\n",
" axes[1].plot(metrics_df[\"k\"], metrics_df[\"davies_bouldin\"], marker=\"o\")\n",
" axes[1].set_title(f\"{family_name} - {method} - Davies-Bouldin\")\n",
" axes[1].set_xlabel(\"k\")\n",
"\n",
" axes[2].plot(metrics_df[\"k\"], metrics_df[\"inertia\"], marker=\"o\")\n",
" axes[2].set_title(f\"{family_name} - {method} - Inertia / proxy SSE\")\n",
" axes[2].set_xlabel(\"k\")\n",
" plt.tight_layout()\n",
" plt.show()\n",
"\n",
" plot_heatmap(\n",
" df_family,\n",
" profile_vars=features,\n",
" cluster_col=\"cluster\",\n",
" title=f\"{family_name} - {method} - Cluster signatures\",\n",
" figsize=(18, 5)\n",
" )\n",
"\n",
" plt.figure(figsize=(7, 5))\n",
" sns.scatterplot(\n",
" data=df_family,\n",
" x=\"pca1\", y=\"pca2\",\n",
" hue=\"cluster\",\n",
" palette=\"tab10\",\n",
" alpha=0.8\n",
" )\n",
" plt.title(\n",
" f\"{family_name} - {method} - PCA projection \"\n",
" f\"(explained var: {result['pca_explained_var'][0]:.2f}, {result['pca_explained_var'][1]:.2f})\"\n",
" )\n",
" plt.tight_layout()\n",
" plt.show()\n",
"\n",
" plt.figure(figsize=(6, 4))\n",
" sns.barplot(data=cluster_sizes, x=\"cluster\", y=\"n_clients\")\n",
" plt.title(f\"{family_name} - {method} - Cluster sizes\")\n",
" plt.tight_layout()\n",
" plt.show()\n",
"\n",
" churn_long = churn_profile.reset_index().melt(\n",
" id_vars=\"cluster\",\n",
" value_vars=[\"churn_hard\", \"churn_soft\", \"churn_warning\"],\n",
" var_name=\"churn_type\",\n",
" value_name=\"rate\"\n",
" )\n",
"\n",
" plt.figure(figsize=(8, 4))\n",
" sns.barplot(data=churn_long, x=\"cluster\", y=\"rate\", hue=\"churn_type\")\n",
" plt.title(f\"{family_name} - {method} - Churn analysis by cluster\")\n",
" plt.ylabel(\"Rate\")\n",
" plt.tight_layout()\n",
" plt.show()\n",
"\n",
" print(f\"\\n=== {family_name} | method={method} ===\")\n",
" print(f\"Clients after filtering: {n_clients}\")\n",
" print(f\"Chosen K: {best_k}\")\n",
" print(cluster_sizes)\n",
" print(\"\\nChurn profile:\")\n",
" print(churn_profile.round(3))\n",
"\n",
" return result\n"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "b1161a03",
"metadata": {
"id": "b1161a03",
"outputId": "2166c9db-fcde-40b9-eb97-8c49c8de095c"
},
"outputs": [
{
"data": {
"image/png": "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RAcAAAAAAOm2evVq+fv7JxsNmJqwsDC98MILat68uezs7LR69Wr16dNHRqNRffv2tah77NgxtW/fXj179lSPHj0sEjChoaFycnLSkCFDdPLkSU2ZMkXZsmWTjY2Nrl+/rpEjR+rXX3/V3LlzVahQIQ0fPjzVmM6fP29OHg8dOlTOzs76+uuvUx3pfPLkSb366qvq1q2bOnfurNmzZ6tLly4KCgrSCy+8IOleUuqHH35Q69atVahQIV26dEnTp09XrVq1dPjwYeXNm1eSlJiYqKZNm2rz5s1q166dBg4cqJiYGG3cuFGHDh1SQEBAmo7r/U6dOiVbW1u5u7tr7dq12rlzp9q1a6f8+fMrIiJCYWFhql27tg4fPqzs2bOrZs2aGjBggL744gsNGzZMJUqUkCTzfx92LlLSv39/+fj4aNSoUfr11181Y8YMubu7a+fOnSpQoIDGjh2rtWvXasKECQoMDDQn50wmk5o3b66tW7eqW7duKlu2rNavX6933nlH58+f1+eff/7Q9vfv3185c+bUiBEjFBERoUmTJqlfv35aunSpuc6CBQvUuXNnBQcHa/z48bp165bCwsJUvXp1/f777+ma0iY9bt++rRYtWmjv3r3atGmTKlasaPF+27ZtVaJECY0bN05r1qzRRx99JA8PD02fPl1169bV+PHjtWjRIr399tuqWLGiatasKUkyGo1q3ry5tm/frjfeeEMlSpTQwYMH9fnnn+v48eP64YcfzPtIzzWYls/6yJEjFRoaqu7du6tSpUqKjo7W3r17tX//ftWvXz9TjuP9Mvp83717V8HBwapevbo+/fRTZc+eXT4+PoqKitLff/9t/gzeP13If23cuFGnTp1SSEiIfHx8zFNa/fXXX/r1119lMBge2q61a9eqadOmaToG/fr1k7u7u0aOHKljx44pLCxMZ86cMf/omCSl6/jSpUuqWrWqbt26pQEDBihXrlyaN2+emjdvrhUrVqhVq1YqUaKExowZo3feeUevvvqqmjdvrtjYWHXp0kXFixfX6NGjJUkdO3bU/PnztX79eovYL168qC1btmjEiBGptsHb21tOTk5avXq1+vfvLw8Pj1TrFixYUImJiebzmhZXrlxJVmZvby9XV9c0rW9mAgAAAAAASIeoqCiTJFOLFi3SvM6tW7eSlQUHB5v8/f0tygoWLGiSZFq3bp1F+datW02STIGBgaaEhARzefv27U0Gg8HUqFEji/pVqlQxFSxYMNm2O3fubH7dv39/k8FgMP3+++/msqtXr5o8PDxMkkynT59OFtfPP/9sLouMjDQ5ODiY3nrrLXNZXFycKTEx0WK/p0+fNjk4OJhGjx5tLps9e7ZJkmnixInJjovRaExWdr9atWqZihcvbrp8+bLp8uXLpiNHjpgGDBhgkmRq1qyZyWRK+Xjv2rXLJMk0f/58c9ny5ctNkkxbt25NVj+1c5H03v3Hcs6cOSZJpuDgYIv4q1SpYjIYDKZevXqZy+7evWvKnz+/qVatWuayH374wSTJ9NFHH1ns59VXXzUZDAbTyZMnH7rvevXqWez7zTffNNna2ppu3LhhMplMppiYGJO7u7upR48eFvu4ePGiyc3NLVn540j6vC5fvtwUExNjqlWrlsnT09Pis2YymUwjRowwSTK98cYb5rKk42MwGEz
"text/plain": [
"<Figure size 1500x400 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABiYAAAHpCAYAAAAGQYQ4AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3XVYVFkfB/DvDC3d3SUIimsXWGuttb62a3e71orY3bF2d2N3YufanViIdLfMff9AR0dAAYEhvp/nuc/unHvuub9zZrjeuWfOOSJBEAQQERERERERERERERHlA7G8AyAiIiIiIiIiIiIiouKDHRNERERERERERERERJRv2DFBRERERERERERERET5hh0TRERERERERERERESUb9gxQURERERERERERERE+YYdE0RERERERERERERElG/YMUFERERERERERERERPmGHRNERERERERERERERJRv2DFBRERERERERERERET5hh0TREREVCzY2NigS5cu8g6jSJBnWxaG9/Hs2bMQiUTw9fWVdyjFSpcuXWBjYyPvMPLV69evIRKJsH79enmHQkRERESULeyYICIiohx7+fIlevfuDTs7O6iqqkJLSwvVqlXDwoULkZCQIO/wiqSaNWtCJBJJNz09PVSoUAFr166FRCLJVlmPHj3ChAkT8Pr167wJligXREdHY+LEiShTpgw0NDSgpqYGNzc3/PPPP/jw4UO+xbF06VJ2APzE5cuXMWHCBERGRso7FCIiIiIq4BTlHQAREREVTocPH0arVq2goqKCTp06wc3NDcnJybh48SJGjBiBhw8fYuXKlfIOU+rp06cQi4vGbzIsLCwwffp0AEBISAg2btyI7t2749mzZ5gxY0aWy3n06BEmTpyImjVrZuuX5vJsy6L0PtLPvXr1CnXr1sXbt2/RqlUr9OrVC8rKyrh37x7WrFmDvXv34tmzZ/kSy9KlS2FgYFCgRuxYW1sjISEBSkpK8g4FQFrHxMSJE9GlSxfo6OjIOxwiIiIiKsDYMUFERETZ5u/vj7Zt28La2hpnzpyBqampdF///v3x4sULHD58+JfPIwgCEhMToaam9stlqaio/HIZBYW2tjb++usv6evevXvD2dkZixcvxuTJk/PkIeW374U827IovY/0Y58+fUKLFi0QFBSEs2fPonr16jL7p06dipkzZ8oputzx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
"text/plain": [
"<Figure size 1800x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAr8AAAHqCAYAAAANsiY3AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAA+xZJREFUeJzs3XecU8XawPHfSc9mN9sru7Qt9A4iIlIFFBBUVLwW5LUXvNj1elXser32gh0UsYHXSlFpVnrvZanbe7K76cm8f8SNhC0ssIWF+d4Pn+vOnJwzSU5OnsyZeUYRQggkSZIkSZIk6Qygau4GSJIkSZIkSVJTkcGvJEmSJEmSdMaQwa8kSZIkSZJ0xpDBryRJkiRJknTGkMGvJEmSJEmSdMaQwa8kSZIkSZJ0xpDBryRJkiRJknTGkMGvJEmSJEmSdMaQwa8kSZIkSZJ0xpDBbwvVtm1brrvuuuZuxmmhOV/LlvA+Ll++HEVRmDdvXnM3RToNDBkyhCFDhjT5cavO4+XLlzf5sQF8Ph9du3bl6aefbpbjH01RFKZPn37cj2vu1/FE2y2dfhYtWkRoaCiFhYXH/VgZ/B4hMzOTm2++mfbt22MwGDCbzQwcOJBXX30Vu93e3M07LQ0ZMgRFUQL/oqKi6NevHx9++CE+n++49rV9+3amT5/OgQMHGqexknQSDhw4EHSuq9VqWrduzcUXX8zGjRurbe9wOHj55Zfp378/4eHhGAwGMjIyuOOOO9i9e3eNx7j//vtRFIUrrriikZ/Nqeutt95i1qxZzd2Maj777DMOHz7MHXfc0dxNkZpJbm4uDz74IEOHDiUsLOyEfkRkZ2dz+eWXExERgdlsZvz48ezbt6/GbT/44AM6deqEwWAgPT2d119//aSfw3fffUfv3r0xGAy0bt2axx57DI/HU6/H+nw+/vOf/9CuXTsMBgPdu3fns88+q3HbHTt2MHr0aEJDQ4mKiuKaa66pFuSOHj2atLQ0nn322eN/IkISQgjxww8/CKPRKCIiIsSdd94p3n33XfHGG2+ISZMmCa1WK2688cbmbmIQh8MhXC5XczfjpA0ePFgkJyeL2bNni9mzZ4uXXnpJ9OzZUwDigQceOK59zZ07VwBi2bJlx/W45nwtW8L7uGzZMgGIuXPnNndTWrT9+/cLQFx55ZVi9uzZYtasWeKBBx4QZrNZ6PV6sWHDhsC2hYWFok+fPgIQY8eOFa+88op4//33xX333SdSUlKEVquttn+fzyeSk5NF27ZthdFoFFartQmfXf05nU7hdDobbf9dunQRgwcPrlbu9XqF3W4XXq+30Y5dlx49eoibbrqpWY5dE0A89thjx/245n4dT7Tdp4Kqa2l6eroYMGDAcX9flZeXi/T0dBEXFyeef/558dJLL4mUlBSRnJwsioqKgrZ9++23BSAuvfRS8e6774prrrlGAOK555474fYvWLBAKIoihg4dKt59910xdepUoVKpxC233FKvxz/44IMCEDfeeKN49913xZgxYwQgPvvss6DtDh8+LGJiYkRqaqp49dVXxdNPPy0iIyNFjx49ql073nrrLRESEnLc1zsZ/Aoh9u3bJ0JDQ0XHjh1FTk5Otfo9e/aIV1555aSP4/P5hM1mO+n9nE4GDx4sunTpElRWWVkpkpOThclkOq7A8HiCX/le1J8MfhtGVfD7wgsvBJV/9913AggKjMaMGSNUKpWYN29etf04HA5xzz33VCtfunSpAMTSpUuFVqsVs2bNavgnUYOKioomOU591Rb8Nqf169cLQCxevLi5mxLQUoPIU6XdJ/IDwGq1iuLiYiHEiXXWPP/88wIQq1evDpTt2LFDqNVq8dBDDwXKbDabiI6OFmPGjAl6/FVXXSVMJpMoKSk5rnZX6dy5s+jRo4dwu92BsocfflgoiiJ27NhR52OzsrKEVqsVt99+e6DM5/OJQYMGieTkZOHxeALlt956qzAajeLgwYOBsp9//lkA4p133gnab35+vlCr1eKDDz44rucig18hxC233CIA8ccff9Rr+w8//FAMHTpUxMbGCp1OJzp16iTeeuutatu1adNGjBkzRixatEj06dNH6PV68fLLLweCiS+++EJMnz5dJCUlidDQUHHppZeKsrIy4XA4xD//+U8RGxsrTCaTuO6664TD4ai278mTJweVbdq0SZx33nnCYDCIVq1aiSeffFJ8+OGHAhD79++v1q7ffvtN9OvXT+j1etGuXTvx0UcfBe2vuLhY3HPPPaJr167CZDKJsLAwMXr0aLFx48Zqz9Vut4vHHntMpKenC71eLxISEsTFF18s9u7dW+drWVPwK4QQEydOFIDIzs4WBw4cELfeeqvIyMgQBoNBREVFiYkTJwY9p5kzZwqg2r+qC0tt70VNr2XVvn777TcxdepUERMTI8LDw8VNN90knE6nKC0tFddcc42IiIgQERER4r777hM+ny+o/RUVFeLuu+8WycnJQqfTiYyMDPHCCy9U2662Y//+++/irrvuEjExMSIkJERMmDBBFBQUVHudFixYIM4991wREhIiQkNDxYUXXii2bt1a52t+vGoKfh0OhxgzZowwm82Bz81jjz0mALFr1y5x1VVXCbPZLGJiYsS///1v4fP5xKFDh8RFF10kwsLCRHx8vPjvf/9b7VgOh0M8+uijIjU1Veh0OpGcnCzuu+++auf/8X4Gj3Wuu1wuMX36dJGWlib0er2IiooSAwcOFD/99FNDvIRCiNqD34qKCgGI888/XwghxMqVKwO9I8fj+uuvF507dxZCCHHBBRcE9lcfgLj99tvFJ598IjIyMoRerxe9e/cWv/zyS9B2Ve/xtm3bxJVXXikiIiJEz549hRBCuN1u8cQTT4j27dsLnU4n2rRpIx566KFq793gwYOrBaf1fd+FEGL27NmiX79+gTt1gwYNEj/++KMQwv9+H30NqDpW1Xl8dLDx5Zdfit69ewuDwSCio6PFVVddJbKysoK2mTx5sjCZTCIrK0uMHz9emEwmERMTI+65556gL+3aPProo0Kn09X4Yz4rK0tMmTJFxMXFCZ1OJzp37hz0RW6z2USHDh1Ehw4dgn6wFxcXi4SEBDFgwIBAG6ramZmZKUaOHClCQkJEYmKiePzxx6tde44OIutzna3tday6jm/btk0MGTJEGI1GkZSUJJ5//vlqz7e+77XD4RDTpk0TMTExIjQ0VIwbN04cPnz4mMFvXl6eUKvVYvr06dXqdu7cKQDx+uuvB17D+nzHVT3nzz77TDz88MMiKSlJKIoiSktLhcvlEjt27Kix46wuJxL89uvXT/Tr169a+ciRI0Vqamrg7/nz5wtAzJ8/P2i7P//8UwBi9uzZx9VWIYTYtm2bAMSbb74ZVJ6dnS0A8eSTT9b5+DfffDNw7TjSp59+Gvi+rRIXFycuu+yyavvIyMgQw4cPr1beq1cvcdFFFx3P0xGa4x8ocfr5/vvvad++Peecc069tp8xYwZdunThoosuQqPR8P3333Pbbbfh8/m4/fbbg7bdtWsXV155JTfffDM33ngjHTp0CNQ9++yzGI1GHnzwQfbu3cvrr7+OVqtFpVJRWlrK9OnTWblyJbNmzaJdu3Y8+uijtbYpOzuboUOHoigKDz30ECaTiffffx+9Xl/j9nv37mXixIlcf/31TJ48mQ8//JDrrruOPn360KVLFwD27dvHN998w2WXXUa7du3Iz8/nnXfeYfDgwWzfvp2kpCQAvF4vY8eOZcmSJUyaNIl//vOflJeX8/PPP7N161ZSU1Pr9boead++fajVaiIiIliwYAF//vknkyZNIjk5mQMHDjBjxgyGDBnC9u3bCQkJ4bzzzuPOO+/ktdde41//+hedOnUCCPz/sd6LmkydOpWEhAQef/xxVq5cybvvvktERAR//vknrVu35plnnmHBggW88MILdO3alWuvvRYAIQQXXXQRy5Yt4/rrr6dnz578+OOP3HfffWRnZ/Pyyy8f8/lPnTqVyMhIHnvsMQ4cOMArr7zCHXfcwRdffBHYZvbs2UyePJlRo0bx/PPPY7PZmDFjBueeey4bNmy
"text/plain": [
"<Figure size 700x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAk4AAAGGCAYAAACNCg6xAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAPiFJREFUeJzt3X98zfX///H7MXY2P3Zm2GYfwxA2v6PW8ptlCRH9UDKJ5NOmtybkXWFSC+VHhH6xN1HSOyoKM7/eMRW1/MrPaN5lm/zYbBi21/ePPjtfxzZem3E2btfL5Vxynq/neb0er9frvDr3vc7z9ToWwzAMAQAA4JrKOLsAAACA0oLgBAAAYBLBCQAAwCSCEwAAgEkEJwAAAJMITgAAACYRnAAAAEwiOAEAAJhEcAIAADCJ4IRbRu3atfXUU085u4xbgjO3ZWnYjxs2bJDFYtHnn3/u7FJuK0899ZRq167t7DJuqiNHjshisSg2NtbZpeD/EJxwVYcOHdKzzz6rOnXqyM3NTR4eHmrdurVmzJihc+fOObu8W1KHDh1ksVjsDy8vL911112aN2+ecnJyCjWvPXv2aPz48Tpy5MiNKRYoBunp6YqOjlazZs1UsWJFubu7q3Hjxho9erT+/PPPm1bH7NmzCSi4prLOLgAl18qVK/XII4/IarUqPDxcjRs31oULF/Tdd99p5MiR2r17t95//31nl2m3b98+lSlza/wtUKNGDcXExEiSjh8/rgULFmjQoEHav3+/3nzzTdPz2bNnj6Kjo9WhQ4dC/aXuzG15K+1HXNtvv/2m0NBQJSUl6ZFHHtGQIUPk6uqqHTt26KOPPtKyZcu0f//+m1LL7NmzVbVq1RJ1xrNWrVo6d+6cypUr5+xS8H8ITsjX4cOH1bdvX9WqVUvr1q1T9erV7dMiIiJ08OBBrVy58rqXYxiGzp8/L3d39+uel9Vqve55lBQ2m01PPvmk/fmzzz6rBg0aaNasWXrttdduyP9EL98XztyWt9J+xNVdunRJvXv3VkpKijZs2KA2bdo4TH/99dc1adIkJ1VXPC5duqScnBy5uroW6fUWi0Vubm7FXBWuB3/WIV+TJ09WRkaGPvroI4fQlKtevXr6xz/+YX8+f/58derUSd7e3rJarQoKCtKcOXPyvK527drq3r27Vq9erVatWsnd3V3vvfeefczIZ599pujoaP3P//yPKlWqpIcfflhpaWnKysrS8OHD5e3trYoVK2rgwIHKysrKM+8r/1LcsWOH2rdvL3d3d9WoUUMTJ07U/PnzZbFYHL6+yq3ru+++09133y03NzfVqVNHCxYscJjfyZMn9eKLL6pJkyaqWLGiPDw81LVrV/3yyy951vX8+fMaP3686tevLzc3N1WvXl29e/fWoUOHzOwCB+XLl9c999yjzMxMHT9+XL///ruee+45NWjQQO7u7qpSpYoeeeQRh3WKjY3VI488Iknq2LGj/au/DRs2XHVf5LctY2NjZbFY9N133+n5559XtWrV5OnpqWeffVYXLlzQ6dOnFR4ersqVK6ty5coaNWqUDMNwWIfMzEyNGDFC/v7+slqtatCggd566608/Qpa9ubNmxUVFaVq1aqpQoUKeuihh3T8+PE82+rbb79V27ZtVaFCBVWqVEndunXT7t27C73NCysrK0vdu3eXzWbTli1bJEnjx4+XxWLR/v379eSTT8pms6latWp69dVXZRiGjh49qp49e8rDw0O+vr56++23853vuHHjVK9ePVmtVvn7+2vUqFF53v+FPQav9V6/ePGioqOjdccdd8jNzU1VqlRRmzZtFBcXV2zb7N///rd++eUXvfzyy3lCkyR5eHjo9ddfL/D1uf/fyH1P58pvXFBycrIGDhyoGjVqyGq1qnr16urZs6f9mKldu7Z2796tjRs32o+VDh062F9/+vRpDR8+3P7+rVevniZNmuTw9Xnuct966y1Nnz5ddevWldVq1Z49ewpch7i4OLVp00aenp6qWLGiGjRooH/+858FrkvuOuf3uPKssplj4VrbBXlxxgn5+vrrr1WnTh3de++9pvrPmTNHjRo10oMPPqiyZcvq66+/1nPPPaecnBxFREQ49N23b58ef/xxPfvss3rmmWfUoEED+7SYmBi5u7vrpZde0sGDBzVz5kyVK1dOZcqU0alTpzR+/Hht3bpVsbGxCggI0NixYwus6Y8//rAHhjFjxqhChQr68MMPCzyjcfDgQT388MMaNGiQBgwYoHnz5umpp55Sy5Yt1ahRI0l/f62wfPlyPfLIIwoICFBKSoree+89tW/fXnv27JGfn58kKTs7W927d1d8fLz69u2rf/zjHzpz5ozi4uK0a9cu1a1b19R2vdxvv/0mFxcXeXp66ptvvtGWLVvUt29f1ahRQ0eOHNGcOXPUoUMH7dmzR+XLl1e7du30/PPP65133tE///lPBQYGSpL9v9faF/kZNmyYfH19FR0dra1bt+r999+Xp6entmzZopo1a+qNN97QN998oylTpqhx48YKDw+X9PfZrAcffFDr16/XoEGD1Lx5c61evVojR47UH3/8oWnTpl1z/YcNG6bKlStr3LhxOnLkiKZPn67IyEgtWbLE3mfhwoUaMGCAwsLCNGnSJJ09e1Zz5sxRmzZt9PPPP9+wgcXnzp1Tz549tW3bNq1du1Z33XWXw/THHntMgYGBevPNN7Vy5UpNnDhRXl5eeu+999SpUydNmjRJixYt0osvvqi77rpL7dq1kyTl5OTowQcf1HfffachQ4YoMDBQO3fu1LRp07R//34tX77cvozCHINm3uvjx49XTEyMBg8erLvvvlvp6enatm2bfvrpJ913333Fst2++uorSVL//v2LZX5X06dPH+3evVvDhg1T7dq1lZqaqri4OCUlJal27dqaPn26hg0bpooVK+rll1+WJPn4+EiSzp49q/bt2+uPP/7Qs88+q5o1a2rLli0aM2aMjh07punTpzssa/78+Tp//ryGDBkiq9UqLy+vfGvavXu3unfvrqZNm2rChAmyWq06ePCgNm/eXOB6BAYGauHChQ5tp0+fVlRUlLy9ve1tZo+Fa20X5MMArpCWlmZIMnr27Gn6NWfPns3TFhYWZtSpU8ehrVatWoYkY9WqVQ7t69evNyQZjRs3Ni5cuGBvf/zxxw2LxWJ07drVoX9ISIhRq1atPPMeMGCA/fmwYcMMi8Vi/Pzzz/a2EydOGF5eXoYk4/Dhw3nq2rRpk70tNTXVsFqtxogRI+xt58+fN7Kzsx2We/jwYcNqtRoTJkywt82bN8+QZEydOjXPdsnJycnTdrn27dsbDRs2NI4fP24cP37c+PXXX43nn3/ekGT06NHDMIz8t3dCQoIhyViwYIG9benSpYYkY/369Xn6F7Qvcqddvi3nz59vSDLCwsIc6g8JCTEsFosxdOhQe9ulS5eMGjVqGO3bt7e3LV++3JBkTJw40WE5Dz/8sGGxWIyDBw9ec9mhoaEOy37hhRcMFxcX4/Tp04ZhGMaZM2cMT09P45lnnnFYRnJysmGz2fK0X4/c9+vSpUuNM2fOGO3btzeqVq3q8F4zDMMYN26cIckYMmSIvS13+1gsFuPNN9+0t586dcpwd3d3WPeFCxcaZcqUMf7zn/84zHfu3LmGJGPz5s32tsIeg9d6rzdr1szo1q2buQ1SRC1atDBsNpvp/gMGDHA47nP3w5Xv78OHDxuSjPnz5xuG8fe2lWRMmTLlqvNv1KiRw/s212uvvWZUqFDB2L9/v0P7Sy+9ZLi4uBhJSUkOy/Xw8DBSU1OvuT7Tpk0zJBnHjx8vsM+V63KlnJwco3v37kbFihWN3bt3G4Zh/lgwu13giK/qkEd6erokqVKlSqZfc/kYpbS0NP31119q3769fvvtN6WlpTn0DQgIUFhYWL7zCQ8Pdxi/ExwcLMMw9PTTTzv0Cw4O1tGjR3Xp0qUCa1q1apVCQkLUvHlze5uXl5f69euXb/+goCC1bdvW/rxatWpq0KCBfvvtN3ub1Wq1D1zOzs7WiRMn7KfXf/rpJ3u/f//736pataqGDRuWZzkWi6X
"text/plain": [
"<Figure size 600x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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cePGORp/7ty5qlWrlp599lkVK1ZMX331lXr37q20tDT16dPHbNw///xTnTp10htvvKGePXuqevXqpmERERFydHTUsGHDdPToUX344YcqXry4bGxs9O+//2rs2LHatWuXli1bpkqVKmn06NFZ1nT69GnTF+rhw4fL2dlZixYtyvIX8aNHj+rFF19U9+7d1bVrVy1ZskTdunVT/fr1VatWLUm3um1s2LBBHTp0UKVKlRQfH6/58+erefPm+uOPP1SuXDlJUmpqqp555hlFRkbq5Zdf1ltvvaXExERt27ZNv//+u/z8/HK0XW93/Phx2drays3NTZs2bdJPP/2kl19+WRUqVFBMTIzmzp2rFi1a6I8//pCTk5OaNWum/v3764MPPtCIESPk7+8vSaZ/7/ZaZKZfv37y9vbWuHHjtGvXLi1YsEBubm766aefVLFiRU2cOFGbNm3S1KlTVbt2bXXp0kXSraMhzz77rHbs2KHu3burbt262rp1qwYPHqzTp09r+vTpd13/fv36qVSpUhozZoxiYmI0Y8YM9e3bV2vWrDGNs2LFCnXt2lUhISGaPHmyrl69qrlz56pp06b65ZdfctUdLDeuXbum5557Tnv37tX27dv1yCOPmA3v2LGj/P39NWnSJG3cuFHjx4+Xu7u75s+fr8cff1yTJ0/WypUrFR4erkceeUTNmjWTdOsL0bPPPqsff/xR//nPf+Tv76+DBw9q+vTp+uuvv7RhwwbTMnLzHszJvj527FhFRESoR48eatiwoS5fvqy9e/dq//79euKJJ/Jku6V/eercuXOOp/n333/11FNP6fnnn9dLL72ktWvXaujQoQoICFDr1q3vqY4LFy6odevWevnll/Xaa6/Jy8vLNGzVqlVKTEzUG2+8IYPBoClTpuj555/X8ePHsz1ymNPPinSTJk2SjY2NwsPDlZCQoClTpujVV1/Vzz//bBrns88+09WrV/Xmm2+qdOnS2r17tz788EP997//1WeffZZlLZ07d1bPnj31+++/m50svWfPHv311196++23JUnbtm1Tp06d1KpVK9ORosOHD2vnzp2ZfrGXpJSUFIWEhCg5Odn0+XD69Gl9/fXXunTpklxdXbPZ8rdez6efflovvfSSOnXqpE8//VRvvvmm7Ozs9Prrr6tEiRJq37691qxZo/fff1+2tramaT/55BMZjUa9+uqr2S6je/fuWrZsmVq3bq0ePXro5s2b+uGHH7Rr1y41aNAg22nv5uzZs3ryySfl4eGhYcOGyc3NTTExMVq3bp0kycPDQ3PnztWbb76p9u3b6/nnn5ck1alTR5J06NAhNWnSROXLl9ewYcPk7OysTz/9VO3atdPnn3+u9u3bmy2vd+/e8vDw0OjRo5WUlGRR7ShkjEAhlZCQYJRkfO6553I8zdWrVzO0hYSEGCtXrmzW9tBDDxklGbds2WLWvmPHDqMkY+3atY0pKSmm9k6dOhkNBoOxdevWZuMHBQUZH3rooQzz7tq1q+l5v379jAaDwfjLL7+Y2i5cuGB0d3c3SjKeOHEiQ13ff/+9qe3s2bNGe3t746BBg0xt169fN6amppot98SJE0Z7e3vjO++8Y2pbsmSJUZLx/fffz7Bd0tLSMrTdrnnz5sYaNWoYz507Zzx37pzx8OHDxv79+xslGdu2bWs
"text/plain": [
"<Figure size 800x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"=== Carmignac Patrimoine | method=kmeans ===\n",
"Clients after filtering: 3058\n",
"Chosen K: 4\n",
" cluster n_clients\n",
"0 0 2601\n",
"1 1 172\n",
"2 2 200\n",
"3 3 85\n",
"\n",
"Churn profile:\n",
" churn_hard churn_soft churn_warning\n",
"cluster \n",
"0 0.688 0.765 0.129\n",
"1 0.907 0.953 0.750\n",
"2 0.745 0.870 0.700\n",
"3 0.847 0.918 0.765\n"
]
}
],
"source": [
"# KMeans — test on one family\n",
"\n",
"test_family = top_15_families[0]\n",
"result_test_kmeans = run_family_clustering(\n",
" df_base=df_family_client_base,\n",
" family_name=test_family,\n",
" features=family_cluster_features,\n",
" method=\"kmeans\",\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=RANDOM_STATE,\n",
" make_plots=True\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "e339c5fb",
"metadata": {
"id": "e339c5fb",
"outputId": "d9d744b3-99f5-4f5d-e24b-0969f9f6861f"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Patrimoine\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Sécurité\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Investissement\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Credit <NUM>\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Portfolio Sécurité\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Portfolio Flexible Bond\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Portfolio Credit\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Emergents\n",
"==========================================================================================\n",
"[SKIP] Carmignac Emergents (kmeans): no valid K with cluster size constraints.\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Court Terme\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Portfolio Long-Short European Equities\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Portfolio Grande Europe\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Portfolio Emergents\n",
"==========================================================================================\n",
"[SKIP] Carmignac Portfolio Emergents (kmeans): no valid K with cluster size constraints.\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Portfolio Global Bond\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Portfolio Patrimoine\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running KMeans clustering for family: Carmignac Portfolio Emerging Patrimoine\n",
"==========================================================================================\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>method</th>\n",
" <th>fund_family</th>\n",
" <th>n_clients</th>\n",
" <th>best_k</th>\n",
" <th>silhouette</th>\n",
" <th>davies_bouldin</th>\n",
" <th>min_cluster_size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>3058</td>\n",
" <td>4</td>\n",
" <td>0.882916</td>\n",
" <td>0.443551</td>\n",
" <td>85</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>2126</td>\n",
" <td>4</td>\n",
" <td>0.872248</td>\n",
" <td>0.450959</td>\n",
" <td>74</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>1344</td>\n",
" <td>4</td>\n",
" <td>0.865687</td>\n",
" <td>0.464262</td>\n",
" <td>39</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" <td>1099</td>\n",
" <td>5</td>\n",
" <td>0.776536</td>\n",
" <td>0.690654</td>\n",
" <td>26</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" <td>586</td>\n",
" <td>4</td>\n",
" <td>0.717091</td>\n",
" <td>0.635826</td>\n",
" <td>28</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>507</td>\n",
" <td>4</td>\n",
" <td>0.714238</td>\n",
" <td>0.690596</td>\n",
" <td>17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>1573</td>\n",
" <td>4</td>\n",
" <td>0.697358</td>\n",
" <td>0.776298</td>\n",
" <td>86</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" <td>1053</td>\n",
" <td>4</td>\n",
" <td>0.675407</td>\n",
" <td>0.801578</td>\n",
" <td>40</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Credit &lt;NUM&gt;</td>\n",
" <td>370</td>\n",
" <td>4</td>\n",
" <td>0.533313</td>\n",
" <td>0.996512</td>\n",
" <td>25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" <td>1664</td>\n",
" <td>4</td>\n",
" <td>0.532877</td>\n",
" <td>0.680604</td>\n",
" <td>70</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>1125</td>\n",
" <td>4</td>\n",
" <td>0.451412</td>\n",
" <td>0.935678</td>\n",
" <td>46</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" <td>984</td>\n",
" <td>4</td>\n",
" <td>0.366476</td>\n",
" <td>1.024236</td>\n",
" <td>48</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" <td>1107</td>\n",
" <td>5</td>\n",
" <td>0.297069</td>\n",
" <td>1.067643</td>\n",
" <td>29</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" method fund_family n_clients \\\n",
"0 kmeans Carmignac Patrimoine 3058 \n",
"1 kmeans Carmignac Investissement 2126 \n",
"2 kmeans Carmignac Portfolio Grande Europe 1344 \n",
"3 kmeans Carmignac Portfolio Emerging Patrimoine 1099 \n",
"4 kmeans Carmignac Portfolio Long-Short European Equities 586 \n",
"5 kmeans Carmignac Court Terme 507 \n",
"6 kmeans Carmignac Sécurité 1573 \n",
"7 kmeans Carmignac Portfolio Flexible Bond 1053 \n",
"8 kmeans Carmignac Credit <NUM> 370 \n",
"9 kmeans Carmignac Portfolio Global Bond 1664 \n",
"10 kmeans Carmignac Portfolio Sécurité 1125 \n",
"11 kmeans Carmignac Portfolio Credit 984 \n",
"12 kmeans Carmignac Portfolio Patrimoine 1107 \n",
"\n",
" best_k silhouette davies_bouldin min_cluster_size \n",
"0 4 0.882916 0.443551 85 \n",
"1 4 0.872248 0.450959 74 \n",
"2 4 0.865687 0.464262 39 \n",
"3 5 0.776536 0.690654 26 \n",
"4 4 0.717091 0.635826 28 \n",
"5 4 0.714238 0.690596 17 \n",
"6 4 0.697358 0.776298 86 \n",
"7 4 0.675407 0.801578 40 \n",
"8 4 0.533313 0.996512 25 \n",
"9 4 0.532877 0.680604 70 \n",
"10 4 0.451412 0.935678 46 \n",
"11 4 0.366476 1.024236 48 \n",
"12 5 0.297069 1.067643 29 "
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# KMeans — run clustering on the top 15 fund families\n",
"\n",
"family_results_kmeans = {}\n",
"family_summary_rows_kmeans = []\n",
"\n",
"for fam in top_15_families:\n",
" print(\"\\n\" + \"=\" * 90)\n",
" print(f\"Running KMeans clustering for family: {fam}\")\n",
" print(\"=\" * 90)\n",
"\n",
" res = run_family_clustering(\n",
" df_base=df_family_client_base,\n",
" family_name=fam,\n",
" features=family_cluster_features,\n",
" method=\"kmeans\",\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=RANDOM_STATE,\n",
" make_plots=False\n",
" )\n",
"\n",
" if res is not None:\n",
" family_results_kmeans[fam] = res\n",
" best_row = res[\"metrics_df\"].loc[res[\"metrics_df\"][\"k\"] == res[\"best_k\"]].iloc[0]\n",
"\n",
" family_summary_rows_kmeans.append({\n",
" \"method\": \"kmeans\",\n",
" \"fund_family\": fam,\n",
" \"n_clients\": res[\"n_clients\"],\n",
" \"best_k\": res[\"best_k\"],\n",
" \"silhouette\": best_row[\"silhouette\"],\n",
" \"davies_bouldin\": best_row[\"davies_bouldin\"],\n",
" \"min_cluster_size\": int(best_row[\"min_cluster_size\"]),\n",
" })\n",
"\n",
"family_summary_kmeans = pd.DataFrame(family_summary_rows_kmeans).sort_values(\n",
" [\"silhouette\", \"n_clients\"],\n",
" ascending=[False, False]\n",
").reset_index(drop=True)\n",
"\n",
"family_summary_kmeans\n"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "f5c7e517",
"metadata": {
"id": "f5c7e517",
"outputId": "6a8d8ae1-31e3-434d-884e-5862376e3525"
},
"outputs": [
{
"data": {
"image/png": "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RAcAAAAAAOm2evVq+fv7JxsNmJqwsDC98MILat68uezs7LR69Wr16dNHRqNRffv2tah77NgxtW/fXj179lSPHj0sEjChoaFycnLSkCFDdPLkSU2ZMkXZsmWTjY2Nrl+/rpEjR+rXX3/V3LlzVahQIQ0fPjzVmM6fP29OHg8dOlTOzs76+uuvUx3pfPLkSb366qvq1q2bOnfurNmzZ6tLly4KCgrSCy+8IOleUuqHH35Q69atVahQIV26dEnTp09XrVq1dPjwYeXNm1eSlJiYqKZNm2rz5s1q166dBg4cqJiYGG3cuFGHDh1SQEBAmo7r/U6dOiVbW1u5u7tr7dq12rlzp9q1a6f8+fMrIiJCYWFhql27tg4fPqzs2bOrZs2aGjBggL744gsNGzZMJUqUkCTzfx92LlLSv39/+fj4aNSoUfr11181Y8YMubu7a+fOnSpQoIDGjh2rtWvXasKECQoMDDQn50wmk5o3b66tW7eqW7duKlu2rNavX6933nlH58+f1+eff/7Q9vfv3185c+bUiBEjFBERoUmTJqlfv35aunSpuc6CBQvUuXNnBQcHa/z48bp165bCwsJUvXp1/f777+ma0iY9bt++rRYtWmjv3r3atGmTKlasaPF+27ZtVaJECY0bN05r1qzRRx99JA8PD02fPl1169bV+PHjtWjRIr399tuqWLGiatasKUkyGo1q3ry5tm/frjfeeEMlSpTQwYMH9fnnn+v48eP64YcfzPtIzzWYls/6yJEjFRoaqu7du6tSpUqKjo7W3r17tX//ftWvXz9TjuP9Mvp83717V8HBwapevbo+/fRTZc+eXT4+PoqKitLff/9t/gzeP13If23cuFGnTp1SSEiIfHx8zFNa/fXXX/r1119lMBge2q61a9eqadOmaToG/fr1k7u7u0aOHKljx44pLCxMZ86cMf/omCSl6/jSpUuqWrWqbt26pQEDBihXrlyaN2+emjdvrhUrVqhVq1YqUaKExowZo3feeUevvvqqmjdvrtjYWHXp0kXFixfX6NGjJUkdO3bU/PnztX79eovYL168qC1btmjEiBGptsHb21tOTk5avXq1+vfvLw8Pj1TrFixYUImJiebzmhZXrlxJVmZvby9XV9c0rW9mAgAAAAAASIeoqCiTJFOLFi3SvM6tW7eSlQUHB5v8/f0tygoWLGiSZFq3bp1F+datW02STIGBgaaEhARzefv27U0Gg8HUqFEji/pVqlQxFSxYMNm2O3fubH7dv39/k8FgMP3+++/msqtXr5o8PDxMkkynT59OFtfPP/9sLouMjDQ5ODiY3nrrLXNZXFycKTEx0WK/p0+fNjk4OJhGjx5tLps9e7ZJkmnixInJjovRaExWdr9atWqZihcvbrp8+bLp8uXLpiNHjpgGDBhgkmRq1qyZyWRK+Xjv2rXLJMk0f/58c9ny5ctNkkxbt25NVj+1c5H03v3Hcs6cOSZJpuDgYIv4q1SpYjIYDKZevXqZy+7evWvKnz+/qVatWuayH374wSTJ9NFHH1ns59VXXzUZDAbTyZMnH7rvevXqWez7zTffNNna2ppu3LhhMplMppiYGJO7u7upR48eFvu4ePGiyc3NLVn540j6vC5fvtwUExNjqlWrlsnT09Pis2YymUwjRowwSTK98cYb5rKk42MwGEz
"text/plain": [
"<Figure size 1500x400 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABiYAAAHpCAYAAAAGQYQ4AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs3XVYVFkfB/DvDC3d3SUIimsXWGuttb62a3e71orY3bF2d2N3YufanViIdLfMff9AR0dAAYEhvp/nuc/unHvuub9zZrjeuWfOOSJBEAQQERERERERERERERHlA7G8AyAiIiIiIiIiIiIiouKDHRNERERERERERERERJRv2DFBRERERERERERERET5hh0TRERERERERERERESUb9gxQURERERERERERERE+YYdE0RERERERERERERElG/YMUFERERERERERERERPmGHRNERERERERERERERJRv2DFBRERERERERERERET5hh0TREREVCzY2NigS5cu8g6jSJBnWxaG9/Hs2bMQiUTw9fWVdyjFSpcuXWBjYyPvMPLV69evIRKJsH79enmHQkRERESULeyYICIiohx7+fIlevfuDTs7O6iqqkJLSwvVqlXDwoULkZCQIO/wiqSaNWtCJBJJNz09PVSoUAFr166FRCLJVlmPHj3ChAkT8Pr167wJligXREdHY+LEiShTpgw0NDSgpqYGNzc3/PPPP/jw4UO+xbF06VJ2APzE5cuXMWHCBERGRso7FCIiIiIq4BTlHQAREREVTocPH0arVq2goqKCTp06wc3NDcnJybh48SJGjBiBhw8fYuXKlfIOU+rp06cQi4vGbzIsLCwwffp0AEBISAg2btyI7t2749mzZ5gxY0aWy3n06BEmTpyImjVrZuuX5vJsy6L0PtLPvXr1CnXr1sXbt2/RqlUr9OrVC8rKyrh37x7WrFmDvXv34tmzZ/kSy9KlS2FgYFCgRuxYW1sjISEBSkpK8g4FQFrHxMSJE9GlSxfo6OjIOxwiIiIiKsDYMUFERETZ5u/vj7Zt28La2hpnzpyBqampdF///v3x4sULHD58+JfPIwgCEhMToaam9stlqaio/HIZBYW2tjb++usv6evevXvD2dkZixcvxuTJk/PkIeW374U827IovY/0Y58+fUKLFi0QFBSEs2fPonr16jL7p06dipkzZ8oputzx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
"text/plain": [
"<Figure size 1800x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAr8AAAHqCAYAAAANsiY3AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAA+xZJREFUeJzs3XecU8XawPHfSc9mN9sru7Qt9A4iIlIFFBBUVLwW5LUXvNj1elXser32gh0UsYHXSlFpVnrvZanbe7K76cm8f8SNhC0ssIWF+d4Pn+vOnJwzSU5OnsyZeUYRQggkSZIkSZIk6Qygau4GSJIkSZIkSVJTkcGvJEmSJEmSdMaQwa8kSZIkSZJ0xpDBryRJkiRJknTGkMGvJEmSJEmSdMaQwa8kSZIkSZJ0xpDBryRJkiRJknTGkMGvJEmSJEmSdMaQwa8kSZIkSZJ0xpDBbwvVtm1brrvuuuZuxmmhOV/LlvA+Ll++HEVRmDdvXnM3RToNDBkyhCFDhjT5cavO4+XLlzf5sQF8Ph9du3bl6aefbpbjH01RFKZPn37cj2vu1/FE2y2dfhYtWkRoaCiFhYXH/VgZ/B4hMzOTm2++mfbt22MwGDCbzQwcOJBXX30Vu93e3M07LQ0ZMgRFUQL/oqKi6NevHx9++CE+n++49rV9+3amT5/OgQMHGqexknQSDhw4EHSuq9VqWrduzcUXX8zGjRurbe9wOHj55Zfp378/4eHhGAwGMjIyuOOOO9i9e3eNx7j//vtRFIUrrriikZ/Nqeutt95i1qxZzd2Maj777DMOHz7MHXfc0dxNkZpJbm4uDz74IEOHDiUsLOyEfkRkZ2dz+eWXExERgdlsZvz48ezbt6/GbT/44AM6deqEwWAgPT2d119//aSfw3fffUfv3r0xGAy0bt2axx57DI/HU6/H+nw+/vOf/9CuXTsMBgPdu3fns88+q3HbHTt2MHr0aEJDQ4mKiuKaa66pFuSOHj2atLQ0nn322eN/IkISQgjxww8/CKPRKCIiIsSdd94p3n33XfHGG2+ISZMmCa1WK2688cbmbmIQh8MhXC5XczfjpA0ePFgkJyeL2bNni9mzZ4uXXnpJ9OzZUwDigQceOK59zZ07VwBi2bJlx/W45nwtW8L7uGzZMgGIuXPnNndTWrT9+/cLQFx55ZVi9uzZYtasWeKBBx4QZrNZ6PV6sWHDhsC2hYWFok+fPgIQY8eOFa+88op4//33xX333SdSUlKEVquttn+fzyeSk5NF27ZthdFoFFartQmfXf05nU7hdDobbf9dunQRgwcPrlbu9XqF3W4XXq+30Y5dlx49eoibbrqpWY5dE0A89thjx/245n4dT7Tdp4Kqa2l6eroYMGDAcX9flZeXi/T0dBEXFyeef/558dJLL4mUlBSRnJwsioqKgrZ9++23BSAuvfRS8e6774prrrlGAOK555474fYvWLBAKIoihg4dKt59910xdepUoVKpxC233FKvxz/44IMCEDfeeKN49913xZgxYwQgPvvss6DtDh8+LGJiYkRqaqp49dVXxdNPPy0iIyNFjx49ql073nrrLRESEnLc1zsZ/Aoh9u3bJ0JDQ0XHjh1FTk5Otfo9e/aIV1555aSP4/P5hM1mO+n9nE4GDx4sunTpElRWWVkpkpOThclkOq7A8HiCX/le1J8MfhtGVfD7wgsvBJV/9913AggKjMaMGSNUKpWYN29etf04HA5xzz33VCtfunSpAMTSpUuFVqsVs2bNavgnUYOKioomOU591Rb8Nqf169cLQCxevLi5mxLQUoPIU6XdJ/IDwGq1iuLiYiHEiXXWPP/88wIQq1evDpTt2LFDqNVq8dBDDwXKbDabiI6OFmPGjAl6/FVXXSVMJpMoKSk5rnZX6dy5s+jRo4dwu92BsocfflgoiiJ27NhR52OzsrKEVqsVt99+e6DM5/OJQYMGieTkZOHxeALlt956qzAajeLgwYOBsp9//lkA4p133gnab35+vlCr1eKDDz44rucig18hxC233CIA8ccff9Rr+w8//FAMHTpUxMbGCp1OJzp16iTeeuutatu1adNGjBkzRixatEj06dNH6PV68fLLLweCiS+++EJMnz5dJCUlidDQUHHppZeKsrIy4XA4xD//+U8RGxsrTCaTuO6664TD4ai278mTJweVbdq0SZx33nnCYDCIVq1aiSeffFJ8+OGHAhD79++v1q7ffvtN9OvXT+j1etGuXTvx0UcfBe2vuLhY3HPPPaJr167CZDKJsLAwMXr0aLFx48Zqz9Vut4vHHntMpKenC71eLxISEsTFF18s9u7dW+drWVPwK4QQEydOFIDIzs4WBw4cELfeeqvIyMgQBoNBREVFiYkTJwY9p5kzZwqg2r+qC0tt70VNr2XVvn777TcxdepUERMTI8LDw8VNN90knE6nKC0tFddcc42IiIgQERER4r777hM+ny+o/RUVFeLuu+8WycnJQqfTiYyMDPHCCy9U2662Y//+++/irrvuEjExMSIkJERMmDBBFBQUVHudFixYIM4991wREhIiQkNDxYUXXii2bt1a52t+vGoKfh0OhxgzZowwm82Bz81jjz0mALFr1y5x1VVXCbPZLGJiYsS///1v4fP5xKFDh8RFF10kwsLCRHx8vPjvf/9b7VgOh0M8+uijIjU1Veh0OpGcnCzuu+++auf/8X4Gj3Wuu1wuMX36dJGWlib0er2IiooSAwcOFD/99FNDvIRCiNqD34qKCgGI888/XwghxMqVKwO9I8fj+uuvF507dxZCCHHBBRcE9lcfgLj99tvFJ598IjIyMoRerxe9e/cWv/zyS9B2Ve/xtm3bxJVXXikiIiJEz549hRBCuN1u8cQTT4j27dsLnU4n2rRpIx566KFq793gwYOrBaf1fd+FEGL27NmiX79+gTt1gwYNEj/++KMQwv9+H30NqDpW1Xl8dLDx5Zdfit69ewuDwSCio6PFVVddJbKysoK2mTx5sjCZTCIrK0uMHz9emEwmERMTI+65556gL+3aPProo0Kn09X4Yz4rK0tMmTJFxMXFCZ1OJzp37hz0RW6z2USHDh1Ehw4dgn6wFxcXi4SEBDFgwIBAG6ramZmZKUaOHClCQkJEYmKiePzxx6tde44OIutzna3tday6jm/btk0MGTJEGI1GkZSUJJ5//vlqz7e+77XD4RDTpk0TMTExIjQ0VIwbN04cPnz4mMFvXl6eUKvVYvr06dXqdu7cKQDx+uuvB17D+nzHVT3nzz77TDz88MMiKSlJKIoiSktLhcvlEjt27Kix46wuJxL89uvXT/Tr169a+ciRI0Vqamrg7/nz5wtAzJ8/P2i7P//8UwBi9uzZx9VWIYTYtm2bAMSbb74ZVJ6dnS0A8eSTT9b5+DfffDNw7TjSp59+Gvi+rRIXFycuu+yyavvIyMgQw4cPr1beq1cvcdFFFx3P0xGa4x8ocfr5/vvvad++Peecc069tp8xYwZdunThoosuQqPR8P3333Pbbbfh8/m4/fbbg7bdtWsXV155JTfffDM33ngjHTp0CNQ9++yzGI1GHnzwQfbu3cvrr7+OVqtFpVJRWlrK9OnTWblyJbNmzaJdu3Y8+uijtbYpOzuboUOHoigKDz30ECaTiffffx+9Xl/j9nv37mXixIlcf/31TJ48mQ8//JDrrruOPn360KVLFwD27dvHN998w2WXXUa7du3Iz8/nnXfeYfDgwWzfvp2kpCQAvF4vY8eOZcmSJUyaNIl//vOflJeX8/PPP7N161ZSU1Pr9boead++fajVaiIiIliwYAF//vknkyZNIjk5mQMHDjBjxgyGDBnC9u3bCQkJ4bzzzuPOO+/ktdde41//+hedOnUCCPz/sd6LmkydOpWEhAQef/xxVq5cybvvvktERAR//vknrVu35plnnmHBggW88MILdO3alWuvvRYAIQQXXXQRy5Yt4/rrr6dnz578+OOP3HfffWRnZ/Pyyy8f8/lPnTqVyMhIHnvsMQ4cOMArr7zCHXfcwRdffBHYZvbs2UyePJlRo0bx/PPPY7PZmDFjBueeey4bNmy
"text/plain": [
"<Figure size 700x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAk4AAAGGCAYAAACNCg6xAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAPiFJREFUeJzt3X98zfX///H7MXY2P3Zm2GYfwxA2v6PW8ptlCRH9UDKJ5NOmtybkXWFSC+VHhH6xN1HSOyoKM7/eMRW1/MrPaN5lm/zYbBi21/ePPjtfxzZem3E2btfL5Vxynq/neb0er9frvDr3vc7z9ToWwzAMAQAA4JrKOLsAAACA0oLgBAAAYBLBCQAAwCSCEwAAgEkEJwAAAJMITgAAACYRnAAAAEwiOAEAAJhEcAIAADCJ4IRbRu3atfXUU085u4xbgjO3ZWnYjxs2bJDFYtHnn3/u7FJuK0899ZRq167t7DJuqiNHjshisSg2NtbZpeD/EJxwVYcOHdKzzz6rOnXqyM3NTR4eHmrdurVmzJihc+fOObu8W1KHDh1ksVjsDy8vL911112aN2+ecnJyCjWvPXv2aPz48Tpy5MiNKRYoBunp6YqOjlazZs1UsWJFubu7q3Hjxho9erT+/PPPm1bH7NmzCSi4prLOLgAl18qVK/XII4/IarUqPDxcjRs31oULF/Tdd99p5MiR2r17t95//31nl2m3b98+lSlza/wtUKNGDcXExEiSjh8/rgULFmjQoEHav3+/3nzzTdPz2bNnj6Kjo9WhQ4dC/aXuzG15K+1HXNtvv/2m0NBQJSUl6ZFHHtGQIUPk6uqqHTt26KOPPtKyZcu0f//+m1LL7NmzVbVq1RJ1xrNWrVo6d+6cypUr5+xS8H8ITsjX4cOH1bdvX9WqVUvr1q1T9erV7dMiIiJ08OBBrVy58rqXYxiGzp8/L3d39+uel9Vqve55lBQ2m01PPvmk/fmzzz6rBg0aaNasWXrttdduyP9EL98XztyWt9J+xNVdunRJvXv3VkpKijZs2KA2bdo4TH/99dc1adIkJ1VXPC5duqScnBy5uroW6fUWi0Vubm7FXBWuB3/WIV+TJ09WRkaGPvroI4fQlKtevXr6xz/+YX8+f/58derUSd7e3rJarQoKCtKcOXPyvK527drq3r27Vq9erVatWsnd3V3vvfeefczIZ599pujoaP3P//yPKlWqpIcfflhpaWnKysrS8OHD5e3trYoVK2rgwIHKysrKM+8r/1LcsWOH2rdvL3d3d9WoUUMTJ07U/PnzZbFYHL6+yq3ru+++09133y03NzfVqVNHCxYscJjfyZMn9eKLL6pJkyaqWLGiPDw81LVrV/3yyy951vX8+fMaP3686tevLzc3N1WvXl29e/fWoUOHzOwCB+XLl9c999yjzMxMHT9+XL///ruee+45NWjQQO7u7qpSpYoeeeQRh3WKjY3VI488Iknq2LGj/au/DRs2XHVf5LctY2NjZbFY9N133+n5559XtWrV5OnpqWeffVYXLlzQ6dOnFR4ersqVK6ty5coaNWqUDMNwWIfMzEyNGDFC/v7+slqtatCggd566608/Qpa9ubNmxUVFaVq1aqpQoUKeuihh3T8+PE82+rbb79V27ZtVaFCBVWqVEndunXT7t27C73NCysrK0vdu3eXzWbTli1bJEnjx4+XxWLR/v379eSTT8pms6latWp69dVXZRiGjh49qp49e8rDw0O+vr56++23853vuHHjVK9ePVmtVvn7+2vUqFF53v+FPQav9V6/ePGioqOjdccdd8jNzU1VqlRRmzZtFBcXV2zb7N///rd++eUXvfzyy3lCkyR5eHjo9ddfL/D1uf/fyH1P58pvXFBycrIGDhyoGjVqyGq1qnr16urZs6f9mKldu7Z2796tjRs32o+VDh062F9/+vRpDR8+3P7+rVevniZNmuTw9Xnuct966y1Nnz5ddevWldVq1Z49ewpch7i4OLVp00aenp6qWLGiGjRooH/+858FrkvuOuf3uPKssplj4VrbBXlxxgn5+vrrr1WnTh3de++9pvrPmTNHjRo10oMPPqiyZcvq66+/1nPPPaecnBxFREQ49N23b58ef/xxPfvss3rmmWfUoEED+7SYmBi5u7vrpZde0sGDBzVz5kyVK1dOZcqU0alTpzR+/Hht3bpVsbGxCggI0NixYwus6Y8//rAHhjFjxqhChQr68MMPCzyjcfDgQT388MMaNGiQBgwYoHnz5umpp55Sy5Yt1ahRI0l/f62wfPlyPfLIIwoICFBKSoree+89tW/fXnv27JGfn58kKTs7W927d1d8fLz69u2rf/zjHzpz5ozi4uK0a9cu1a1b19R2vdxvv/0mFxcXeXp66ptvvtGWLVvUt29f1ahRQ0eOHNGcOXPUoUMH7dmzR+XLl1e7du30/PPP65133tE///lPBQYGSpL9v9faF/kZNmyYfH19FR0dra1bt+r999+Xp6entmzZopo1a+qNN97QN998oylTpqhx48YKDw+X9PfZrAcffFDr16/XoEGD1Lx5c61evVojR47UH3/8oWnTpl1z/YcNG6bKlStr3LhxOnLkiKZPn67IyEgtWbLE3mfhwoUaMGCAwsLCNGnSJJ09e1Zz5sxRmzZt9PPPP9+wgcXnzp1Tz549tW3bNq1du1Z33XWXw/THHntMgYGBevPNN7Vy5UpNnDhRXl5eeu+999SpUydNmjRJixYt0osvvqi77rpL7dq1kyTl5OTowQcf1HfffachQ4YoMDBQO3fu1LRp07R//34tX77cvozCHINm3uvjx49XTEyMBg8erLvvvlvp6enatm2bfvrpJ913333Fst2++uorSVL//v2LZX5X06dPH+3evVvDhg1T7dq1lZqaqri4OCUlJal27dqaPn26hg0bpooVK+rll1+WJPn4+EiSzp49q/bt2+uPP/7Qs88+q5o1a2rLli0aM2aMjh07punTpzssa/78+Tp//ryGDBkiq9UqLy+vfGvavXu3unfvrqZNm2rChAmyWq06ePCgNm/eXOB6BAYGauHChQ5tp0+fVlRUlLy9ve1tZo+Fa20X5MMArpCWlmZIMnr27Gn6NWfPns3TFhYWZtSpU8ehrVatWoYkY9WqVQ7t69evNyQZjRs3Ni5cuGBvf/zxxw2LxWJ07drVoX9ISIhRq1atPPMeMGCA/fmwYcMMi8Vi/Pzzz/a2EydOGF5eXoYk4/Dhw3nq2rRpk70tNTXVsFqtxogRI+xt58+fN7Kzsx2We/jwYcNqtRoTJkywt82bN8+QZEydOjXPdsnJycnTdrn27dsbDRs2NI4fP24cP37c+PXXX43nn3/ekGT06NHDMIz8t3dCQoIhyViwYIG9benSpYYkY/369Xn6F7Qvcqddvi3nz59vSDLCwsIc6g8JCTEsFosxdOhQe9ulS5eMGjVqGO3bt7e3LV++3JBkTJw40WE5Dz/8sGGxWIyDBw9ec9mhoaEOy37hhRcMFxcX4/Tp04ZhGMaZM2cMT09P45lnnnFYRnJysmGz2fK0X4/c9+vSpUuNM2fOGO3btzeqVq3q8F4zDMMYN26cIckYMmSIvS13+1gsFuPNN9+0t586dcpwd3d3WPeFCxcaZcqUMf7zn/84zHfu3LmGJGPz5s32tsIeg9d6rzdr1szo1q2buQ1SRC1atDBsNpvp/gMGDHA47nP3w5Xv78OHDxuSjPnz5xuG8fe2lWRMmTLlqvNv1KiRw/s212uvvWZUqFDB2L9/v0P7Sy+9ZLi4uBhJSUkOy/Xw8DBSU1OvuT7Tpk0zJBnHjx8vsM+V63KlnJwco3v37kbFihWN3bt3G4Zh/lgwu13giK/qkEd6erokqVKlSqZfc/kYpbS0NP31119q3769fvvtN6WlpTn0DQgIUFhYWL7zCQ8Pdxi/ExwcLMMw9PTTTzv0Cw4O1tGjR3Xp0qUCa1q1apVCQkLUvHlze5uXl5f69euXb/+goCC1bdvW/rxatWpq0KCBfvvtN3ub1Wq1D1zOzs7WiRMn7KfXf/rpJ3u/f//736pataqGDRuWZzkWi6X
"text/plain": [
"<Figure size 600x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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cePGORp/7ty5qlWrlp599lkVK1ZMX331lXr37q20tDT16dPHbNw///xTnTp10htvvKGePXuqevXqpmERERFydHTUsGHDdPToUX344YcqXry4bGxs9O+//2rs2LHatWuXli1bpkqVKmn06NFZ1nT69GnTF+rhw4fL2dlZixYtyvIX8aNHj+rFF19U9+7d1bVrVy1ZskTdunVT/fr1VatWLUm3um1s2LBBHTp0UKVKlRQfH6/58+erefPm+uOPP1SuXDlJUmpqqp555hlFRkbq5Zdf1ltvvaXExERt27ZNv//+u/z8/HK0XW93/Phx2drays3NTZs2bdJPP/2kl19+WRUqVFBMTIzmzp2rFi1a6I8//pCTk5OaNWum/v3764MPPtCIESPk7+8vSaZ/7/ZaZKZfv37y9vbWuHHjtGvXLi1YsEBubm766aefVLFiRU2cOFGbNm3S1KlTVbt2bXXp0kXSraMhzz77rHbs2KHu3burbt262rp1qwYPHqzTp09r+vTpd13/fv36qVSpUhozZoxiYmI0Y8YM9e3bV2vWrDGNs2LFCnXt2lUhISGaPHmyrl69qrlz56pp06b65ZdfctUdLDeuXbum5557Tnv37tX27dv1yCOPmA3v2LGj/P39NWnSJG3cuFHjx4+Xu7u75s+fr8cff1yTJ0/WypUrFR4erkceeUTNmjWTdOsL0bPPPqsff/xR//nPf+Tv76+DBw9q+vTp+uuvv7RhwwbTMnLzHszJvj527FhFRESoR48eatiwoS5fvqy9e/dq//79euKJJ/Jku6V/eercuXOOp/n333/11FNP6fnnn9dLL72ktWvXaujQoQoICFDr1q3vqY4LFy6odevWevnll/Xaa6/Jy8vLNGzVqlVKTEzUG2+8IYPBoClTpuj555/X8ePHsz1ymNPPinSTJk2SjY2NwsPDlZCQoClTpujVV1/Vzz//bBrns88+09WrV/Xmm2+qdOnS2r17tz788EP997//1WeffZZlLZ07d1bPnj31+++/m50svWfPHv311196++23JUnbtm1Tp06d1KpVK9ORosOHD2vnzp2ZfrGXpJSUFIWEhCg5Odn0+XD69Gl9/fXXunTpklxdXbPZ8rdez6efflovvfSSOnXqpE8//VRvvvmm7Ozs9Prrr6tEiRJq37691qxZo/fff1+2tramaT/55BMZjUa9+uqr2S6je/fuWrZsmVq3bq0ePXro5s2b+uGHH7Rr1y41aNAg22nv5uzZs3ryySfl4eGhYcOGyc3NTTExMVq3bp0kycPDQ3PnztWbb76p9u3b6/nnn5ck1alTR5J06NAhNWnSROXLl9ewYcPk7OysTz/9VO3atdPnn3+u9u3bmy2vd+/e8vDw0OjRo5WUlGRR7ShkjEAhlZCQYJRkfO6553I8zdWrVzO0hYSEGCtXrmzW9tBDDxklGbds2WLWvmPHDqMkY+3atY0pKSmm9k6dOhkNBoOxdevWZuMHBQUZH3rooQzz7tq1q+l5v379jAaDwfjLL7+Y2i5cuGB0d3c3SjKeOHEiQ13ff/+9qe3s2bNGe3t746BBg0xt169fN6amppot98SJE0Z7e3vjO++8Y2pbsmSJUZLx/fffz7Bd0tLSMrTdrnnz5sYaNWoYz507Zzx37pzx8OHDxv79+xslGdu2bWs
"text/plain": [
"<Figure size 800x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"=== Carmignac Patrimoine | method=kmeans ===\n",
"Clients after filtering: 3058\n",
"Chosen K: 4\n",
" cluster n_clients\n",
"0 0 2601\n",
"1 1 172\n",
"2 2 200\n",
"3 3 85\n",
"\n",
"Churn profile:\n",
" churn_hard churn_soft churn_warning\n",
"cluster \n",
"0 0.688 0.765 0.129\n",
"1 0.907 0.953 0.750\n",
"2 0.745 0.870 0.700\n",
"3 0.847 0.918 0.765\n"
]
}
],
"source": [
"# KMeans — visual and business review for one selected family\n",
"\n",
"selected_family = top_15_families[0]\n",
"if selected_family in family_results_kmeans:\n",
" _ = run_family_clustering(\n",
" df_base=df_family_client_base,\n",
" family_name=selected_family,\n",
" features=family_cluster_features,\n",
" method=\"kmeans\",\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=RANDOM_STATE,\n",
" make_plots=True\n",
" )\n"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "4ba643a5",
"metadata": {
"id": "4ba643a5",
"outputId": "5a75c58f-9364-4568-e27c-14e894704bea"
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>method</th>\n",
" <th>fund_family</th>\n",
" <th>n_clients</th>\n",
" <th>best_k</th>\n",
" <th>silhouette</th>\n",
" <th>davies_bouldin</th>\n",
" <th>min_cluster_size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>3058</td>\n",
" <td>4</td>\n",
" <td>0.882916</td>\n",
" <td>0.443551</td>\n",
" <td>85</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>2126</td>\n",
" <td>4</td>\n",
" <td>0.872248</td>\n",
" <td>0.450959</td>\n",
" <td>74</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>1344</td>\n",
" <td>4</td>\n",
" <td>0.865687</td>\n",
" <td>0.464262</td>\n",
" <td>39</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" <td>1099</td>\n",
" <td>5</td>\n",
" <td>0.776536</td>\n",
" <td>0.690654</td>\n",
" <td>26</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" <td>586</td>\n",
" <td>4</td>\n",
" <td>0.717091</td>\n",
" <td>0.635826</td>\n",
" <td>28</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>507</td>\n",
" <td>4</td>\n",
" <td>0.714238</td>\n",
" <td>0.690596</td>\n",
" <td>17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>1573</td>\n",
" <td>4</td>\n",
" <td>0.697358</td>\n",
" <td>0.776298</td>\n",
" <td>86</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" <td>1053</td>\n",
" <td>4</td>\n",
" <td>0.675407</td>\n",
" <td>0.801578</td>\n",
" <td>40</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Credit &lt;NUM&gt;</td>\n",
" <td>370</td>\n",
" <td>4</td>\n",
" <td>0.533313</td>\n",
" <td>0.996512</td>\n",
" <td>25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" <td>1664</td>\n",
" <td>4</td>\n",
" <td>0.532877</td>\n",
" <td>0.680604</td>\n",
" <td>70</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>1125</td>\n",
" <td>4</td>\n",
" <td>0.451412</td>\n",
" <td>0.935678</td>\n",
" <td>46</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" <td>984</td>\n",
" <td>4</td>\n",
" <td>0.366476</td>\n",
" <td>1.024236</td>\n",
" <td>48</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" <td>1107</td>\n",
" <td>5</td>\n",
" <td>0.297069</td>\n",
" <td>1.067643</td>\n",
" <td>29</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" method fund_family n_clients \\\n",
"0 kmeans Carmignac Patrimoine 3058 \n",
"1 kmeans Carmignac Investissement 2126 \n",
"2 kmeans Carmignac Portfolio Grande Europe 1344 \n",
"3 kmeans Carmignac Portfolio Emerging Patrimoine 1099 \n",
"4 kmeans Carmignac Portfolio Long-Short European Equities 586 \n",
"5 kmeans Carmignac Court Terme 507 \n",
"6 kmeans Carmignac Sécurité 1573 \n",
"7 kmeans Carmignac Portfolio Flexible Bond 1053 \n",
"8 kmeans Carmignac Credit <NUM> 370 \n",
"9 kmeans Carmignac Portfolio Global Bond 1664 \n",
"10 kmeans Carmignac Portfolio Sécurité 1125 \n",
"11 kmeans Carmignac Portfolio Credit 984 \n",
"12 kmeans Carmignac Portfolio Patrimoine 1107 \n",
"\n",
" best_k silhouette davies_bouldin min_cluster_size \n",
"0 4 0.882916 0.443551 85 \n",
"1 4 0.872248 0.450959 74 \n",
"2 4 0.865687 0.464262 39 \n",
"3 5 0.776536 0.690654 26 \n",
"4 4 0.717091 0.635826 28 \n",
"5 4 0.714238 0.690596 17 \n",
"6 4 0.697358 0.776298 86 \n",
"7 4 0.675407 0.801578 40 \n",
"8 4 0.533313 0.996512 25 \n",
"9 4 0.532877 0.680604 70 \n",
"10 4 0.451412 0.935678 46 \n",
"11 4 0.366476 1.024236 48 \n",
"12 5 0.297069 1.067643 29 "
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# KMeans — summary table of clustering results across families\n",
"family_summary_kmeans\n"
]
},
{
"cell_type": "markdown",
"id": "8ecdec77",
"metadata": {},
"source": [
"---\n",
"## Gaussian Mixture Model (GMM)\n",
"\n",
"This section repeats the same family-level clustering analysis using a Gaussian Mixture Model.\n",
"Compared with KMeans, GMM allows more flexible cluster shapes and soft probabilistic boundaries.\n"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "f43dec41",
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1500x400 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1800x500 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAArQAAAHqCAYAAAD1Ut3AAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAA+lJJREFUeJzs3Xd4VFX6wPHv9JlkMpPeQyqB0DvSq9LEir2ga68/117Wtmt3BQtrV7Cuir0BCoKi0nsJJQ1Cep1Mkulzfn9kMzIkoabC+TwPj+acO/eemblz73vPPfc9CiGEQJIkSZIkSZK6KGVHN0CSJEmSJEmSToQMaCVJkiRJkqQuTQa0kiRJkiRJUpcmA1pJkiRJkiSpS5MBrSRJkiRJktSlyYBWkiRJkiRJ6tJkQCtJkiRJkiR1aTKglSRJkiRJkro0GdBKkiRJkiRJXZoMaE8BSUlJXHXVVR3djJNCR36W8nuUOqMFCxagUCjIy8tr92139G/iueeeo2fPnni93g5rQ6OrrrqKpKSk43ptR36OJ9Ju6eTicrlISEjg1VdfPa7Xy4D2OGVnZ3PDDTeQkpKCXq/HZDIxatQoXnrpJWw2W0c376Q0fvx4FAqF719oaChDhw7l3XffPeYTys6dO3nsscc65CQsnTyOdZ9csWIF5513HtHR0Wi1WiIjI5k5cyZffvlls+vPzMxEoVCg1+uprq5u43fTOf3555889thjne7919TU8Oyzz3LfffehVMpT6anqtdde44ILLqBbt24oFIpjvjDwer0899xzJCcno9fr6devH//973+bXTYzM5OpU6diNBoJDQ3liiuuoKys7ITaX1BQwIUXXkhwcDAmk4mzzz6bnJyco379n3/+yejRowkICCA6Oprbb7+d2traJss5HA7uu+8+YmNjMRgMDB8+nJ9//tlvGY1Gw5133smTTz6J3W4/9jcjpGP2/fffC4PBIIKDg8Xtt98u3nzzTTFv3jxx8cUXC41GI6677rqObqIfu90unE5nRzfjhI0bN07Ex8eLDz74QHzwwQdizpw5YsCAAQIQ99133zGta+HChQIQy5cvP6bXdeRnebJ8jyeTY9knH3nkEQGI7t27i0ceeUS888474rnnnhPjx48XgPjoo4+arP/BBx8U0dHRQqfTibfeequ93tYxcbvdwmazCa/X2ybrf/755wUgcnNzm9R15G9i7ty5wmQyCZvN1iHbP9Ts2bNFYmLicb22Iz/HE2l3Z5CYmChCQ0PF1KlThVqtFrNnzz6m199///0CENddd5148803xYwZMwQg/vvf//otl5+fL8LDw0Vqaqp46aWXxJNPPilCQkJE//79hcPhOK62W61W0b17dxEZGSmeffZZMWfOHJGQkCDi4+NFeXn5EV+/adMmodfrxcCBA8Vrr70mHnroIaHT6cTUqVObLHvxxRcLtVot7r77bvHGG2+IESNGCLVaLVauXOm3XFVVldBqteKdd9455vcjA9pjlJOTI4xGo+jZs6coLCxsUr93717x4osvnvB2vF6vqK+vP+H1nEzGjRsnevfu7VdWV1cn4uPjRWBg4DEdkI8loJXfhdSSo90nG/e3WbNmNbufLl68WHz33Xd+ZV6vVyQlJYk777xTnHvuuWL8+PFt90YO4nK5jvsE2RYOF9B2pH79+onLL7+8o5vh01UDw87S7uM9zufl5fku5gIDA48poD1w4IDQaDTilltu8WvHmDFjRHx8vHC73b7ym266SRgMBrFv3z5f2c8//ywA8cYbbxxzu4UQ4tlnnxWAWLt2ra8sMzNTqFQq8cADDxzx9dOmTRMxMTHCYrH4yt566y0BiCVLlvjK1qxZIwDx/PPP+8psNptITU0VI0aMaLLeM888U4wZM+aY348MaI/RjTfeKADxxx9/HNXy7777rpgwYYKIiIgQWq1WZGRkiFdffbXJcomJiWLGjBli8eLFYvDgwUKn04m5c+eK5cuXC0B8+umn4rHHHhOxsbHCaDSK888/X1RXVwu73S7+7//+T0RERIjAwEBx1VVXCbvd3mTdh/7ItmzZIsaOHSv0er2Ii4sT//rXv8S7777b5MTR2K6VK1eKoUOHCp1OJ5KTk8V7773nt76Kigpx1113iT59+ojAwEARFBQkpk6dKjZv3tzkvdpsNvHoo4+K7t27C51OJ6Kjo8W5554rsrKyDvtZNhc8CCHErFmzBCAKCgpEXl6euOmmm0R6errQ6/UiNDRUzJo1y+89zZ8/XwBN/jUGty19F819lo3rWrlypbjttttEeHi4MJvN4vrrrxcOh0NUVVWJK664QgQHB4vg4GBxzz33NOnJqq2tFXfeeaeIj48XWq1WpKeni+eff77Jci1t+/fffxd///vfRXh4uAgICBDnnHOOKC0tbfI5/fjjj2L06NEiICBAGI1GMX36dLF9+/bDfubHIy8vT8ycOVMEBASIiIgIcccdd4jFixc3uYBo/D4b90WDwSBSU1PFwoULhRBCrFixQgwbNkzo9XqRnp4ufv75Z7/tPProowIQu3fvFpdddpkwmUwiPDxc/OMf/xBer1fs379fnHXWWSIoKEhERUWJf//7363+Xo9mnxRCiJ49e4rQ0FBRU1Nz1OteuXKl72Tz6aefCqVSKfLz84/qtbNnzxaBgYEiOztbnHHGGSIgIEDExMSIxx9/3G+/ys3N9Z1o5s6dK1JSUoRSqRSbNm0SQgixbNky3z5jNpvFWWedJXbu3Om3rcb98NCA82j3t8zMTHHBBReI8PBw33f94IMPCiH++o4P/de4reaObdnZ2WLWrFkiJCREGAwGMXz4cPH999/7LXPwcfWJJ54QcXFxQqfTiYkTJ4q9e/ce8fPNyckRgFiwYEGTOo/HI+bOnSt69eoldDqdiIyMFNdff72orKz0LfPII48IhUIhli5d6vfa6667Tmg0Gt9xs7Gdn3zyiXjggQdEVFSUCAgIEDNnzhT79+/3e21zgeHzzz8vRowYIUJDQ4VerxeDBg3y/b4O1l7Hlq+++kr07t1b6HQ60bt3b/Hll18eVUA7Y8YMkZyc3GzdaaedJgYPHuz7+0TPuUIIsW/fPpGZmXnYNjXnWAPa//znPwIQO3bs8Cv/+OOPfeeVRpGRkeKCCy5oso709HQxadKkY26rEEIMHTpUDB06tEn5GWecIVJTUw/7WovFItRqtbjnnnv8yh0OhzAajeKaa67xld1zzz1CpVL5Bb5CCPHUU08JoMm+/NJLLwmFQiEqKiqO6f3IgPYYxcXFiZSUlKNefujQoeKqq64Sc+fOFa+88oo444wzBCDmzZvnt1xiYqJIS0sTISEh4v777xevv/66WL58ue+ANmDAADFixAjx8ssvi9tvv10oFApx8cUXi0svvVRMmzZN/Oc//xFXXHGFAMTjjz/eZN0H/8gOHDggQkNDRVhYmHj88cfFv//9b9GzZ0/Rv3//ZgPaHj16iKioKPHggw+KefPmiUGDBgmFQuF3wFq3bp1ITU0V999/v3jjjTfEP//5TxEXFyfMZrPvpC5Ew+3JSZMmCUBcfPHFYt68eeLpp58WEydOFF9//fVhP8uWgodBgwYJlUol6urqxMKFC0X//v3FI488It58803x4IMPipCQEJGYmCjq6uqEEA0nvNtvv10A4sEHH/TdLi4uLj7sd9HcZ9l44B8wYICYOnWq3/dw7733itGjR4tLL71UvPrqq+LMM88UgN/FgNfrFRMnThQKhUJce+21Yt68eWLmzJkCEHfcccdhv8fGbQ8cOFBMnDhRvPLKK+Kuu+4SKpVKXHjhhX6vff/994VCoRBTp04Vr7zyinj22WdFUlKSCA4ObtWer9raWpGSkiIMBoO4//77xYsvviiGDRvm27cODWhjY2NFQkKCuOeee8Qrr7wievXqJVQqlfjkk09EdHS0eOyxx8SLL77o25cODggbg50BAwaISy65RLz66qu+23Vz5swRPXr0EDfddJN49dVXxahRowQgfv3111Z7r43v4Uj75J49ewQg/va3vx3Tum+88UbfSaW+vl4YjUbx3HPPHdVrZ8+eLfR6vej
"text/plain": [
"<Figure size 700x500 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 600x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 800x400 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"=== Carmignac Patrimoine | method=gmm ===\n",
"Clients after filtering: 3058\n",
"Chosen K: 4\n",
" cluster n_clients\n",
"0 0 359\n",
"1 1 147\n",
"2 2 411\n",
"3 3 2141\n",
"\n",
"Churn profile:\n",
" churn_hard churn_soft churn_warning\n",
"cluster \n",
"0 0.437 0.602 0.677\n",
"1 0.905 0.952 0.762\n",
"2 0.822 0.905 0.715\n",
"3 0.719 0.784 0.010\n"
]
}
],
"source": [
"# GMM — test on one family\n",
"\n",
"test_family = top_15_families[0]\n",
"result_test_gmm = run_family_clustering(\n",
" df_base=df_family_client_base,\n",
" family_name=test_family,\n",
" features=family_cluster_features,\n",
" method=\"gmm\",\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=RANDOM_STATE,\n",
" make_plots=True\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "46e92f1b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Patrimoine\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Sécurité\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Investissement\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Credit <NUM>\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Portfolio Sécurité\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Portfolio Flexible Bond\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Portfolio Credit\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Emergents\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Court Terme\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Portfolio Long-Short European Equities\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Portfolio Grande Europe\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Portfolio Emergents\n",
"==========================================================================================\n",
"[SKIP] Carmignac Portfolio Emergents (gmm): no valid K with cluster size constraints.\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Portfolio Global Bond\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Portfolio Patrimoine\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running GMM clustering for family: Carmignac Portfolio Emerging Patrimoine\n",
"==========================================================================================\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>method</th>\n",
" <th>fund_family</th>\n",
" <th>n_clients</th>\n",
" <th>best_k</th>\n",
" <th>silhouette</th>\n",
" <th>davies_bouldin</th>\n",
" <th>min_cluster_size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Emergents</td>\n",
" <td>1724</td>\n",
" <td>6</td>\n",
" <td>0.664224</td>\n",
" <td>0.882056</td>\n",
" <td>36</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>3058</td>\n",
" <td>4</td>\n",
" <td>0.620002</td>\n",
" <td>0.902274</td>\n",
" <td>147</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" <td>1099</td>\n",
" <td>4</td>\n",
" <td>0.593335</td>\n",
" <td>1.217956</td>\n",
" <td>57</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>507</td>\n",
" <td>10</td>\n",
" <td>0.590829</td>\n",
" <td>1.022110</td>\n",
" <td>11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>2126</td>\n",
" <td>6</td>\n",
" <td>0.573233</td>\n",
" <td>3.466825</td>\n",
" <td>51</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>1573</td>\n",
" <td>4</td>\n",
" <td>0.532208</td>\n",
" <td>1.317413</td>\n",
" <td>153</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>1344</td>\n",
" <td>4</td>\n",
" <td>0.526176</td>\n",
" <td>0.966015</td>\n",
" <td>66</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" <td>1053</td>\n",
" <td>4</td>\n",
" <td>0.520831</td>\n",
" <td>1.230711</td>\n",
" <td>93</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" <td>586</td>\n",
" <td>4</td>\n",
" <td>0.503059</td>\n",
" <td>1.250255</td>\n",
" <td>38</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Credit &lt;NUM&gt;</td>\n",
" <td>370</td>\n",
" <td>5</td>\n",
" <td>0.425685</td>\n",
" <td>1.128854</td>\n",
" <td>20</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" <td>1664</td>\n",
" <td>4</td>\n",
" <td>0.258280</td>\n",
" <td>1.620530</td>\n",
" <td>217</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>1125</td>\n",
" <td>7</td>\n",
" <td>0.256945</td>\n",
" <td>1.610219</td>\n",
" <td>52</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" <td>984</td>\n",
" <td>4</td>\n",
" <td>0.249737</td>\n",
" <td>1.929919</td>\n",
" <td>118</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" <td>1107</td>\n",
" <td>4</td>\n",
" <td>0.230332</td>\n",
" <td>2.659801</td>\n",
" <td>90</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" method fund_family n_clients \\\n",
"0 gmm Carmignac Emergents 1724 \n",
"1 gmm Carmignac Patrimoine 3058 \n",
"2 gmm Carmignac Portfolio Emerging Patrimoine 1099 \n",
"3 gmm Carmignac Court Terme 507 \n",
"4 gmm Carmignac Investissement 2126 \n",
"5 gmm Carmignac Sécurité 1573 \n",
"6 gmm Carmignac Portfolio Grande Europe 1344 \n",
"7 gmm Carmignac Portfolio Flexible Bond 1053 \n",
"8 gmm Carmignac Portfolio Long-Short European Equities 586 \n",
"9 gmm Carmignac Credit <NUM> 370 \n",
"10 gmm Carmignac Portfolio Global Bond 1664 \n",
"11 gmm Carmignac Portfolio Sécurité 1125 \n",
"12 gmm Carmignac Portfolio Credit 984 \n",
"13 gmm Carmignac Portfolio Patrimoine 1107 \n",
"\n",
" best_k silhouette davies_bouldin min_cluster_size \n",
"0 6 0.664224 0.882056 36 \n",
"1 4 0.620002 0.902274 147 \n",
"2 4 0.593335 1.217956 57 \n",
"3 10 0.590829 1.022110 11 \n",
"4 6 0.573233 3.466825 51 \n",
"5 4 0.532208 1.317413 153 \n",
"6 4 0.526176 0.966015 66 \n",
"7 4 0.520831 1.230711 93 \n",
"8 4 0.503059 1.250255 38 \n",
"9 5 0.425685 1.128854 20 \n",
"10 4 0.258280 1.620530 217 \n",
"11 7 0.256945 1.610219 52 \n",
"12 4 0.249737 1.929919 118 \n",
"13 4 0.230332 2.659801 90 "
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# GMM — run clustering on the top 15 fund families\n",
"\n",
"family_results_gmm = {}\n",
"family_summary_rows_gmm = []\n",
"\n",
"for fam in top_15_families:\n",
" print(\"\\n\" + \"=\" * 90)\n",
" print(f\"Running GMM clustering for family: {fam}\")\n",
" print(\"=\" * 90)\n",
"\n",
" res = run_family_clustering(\n",
" df_base=df_family_client_base,\n",
" family_name=fam,\n",
" features=family_cluster_features,\n",
" method=\"gmm\",\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=RANDOM_STATE,\n",
" make_plots=False\n",
" )\n",
"\n",
" if res is not None:\n",
" family_results_gmm[fam] = res\n",
" best_row = res[\"metrics_df\"].loc[res[\"metrics_df\"][\"k\"] == res[\"best_k\"]].iloc[0]\n",
"\n",
" family_summary_rows_gmm.append({\n",
" \"method\": \"gmm\",\n",
" \"fund_family\": fam,\n",
" \"n_clients\": res[\"n_clients\"],\n",
" \"best_k\": res[\"best_k\"],\n",
" \"silhouette\": best_row[\"silhouette\"],\n",
" \"davies_bouldin\": best_row[\"davies_bouldin\"],\n",
" \"min_cluster_size\": int(best_row[\"min_cluster_size\"]),\n",
" })\n",
"\n",
"family_summary_gmm = pd.DataFrame(family_summary_rows_gmm).sort_values(\n",
" [\"silhouette\", \"n_clients\"],\n",
" ascending=[False, False]\n",
").reset_index(drop=True)\n",
"\n",
"family_summary_gmm\n"
]
},
{
"cell_type": "markdown",
"id": "a8829205",
"metadata": {},
"source": [
"---\n",
"## Agglomerative Clustering (Ward linkage)\n",
"\n",
"This section applies hierarchical agglomerative clustering with Ward linkage.\n",
"Ward linkage is a natural benchmark because it also minimizes within-cluster variance, but without relying on centroid updates like KMeans.\n"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "7daa23a2",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[SKIP] Carmignac Patrimoine (agglo): no valid K with cluster size constraints.\n"
]
}
],
"source": [
"# Agglomerative (Ward) — test on one family\n",
"\n",
"test_family = top_15_families[0]\n",
"result_test_agglo = run_family_clustering(\n",
" df_base=df_family_client_base,\n",
" family_name=test_family,\n",
" features=family_cluster_features,\n",
" method=\"agglo\",\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=RANDOM_STATE,\n",
" make_plots=True\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": 30,
"id": "0238d752",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Patrimoine\n",
"==========================================================================================\n",
"[SKIP] Carmignac Patrimoine (agglo): no valid K with cluster size constraints.\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Sécurité\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Investissement\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Credit <NUM>\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Portfolio Sécurité\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Portfolio Flexible Bond\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Portfolio Credit\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Emergents\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Court Terme\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Portfolio Long-Short European Equities\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Portfolio Grande Europe\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Portfolio Emergents\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Portfolio Global Bond\n",
"==========================================================================================\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Portfolio Patrimoine\n",
"==========================================================================================\n",
"[SKIP] Carmignac Portfolio Patrimoine (agglo): no valid K with cluster size constraints.\n",
"\n",
"==========================================================================================\n",
"Running Agglomerative (Ward) clustering for family: Carmignac Portfolio Emerging Patrimoine\n",
"==========================================================================================\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>method</th>\n",
" <th>fund_family</th>\n",
" <th>n_clients</th>\n",
" <th>best_k</th>\n",
" <th>silhouette</th>\n",
" <th>davies_bouldin</th>\n",
" <th>min_cluster_size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>1344</td>\n",
" <td>4</td>\n",
" <td>0.870464</td>\n",
" <td>0.459435</td>\n",
" <td>36</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Emergents</td>\n",
" <td>1724</td>\n",
" <td>4</td>\n",
" <td>0.857240</td>\n",
" <td>0.500054</td>\n",
" <td>71</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>2126</td>\n",
" <td>4</td>\n",
" <td>0.848704</td>\n",
" <td>0.464014</td>\n",
" <td>64</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>1573</td>\n",
" <td>4</td>\n",
" <td>0.729010</td>\n",
" <td>0.683887</td>\n",
" <td>72</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" <td>586</td>\n",
" <td>4</td>\n",
" <td>0.727517</td>\n",
" <td>0.653392</td>\n",
" <td>23</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" <td>1099</td>\n",
" <td>4</td>\n",
" <td>0.712537</td>\n",
" <td>0.735692</td>\n",
" <td>30</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" <td>530</td>\n",
" <td>4</td>\n",
" <td>0.702277</td>\n",
" <td>0.840866</td>\n",
" <td>27</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>507</td>\n",
" <td>4</td>\n",
" <td>0.699075</td>\n",
" <td>0.640791</td>\n",
" <td>13</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" <td>1053</td>\n",
" <td>5</td>\n",
" <td>0.656056</td>\n",
" <td>0.966215</td>\n",
" <td>53</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" <td>1664</td>\n",
" <td>4</td>\n",
" <td>0.541081</td>\n",
" <td>0.576114</td>\n",
" <td>37</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Credit &lt;NUM&gt;</td>\n",
" <td>370</td>\n",
" <td>7</td>\n",
" <td>0.481484</td>\n",
" <td>0.804886</td>\n",
" <td>13</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>1125</td>\n",
" <td>4</td>\n",
" <td>0.457563</td>\n",
" <td>0.917725</td>\n",
" <td>46</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" <td>984</td>\n",
" <td>4</td>\n",
" <td>0.355641</td>\n",
" <td>0.927568</td>\n",
" <td>63</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" method fund_family n_clients \\\n",
"0 agglo Carmignac Portfolio Grande Europe 1344 \n",
"1 agglo Carmignac Emergents 1724 \n",
"2 agglo Carmignac Investissement 2126 \n",
"3 agglo Carmignac Sécurité 1573 \n",
"4 agglo Carmignac Portfolio Long-Short European Equities 586 \n",
"5 agglo Carmignac Portfolio Emerging Patrimoine 1099 \n",
"6 agglo Carmignac Portfolio Emergents 530 \n",
"7 agglo Carmignac Court Terme 507 \n",
"8 agglo Carmignac Portfolio Flexible Bond 1053 \n",
"9 agglo Carmignac Portfolio Global Bond 1664 \n",
"10 agglo Carmignac Credit <NUM> 370 \n",
"11 agglo Carmignac Portfolio Sécurité 1125 \n",
"12 agglo Carmignac Portfolio Credit 984 \n",
"\n",
" best_k silhouette davies_bouldin min_cluster_size \n",
"0 4 0.870464 0.459435 36 \n",
"1 4 0.857240 0.500054 71 \n",
"2 4 0.848704 0.464014 64 \n",
"3 4 0.729010 0.683887 72 \n",
"4 4 0.727517 0.653392 23 \n",
"5 4 0.712537 0.735692 30 \n",
"6 4 0.702277 0.840866 27 \n",
"7 4 0.699075 0.640791 13 \n",
"8 5 0.656056 0.966215 53 \n",
"9 4 0.541081 0.576114 37 \n",
"10 7 0.481484 0.804886 13 \n",
"11 4 0.457563 0.917725 46 \n",
"12 4 0.355641 0.927568 63 "
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Agglomerative (Ward) — run clustering on the top 15 fund families\n",
"\n",
"family_results_agglo = {}\n",
"family_summary_rows_agglo = []\n",
"\n",
"for fam in top_15_families:\n",
" print(\"\\n\" + \"=\" * 90)\n",
" print(f\"Running Agglomerative (Ward) clustering for family: {fam}\")\n",
" print(\"=\" * 90)\n",
"\n",
" res = run_family_clustering(\n",
" df_base=df_family_client_base,\n",
" family_name=fam,\n",
" features=family_cluster_features,\n",
" method=\"agglo\",\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=RANDOM_STATE,\n",
" make_plots=False\n",
" )\n",
"\n",
" if res is not None:\n",
" family_results_agglo[fam] = res\n",
" best_row = res[\"metrics_df\"].loc[res[\"metrics_df\"][\"k\"] == res[\"best_k\"]].iloc[0]\n",
"\n",
" family_summary_rows_agglo.append({\n",
" \"method\": \"agglo\",\n",
" \"fund_family\": fam,\n",
" \"n_clients\": res[\"n_clients\"],\n",
" \"best_k\": res[\"best_k\"],\n",
" \"silhouette\": best_row[\"silhouette\"],\n",
" \"davies_bouldin\": best_row[\"davies_bouldin\"],\n",
" \"min_cluster_size\": int(best_row[\"min_cluster_size\"]),\n",
" })\n",
"\n",
"family_summary_agglo = pd.DataFrame(family_summary_rows_agglo).sort_values(\n",
" [\"silhouette\", \"n_clients\"],\n",
" ascending=[False, False]\n",
").reset_index(drop=True)\n",
"\n",
"family_summary_agglo\n"
]
},
{
"cell_type": "markdown",
"id": "2495316e",
"metadata": {},
"source": [
"---\n",
"## Comparison of the three clustering methods\n",
"\n",
"The tables below compare KMeans, Gaussian Mixture, and Agglomerative (Ward) clustering:\n",
"- on one selected family,\n",
"- and across the top 15 families.\n",
"\n",
"This comparison helps assess whether the segmentation is method-specific or robust across algorithms.\n"
]
},
{
"cell_type": "code",
"execution_count": 31,
"id": "a79dd797",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[SKIP] Carmignac Patrimoine (agglo): no valid K with cluster size constraints.\n"
]
},
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>method</th>\n",
" <th>family</th>\n",
" <th>n_clients</th>\n",
" <th>best_k</th>\n",
" <th>silhouette</th>\n",
" <th>davies_bouldin</th>\n",
" <th>min_cluster_size</th>\n",
" <th>status</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>3058.0</td>\n",
" <td>4.0</td>\n",
" <td>0.882916</td>\n",
" <td>0.443551</td>\n",
" <td>85.0</td>\n",
" <td>ok</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>3058.0</td>\n",
" <td>4.0</td>\n",
" <td>0.620002</td>\n",
" <td>0.902274</td>\n",
" <td>147.0</td>\n",
" <td>ok</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>NaN</td>\n",
" <td>skip</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" method family n_clients best_k silhouette \\\n",
"0 kmeans Carmignac Patrimoine 3058.0 4.0 0.882916 \n",
"1 gmm Carmignac Patrimoine 3058.0 4.0 0.620002 \n",
"2 agglo Carmignac Patrimoine NaN NaN NaN \n",
"\n",
" davies_bouldin min_cluster_size status \n",
"0 0.443551 85.0 ok \n",
"1 0.902274 147.0 ok \n",
"2 NaN NaN skip "
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Compare the three methods on one selected family\n",
"\n",
"comparison_one_family = compare_methods_for_family(\n",
" df_base=df_family_client_base,\n",
" family_name=top_15_families[0],\n",
" features=family_cluster_features,\n",
" methods=(\"kmeans\", \"gmm\", \"agglo\"),\n",
" k_min=4,\n",
" k_max=10,\n",
" min_clients=40,\n",
" min_cluster_size=10,\n",
" min_cluster_share=0.02,\n",
" random_state=RANDOM_STATE\n",
")\n",
"\n",
"comparison_one_family.sort_values([\"silhouette\", \"davies_bouldin\"], ascending=[False, True])\n"
]
},
{
"cell_type": "code",
"execution_count": 32,
"id": "7a49e624",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>method</th>\n",
" <th>fund_family</th>\n",
" <th>n_clients</th>\n",
" <th>best_k</th>\n",
" <th>silhouette</th>\n",
" <th>davies_bouldin</th>\n",
" <th>min_cluster_size</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>507</td>\n",
" <td>4</td>\n",
" <td>0.714238</td>\n",
" <td>0.690596</td>\n",
" <td>17</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>507</td>\n",
" <td>4</td>\n",
" <td>0.699075</td>\n",
" <td>0.640791</td>\n",
" <td>13</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Court Terme</td>\n",
" <td>507</td>\n",
" <td>10</td>\n",
" <td>0.590829</td>\n",
" <td>1.022110</td>\n",
" <td>11</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Credit &lt;NUM&gt;</td>\n",
" <td>370</td>\n",
" <td>4</td>\n",
" <td>0.533313</td>\n",
" <td>0.996512</td>\n",
" <td>25</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Credit &lt;NUM&gt;</td>\n",
" <td>370</td>\n",
" <td>7</td>\n",
" <td>0.481484</td>\n",
" <td>0.804886</td>\n",
" <td>13</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Credit &lt;NUM&gt;</td>\n",
" <td>370</td>\n",
" <td>5</td>\n",
" <td>0.425685</td>\n",
" <td>1.128854</td>\n",
" <td>20</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Emergents</td>\n",
" <td>1724</td>\n",
" <td>4</td>\n",
" <td>0.857240</td>\n",
" <td>0.500054</td>\n",
" <td>71</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Emergents</td>\n",
" <td>1724</td>\n",
" <td>6</td>\n",
" <td>0.664224</td>\n",
" <td>0.882056</td>\n",
" <td>36</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>2126</td>\n",
" <td>4</td>\n",
" <td>0.872248</td>\n",
" <td>0.450959</td>\n",
" <td>74</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>2126</td>\n",
" <td>4</td>\n",
" <td>0.848704</td>\n",
" <td>0.464014</td>\n",
" <td>64</td>\n",
" </tr>\n",
" <tr>\n",
" <th>10</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Investissement</td>\n",
" <td>2126</td>\n",
" <td>6</td>\n",
" <td>0.573233</td>\n",
" <td>3.466825</td>\n",
" <td>51</td>\n",
" </tr>\n",
" <tr>\n",
" <th>11</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>3058</td>\n",
" <td>4</td>\n",
" <td>0.882916</td>\n",
" <td>0.443551</td>\n",
" <td>85</td>\n",
" </tr>\n",
" <tr>\n",
" <th>12</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Patrimoine</td>\n",
" <td>3058</td>\n",
" <td>4</td>\n",
" <td>0.620002</td>\n",
" <td>0.902274</td>\n",
" <td>147</td>\n",
" </tr>\n",
" <tr>\n",
" <th>13</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" <td>984</td>\n",
" <td>4</td>\n",
" <td>0.366476</td>\n",
" <td>1.024236</td>\n",
" <td>48</td>\n",
" </tr>\n",
" <tr>\n",
" <th>14</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" <td>984</td>\n",
" <td>4</td>\n",
" <td>0.355641</td>\n",
" <td>0.927568</td>\n",
" <td>63</td>\n",
" </tr>\n",
" <tr>\n",
" <th>15</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Credit</td>\n",
" <td>984</td>\n",
" <td>4</td>\n",
" <td>0.249737</td>\n",
" <td>1.929919</td>\n",
" <td>118</td>\n",
" </tr>\n",
" <tr>\n",
" <th>16</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Emergents</td>\n",
" <td>530</td>\n",
" <td>4</td>\n",
" <td>0.702277</td>\n",
" <td>0.840866</td>\n",
" <td>27</td>\n",
" </tr>\n",
" <tr>\n",
" <th>17</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" <td>1099</td>\n",
" <td>5</td>\n",
" <td>0.776536</td>\n",
" <td>0.690654</td>\n",
" <td>26</td>\n",
" </tr>\n",
" <tr>\n",
" <th>18</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" <td>1099</td>\n",
" <td>4</td>\n",
" <td>0.712537</td>\n",
" <td>0.735692</td>\n",
" <td>30</td>\n",
" </tr>\n",
" <tr>\n",
" <th>19</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Emerging Patrimoine</td>\n",
" <td>1099</td>\n",
" <td>4</td>\n",
" <td>0.593335</td>\n",
" <td>1.217956</td>\n",
" <td>57</td>\n",
" </tr>\n",
" <tr>\n",
" <th>20</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" <td>1053</td>\n",
" <td>4</td>\n",
" <td>0.675407</td>\n",
" <td>0.801578</td>\n",
" <td>40</td>\n",
" </tr>\n",
" <tr>\n",
" <th>21</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" <td>1053</td>\n",
" <td>5</td>\n",
" <td>0.656056</td>\n",
" <td>0.966215</td>\n",
" <td>53</td>\n",
" </tr>\n",
" <tr>\n",
" <th>22</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Flexible Bond</td>\n",
" <td>1053</td>\n",
" <td>4</td>\n",
" <td>0.520831</td>\n",
" <td>1.230711</td>\n",
" <td>93</td>\n",
" </tr>\n",
" <tr>\n",
" <th>23</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" <td>1664</td>\n",
" <td>4</td>\n",
" <td>0.541081</td>\n",
" <td>0.576114</td>\n",
" <td>37</td>\n",
" </tr>\n",
" <tr>\n",
" <th>24</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" <td>1664</td>\n",
" <td>4</td>\n",
" <td>0.532877</td>\n",
" <td>0.680604</td>\n",
" <td>70</td>\n",
" </tr>\n",
" <tr>\n",
" <th>25</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Global Bond</td>\n",
" <td>1664</td>\n",
" <td>4</td>\n",
" <td>0.258280</td>\n",
" <td>1.620530</td>\n",
" <td>217</td>\n",
" </tr>\n",
" <tr>\n",
" <th>26</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>1344</td>\n",
" <td>4</td>\n",
" <td>0.870464</td>\n",
" <td>0.459435</td>\n",
" <td>36</td>\n",
" </tr>\n",
" <tr>\n",
" <th>27</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>1344</td>\n",
" <td>4</td>\n",
" <td>0.865687</td>\n",
" <td>0.464262</td>\n",
" <td>39</td>\n",
" </tr>\n",
" <tr>\n",
" <th>28</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Grande Europe</td>\n",
" <td>1344</td>\n",
" <td>4</td>\n",
" <td>0.526176</td>\n",
" <td>0.966015</td>\n",
" <td>66</td>\n",
" </tr>\n",
" <tr>\n",
" <th>29</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" <td>586</td>\n",
" <td>4</td>\n",
" <td>0.727517</td>\n",
" <td>0.653392</td>\n",
" <td>23</td>\n",
" </tr>\n",
" <tr>\n",
" <th>30</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" <td>586</td>\n",
" <td>4</td>\n",
" <td>0.717091</td>\n",
" <td>0.635826</td>\n",
" <td>28</td>\n",
" </tr>\n",
" <tr>\n",
" <th>31</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Long-Short European Equities</td>\n",
" <td>586</td>\n",
" <td>4</td>\n",
" <td>0.503059</td>\n",
" <td>1.250255</td>\n",
" <td>38</td>\n",
" </tr>\n",
" <tr>\n",
" <th>32</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" <td>1107</td>\n",
" <td>5</td>\n",
" <td>0.297069</td>\n",
" <td>1.067643</td>\n",
" <td>29</td>\n",
" </tr>\n",
" <tr>\n",
" <th>33</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Patrimoine</td>\n",
" <td>1107</td>\n",
" <td>4</td>\n",
" <td>0.230332</td>\n",
" <td>2.659801</td>\n",
" <td>90</td>\n",
" </tr>\n",
" <tr>\n",
" <th>34</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>1125</td>\n",
" <td>4</td>\n",
" <td>0.457563</td>\n",
" <td>0.917725</td>\n",
" <td>46</td>\n",
" </tr>\n",
" <tr>\n",
" <th>35</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>1125</td>\n",
" <td>4</td>\n",
" <td>0.451412</td>\n",
" <td>0.935678</td>\n",
" <td>46</td>\n",
" </tr>\n",
" <tr>\n",
" <th>36</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Portfolio Sécurité</td>\n",
" <td>1125</td>\n",
" <td>7</td>\n",
" <td>0.256945</td>\n",
" <td>1.610219</td>\n",
" <td>52</td>\n",
" </tr>\n",
" <tr>\n",
" <th>37</th>\n",
" <td>agglo</td>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>1573</td>\n",
" <td>4</td>\n",
" <td>0.729010</td>\n",
" <td>0.683887</td>\n",
" <td>72</td>\n",
" </tr>\n",
" <tr>\n",
" <th>38</th>\n",
" <td>kmeans</td>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>1573</td>\n",
" <td>4</td>\n",
" <td>0.697358</td>\n",
" <td>0.776298</td>\n",
" <td>86</td>\n",
" </tr>\n",
" <tr>\n",
" <th>39</th>\n",
" <td>gmm</td>\n",
" <td>Carmignac Sécurité</td>\n",
" <td>1573</td>\n",
" <td>4</td>\n",
" <td>0.532208</td>\n",
" <td>1.317413</td>\n",
" <td>153</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" method fund_family n_clients \\\n",
"0 kmeans Carmignac Court Terme 507 \n",
"1 agglo Carmignac Court Terme 507 \n",
"2 gmm Carmignac Court Terme 507 \n",
"3 kmeans Carmignac Credit <NUM> 370 \n",
"4 agglo Carmignac Credit <NUM> 370 \n",
"5 gmm Carmignac Credit <NUM> 370 \n",
"6 agglo Carmignac Emergents 1724 \n",
"7 gmm Carmignac Emergents 1724 \n",
"8 kmeans Carmignac Investissement 2126 \n",
"9 agglo Carmignac Investissement 2126 \n",
"10 gmm Carmignac Investissement 2126 \n",
"11 kmeans Carmignac Patrimoine 3058 \n",
"12 gmm Carmignac Patrimoine 3058 \n",
"13 kmeans Carmignac Portfolio Credit 984 \n",
"14 agglo Carmignac Portfolio Credit 984 \n",
"15 gmm Carmignac Portfolio Credit 984 \n",
"16 agglo Carmignac Portfolio Emergents 530 \n",
"17 kmeans Carmignac Portfolio Emerging Patrimoine 1099 \n",
"18 agglo Carmignac Portfolio Emerging Patrimoine 1099 \n",
"19 gmm Carmignac Portfolio Emerging Patrimoine 1099 \n",
"20 kmeans Carmignac Portfolio Flexible Bond 1053 \n",
"21 agglo Carmignac Portfolio Flexible Bond 1053 \n",
"22 gmm Carmignac Portfolio Flexible Bond 1053 \n",
"23 agglo Carmignac Portfolio Global Bond 1664 \n",
"24 kmeans Carmignac Portfolio Global Bond 1664 \n",
"25 gmm Carmignac Portfolio Global Bond 1664 \n",
"26 agglo Carmignac Portfolio Grande Europe 1344 \n",
"27 kmeans Carmignac Portfolio Grande Europe 1344 \n",
"28 gmm Carmignac Portfolio Grande Europe 1344 \n",
"29 agglo Carmignac Portfolio Long-Short European Equities 586 \n",
"30 kmeans Carmignac Portfolio Long-Short European Equities 586 \n",
"31 gmm Carmignac Portfolio Long-Short European Equities 586 \n",
"32 kmeans Carmignac Portfolio Patrimoine 1107 \n",
"33 gmm Carmignac Portfolio Patrimoine 1107 \n",
"34 agglo Carmignac Portfolio Sécurité 1125 \n",
"35 kmeans Carmignac Portfolio Sécurité 1125 \n",
"36 gmm Carmignac Portfolio Sécurité 1125 \n",
"37 agglo Carmignac Sécurité 1573 \n",
"38 kmeans Carmignac Sécurité 1573 \n",
"39 gmm Carmignac Sécurité 1573 \n",
"\n",
" best_k silhouette davies_bouldin min_cluster_size \n",
"0 4 0.714238 0.690596 17 \n",
"1 4 0.699075 0.640791 13 \n",
"2 10 0.590829 1.022110 11 \n",
"3 4 0.533313 0.996512 25 \n",
"4 7 0.481484 0.804886 13 \n",
"5 5 0.425685 1.128854 20 \n",
"6 4 0.857240 0.500054 71 \n",
"7 6 0.664224 0.882056 36 \n",
"8 4 0.872248 0.450959 74 \n",
"9 4 0.848704 0.464014 64 \n",
"10 6 0.573233 3.466825 51 \n",
"11 4 0.882916 0.443551 85 \n",
"12 4 0.620002 0.902274 147 \n",
"13 4 0.366476 1.024236 48 \n",
"14 4 0.355641 0.927568 63 \n",
"15 4 0.249737 1.929919 118 \n",
"16 4 0.702277 0.840866 27 \n",
"17 5 0.776536 0.690654 26 \n",
"18 4 0.712537 0.735692 30 \n",
"19 4 0.593335 1.217956 57 \n",
"20 4 0.675407 0.801578 40 \n",
"21 5 0.656056 0.966215 53 \n",
"22 4 0.520831 1.230711 93 \n",
"23 4 0.541081 0.576114 37 \n",
"24 4 0.532877 0.680604 70 \n",
"25 4 0.258280 1.620530 217 \n",
"26 4 0.870464 0.459435 36 \n",
"27 4 0.865687 0.464262 39 \n",
"28 4 0.526176 0.966015 66 \n",
"29 4 0.727517 0.653392 23 \n",
"30 4 0.717091 0.635826 28 \n",
"31 4 0.503059 1.250255 38 \n",
"32 5 0.297069 1.067643 29 \n",
"33 4 0.230332 2.659801 90 \n",
"34 4 0.457563 0.917725 46 \n",
"35 4 0.451412 0.935678 46 \n",
"36 7 0.256945 1.610219 52 \n",
"37 4 0.729010 0.683887 72 \n",
"38 4 0.697358 0.776298 86 \n",
"39 4 0.532208 1.317413 153 "
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Compare the three methods across all top 15 families\n",
"\n",
"comparison_all_methods = pd.concat(\n",
" [family_summary_kmeans, family_summary_gmm, family_summary_agglo],\n",
" axis=0,\n",
" ignore_index=True\n",
")\n",
"\n",
"comparison_all_methods = comparison_all_methods.sort_values(\n",
" [\"fund_family\", \"silhouette\"],\n",
" ascending=[True, False]\n",
").reset_index(drop=True)\n",
"\n",
"comparison_all_methods\n"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "68d73439",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>method</th>\n",
" <th>n_families</th>\n",
" <th>avg_silhouette</th>\n",
" <th>avg_davies_bouldin</th>\n",
" <th>avg_best_k</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>agglo</td>\n",
" <td>13</td>\n",
" <td>0.664511</td>\n",
" <td>0.705434</td>\n",
" <td>4.307692</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>kmeans</td>\n",
" <td>13</td>\n",
" <td>0.644817</td>\n",
" <td>0.742954</td>\n",
" <td>4.153846</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>gmm</td>\n",
" <td>14</td>\n",
" <td>0.467491</td>\n",
" <td>1.514638</td>\n",
" <td>5.000000</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" method n_families avg_silhouette avg_davies_bouldin avg_best_k\n",
"0 agglo 13 0.664511 0.705434 4.307692\n",
"2 kmeans 13 0.644817 0.742954 4.153846\n",
"1 gmm 14 0.467491 1.514638 5.000000"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Method-level average metrics across families\n",
"\n",
"method_comparison_summary = (\n",
" comparison_all_methods.groupby(\"method\", as_index=False)\n",
" .agg(\n",
" n_families=(\"fund_family\", \"count\"),\n",
" avg_silhouette=(\"silhouette\", \"mean\"),\n",
" avg_davies_bouldin=(\"davies_bouldin\", \"mean\"),\n",
" avg_best_k=(\"best_k\", \"mean\")\n",
" )\n",
" .sort_values([\"avg_silhouette\", \"avg_davies_bouldin\"], ascending=[False, True])\n",
")\n",
"\n",
"method_comparison_summary\n"
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"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.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}