Skip to content

View or edit on GitHub

This page is synchronized from trase/data/cote_divoire/trade/list_for_zdc_request.ipynb. Last modified on 2026-08-05 15:56 CEST by Harry Biddle. Please view or edit the original file there; changes should be reflected here after a midnight build (CET time), or manually triggering it with a GitHub action (link).

import boto3
from botocore.exceptions import NoCredentialsError, ClientError

def check_aws_access():
    sts = boto3.client('sts')
    try:
        # Ask AWS "Who am I?"
        identity = sts.get_caller_identity()
        print("✅ Access Confirmed!")
        print(f"   Account: {identity['Account']}")
        print(f"   ARN:     {identity['Arn']}")

        # Optional: Check S3 specifically
        s3 = boto3.client('s3')
        s3.list_objects_v2(Bucket='trase-storage', MaxKeys=1)
        print("✅ S3 Bucket 'trase-storage' is accessible.")

    except NoCredentialsError:
        print("❌ No AWS credentials found.")
    except ClientError as e:
        print(f"❌ Credentials found, but access denied: {e}")
    except Exception as e:
        print(f"❌ Error: {e}")

check_aws_access()
import pandas as pd

# Direct read from S3
path = 's3://trase-storage/cote_divoire/trade/cd/originals/CIV_2024_all_one_sheet.xlsx'

# Read the file
df = pd.read_excel(path)
df.replace(r'\n', '', regex=True, inplace=True)

# Check the data
display(df.head())
YEAR DATE MONTH RGITAR SENS IMMIMP EXPORTER SUPPLIER GEN_CTY_DES_COD DESTINATION ... TRANSPORT MODE SH COMMERCIAL PRODUCT DESC NATURE_COLIS UNIT QUANTITY FOB VALUE CIF VALUE NET WEIGHT GROSS WEIGHT
0 2024 17/01/2024 1 E EXPORT 0815951Y SOCIETE DE COMMERCIALISATION DE CAFE ET CACAO01 AGRI COMMODITIES & FINANCE.FZ-LLC P.O. BOX 330578 FR France ... Transport maritime 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... VR VR - Vrac solide, particules granuleuses 1 355521478 355521478 200200 200200
1 2024 17/01/2024 1 E EXPORT 1105355G SUCDEN COTE D'IVOIRE15 BP 727 ABIDJAN (VILLE) 15 SUCRES ET DENREES20/22 RUE DE LA VILLE L EVEQUE 7 EE ESTONIE ... Transport maritime 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... SA SA - Sac ("sack") 1155 115231310 115231310 75075 75849
2 2024 17/01/2024 1 E EXPORT 0815951Y SOCIETE DE COMMERCIALISATION DE CAFE ET CACAO01 B COCOA TEAM 8 RUE SAINTE THERESE 33000 BORDEREAUX DE Allemagne ... Transport maritime 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... VR VR - Vrac solide, particules granuleuses 1 296701158 296701158 175175 175175
3 2024 09/01/2024 1 E EXPORT 0918197U CASB-SCOOPSBP 924 BOUAFLE (VILLE)BONON - ECOM AGROTRADE .LTD 10TH FLOOR 55 OLD STREET TEL: TR Turquie ... Transport maritime 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... SA SA - Sac ("sack") 10780 1224562174 1224562174 700700 707924
4 2024 09/01/2024 1 E EXPORT 0815951Y SOCIETE DE COMMERCIALISATION DE CAFE ET CACAO01 B JB FOODS GLOBAL PTE.LTD.80 ROBINSON ROAD #17-020 MY Malaisie ... Transport maritime 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... SA SA - Sac ("sack") 1155 132425911 132425911 75075 75849

5 rows × 23 columns


2021 Count: 691
2022 Count: 727
2023 Count: 798
2024 Count: 1038
df.columns
Index(['YEAR', 'DATE', 'MONTH', 'RGITAR', 'SENS', 'IMMIMP', 'EXPORTER ',
       'SUPPLIER', 'GEN_CTY_DES_COD', 'DESTINATION', 'GEN_CTY_ORG', 'ORIGINE',
       'CODE_MODE_TRANSP_FRONTIERE', 'TRANSPORT MODE', 'SH',
       'COMMERCIAL PRODUCT DESC', 'NATURE_COLIS', 'UNIT', 'QUANTITY',
       'FOB VALUE', 'CIF VALUE', 'NET WEIGHT', 'GROSS WEIGHT'],
      dtype='object')
cols_to_fix = ['NET WEIGHT', 'GROSS WEIGHT', 'CIF VALUE']
for col in cols_to_fix:
    df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
df.SUPPLIER.unique()
array(['AGRI COMMODITIES & FINANCE.FZ-LLC P.O. BOX 330578',
       'SUCRES ET DENREES20/22 RUE DE LA VILLE L EVEQUE 7',
       'COCOA TEAM 8 RUE SAINTE THERESE 33000 BORDEREAUX', ...,
       'PALMART GIDA KIMYA DIS TICARET LTD STI',
       'PATISEN SA10 RUE MALAN BP 185 DAKAR / SENEGALDOS',
       'CARGILL BV CARGILL COCOA & CHOCOLATE 1118 CZ SCHI'], dtype=object)
import pandas as pd

# --- EXPANDED MAPPING DICTIONARY ---
keyword_map = {
    # --- MAJOR TRADERS ---
    'CARGILL': 'CARGILL',
    'OLAM': 'OLAM',
    'TOUTON': 'TOUTON',
    'TUTON': 'TOUTON',
    'BARRY': 'BARRY CALLEBAUT',
    'CALLEBAUT': 'BARRY CALLEBAUT',
    'BC COCOA': 'BARRY CALLEBAUT',
    'BC  COCOA': 'BARRY CALLEBAUT', # Catches double spacing
    'HARDTURMSTRASSE': 'BARRY CALLEBAUT', # Catches rows with only address
    'ECOM': 'ECOM',
    'THEOBROMA': 'THEOBROMA',
    'THEOBOMA': 'THEOBROMA', # Typo in data
    'GCB': 'GCB COCOA',
    'WALTER MATTER': 'WALTER MATTER',
    'WALTER  MATTER': 'WALTER MATTER', # Double spacing
    'COCOASOURCE': 'COCOASOURCE',
    'COCOA SOURCE': 'COCOASOURCE',
    'COCOA SUCRE': 'COCOASOURCE', # Likely related or similar naming convention
    'ALBRECHT': 'ALBRECHT & DILL',
    'ALBERCHT': 'ALBRECHT & DILL', # Typo in data

    # --- SUCDEN VARIATIONS ---
    'SUCDEN': 'SUCDEN',
    'SUCRES': 'SUCDEN', 
    'DENREE': 'SUCDEN', 
    'DENRÉES': 'SUCDEN',

    # --- SPECIFIC ENTITIES FROM YOUR LIST ---
    'HUYSER': 'HUYSER MÖLLER',
    'MARKEY': 'R. MARKEY & SONS',
    'ONEM GIDA': 'ONEM GIDA',
    'LOGIKA': 'LOGIKA',
    'MOI INTERNATIONAL': 'MOI INTERNATIONAL',
    'COTTERELL': 'H.D. COTTERELL',
    'FUCHS': 'FUCHS & HOFFMANN',
    'FACTA': 'FACTA INTERNATIONAL',
    'FACTS INTERNATIONAL': 'FACTA INTERNATIONAL',
    'PACTA': 'FACTA INTERNATIONAL', # Typo in data
    'ASIA COCOA INDONESIA': 'ASIA COCOA INDONESIA',
    'ALTINMARKA': 'ALTINMARKA',
    'CACAO LATITUDES': 'CACAO LATITUDES',
    'AGROINDUSTRIAS': 'AGROINDUSTRIAS UNIDAS',
    'IVCOM': 'IVCOM',
    'ECORIGINE': 'ECORIGINE',
    'CEMOI': 'CEMOI',
    'ENTREP COOPERA': 'ENTREP COOPERA',
    'AFRICA SOURCING': 'AFRICA SOURCING',
    'TRANSCAO': 'TRANSCAO',
    'OUTSPAN': 'OUTSPAN',
    'ETHIQUABLE': 'ETHIQUABLE',
    'COMERCIALIZADORA': 'COMERCIALIZADORA ECO CACAO',
    'COMMERCIALIZADORA': 'COMERCIALIZADORA ECO CACAO', # Typo/Spelling
    'AGROFOREST': 'AGROFOREST',
    'PPC GRYF': 'PPC GRYF',
    'ULKER': 'ULKER',
    'NINH THUAN': 'NINH THUAN NITAGREX',
    'CEVA': 'CEVA LOGISTICS',
    'TERRACORE': 'TERRACORE',
    'DEPENDABLE': 'DEPENDABLE DISTRIBUTION',
    'DOMORI': 'DOMORI',
    'GUAN CHONG': 'GUAN CHONG',
    'ALCAO': 'ALCAO',
    'DP.COCO': 'DP COCO',
    'GEZAIRI': 'GEZAIRI TRANS',
    'JS COCOA': 'JS COCOA',
    'JS. COCOA': 'JS COCOA', 
    'JS.COCOA': 'JS COCOA',
    'BALTIC': 'BALTIC COCOA', # Broadened to catch "U A B BALTIC"
    'SINTAG': 'SINTAG',
    'PACHE': 'F. PACHE',
    'PANAMIR': 'PANAMIR',
    'DE MAN': 'DE MAN MET SMAAK',
    'ELSHAMADAN': 'EL SHAMADAN',
    'EL SHAMADAN': 'EL SHAMADAN',
    'ANHUI': 'ANHUI IMPORT',
    'DKS': 'DKS COCOA',
    'LIFE BV': 'LIFE BV',
    'LIFE B.V': 'LIFE BV',
    'INDCRE': 'INDCRESA',
    'IBERCOMMODITIES': 'IBERCOMMODITIES', 
    'IBER COMMODITIES': 'IBERCOMMODITIES',
    'IBERCOMMODITES': 'IBERCOMMODITIES', # Typo in data
    'AGRI MANGEMENT': 'AGRI COMMODITIES',
    'PT ANEKA': 'PT ANEKA',
    'INDUSTRIAL FOOD': 'INDUSTRIAL FOOD COMPANY',
    'LACASA': 'LACASA',
    'EUROPRALINE': 'EUROPRALINE',
    'EUROPROLINE': 'EUROPRALINE',
    'ARGINI': 'ARGINI TRADING',
    'CENTRUM': 'CENTRUM INFORMACJI',
    'ALINDA': 'ALINDA-VELCO',
    'PASTOR': 'PASTOR SA',
    'GIBSON': 'GIBSON LLC',
    'LACTAVIT': 'LACTAVIT',
    'GARLAND': 'GARLAND',
    'YIOTIS': 'YIOTIS',
    'MULTITRADE': 'MULTITRADE SPAIN',
    'MULTLITRADE': 'MULTITRADE SPAIN',
    'MULTIRADE': 'MULTITRADE SPAIN',
    'AL ZAYTUNA': 'AL ZAYTUNA',
    'S.GROUP': 'S GROUP SL',
    'S GROUP': 'S GROUP SL',
    'INDUSTRIA CAPIXABA': 'INDUSTRIA CAPIXABA',
    'C&R': 'C&R COMMODITIES',
    'C & R': 'C&R COMMODITIES',
    'TCC TURIZM': 'TCC TURIZM',
    'CAMPAGNOLI': 'CAMPAGNOLI & RODRIGUEZ',
    'PLOT ENTERPRISE': 'PLOT ENTERPRISE',
    'MIESZKAO': 'MIESZKO',
    'MIESZKO': 'MIESZKO',
    'MONPIT': 'MONPIT',
    'LA CREMA': 'LA CREMA',
    'KWIK HOLLAND': 'KWIK HOLLAND',
    'INGREDIOR': 'INGREDIOR',
    'VICOCOA': 'VICOCOA',
    'TRADING & SERVICES': 'TRADING & SERVICES',
    'ATC AFRICA': 'ATC AFRICA',
    'CACAO LIFE': 'CACAO LIFE',
    'IP RUMYANTSE': 'IP RUMYANTSE',
    'SEN ALIM': 'SEN ALIM',
    'LE FOUR': 'LE FOUR DU KHALIFE',
    'CRISA': 'CRISA',
    'ALBACORA': 'ALBACORA',
    'AMAR TRADING': 'AMAR TRADING',
    'LEBANESE ROASTERY': 'LEBANESE ROASTERY',
    'CANADA INC': 'CANADA INC (11601148)',
    'SOFAPRAL': 'SOFAPRAL',
    'NEW FOODS': 'NEW FOODS',
    'HABIBO': 'HABIBO',
    'IMCD': 'IMCD',
    'CHRISTINE GLOUX': 'CHRISTINE GLOUX',
    'CARRE MARCHE': 'CARRE MARCHE',
    'PALMART': 'PALMART',
    'SENALIA': 'SENALIA',
    'ROMSHIP': 'ROMSHIP',
    'SOBCO': 'SOBCO',
    'IVOIRE CACAO': 'IVOIRE CACAO',
    'KANSO': 'KANSO KASSEM',
    'SOCIETE AGRICOLE': 'SACC',
    'ECAKOOG': 'ECAKOOG',
    'IGI SPA': 'IGI SPA',

    # --- ORIGINAL LIST (RETAINED) ---
    'NEDERLAND': 'NEDERLAND SA',
    'IBERCACAO': 'IBERCACAO',
    'AGROFORCE': 'AGROFORCE',
    'ASCOT': 'ASCOT AMSTERDAM',
    'ACT INTER': 'ACT INTERNATIONAL',
    'AFRICAO': 'AFRICAO',
    'AGRI COMMODITIES': 'AGRI COMMODITIES',
    'MONER': 'MONER COCOA',
    'TAN MONDIAL': 'TAN MONDIAL',
    'JB FOOD': 'JB FOODS',
    'JB COCOA': 'JB FOODS',
    'KSW': 'KSW GLOBAL',
    'ARASCO': 'ARASCO',
    'ARSCO': 'ARASCO', # Typo in data
    'COMOD': 'COMOD',
    'VIGOLIN': 'VIGOLIN',
    'TRILINI': 'TRILINI',
    'TEPCO': 'TEPCO',
    'MISCAL': 'MISCAL',
    'COCOA TEAM': 'COCOA TEAM',
    'CHOCOLATES DEL NORTE': 'CHOCOLATES DEL NORTE',
    'DEL NORTE': 'CHOCOLATES DEL NORTE',
    'UCOM': 'UCOM',
    'ANCILE': 'ANCILE',
    'QUAST': 'QUAST & CONS',
    'LOTTE': 'LOTTE',
    'YIWU': 'YIWU XINDU',
    'SENICO': 'SENICO',
    'PATISEN': 'PATISEN',
    'KATOEN': 'KATOEN NATIE',
    'BOLLORE': 'BOLLORE',
    'CWT': 'CWT COMMODITIES',
    'FERRERO': 'FERRERO',
    'NESTLE': 'NESTLE',
    'MARS': 'MARS',
    'MITSUI': 'MITSUI'
}

def clean_company_name(text):
    if pd.isna(text):
        return text

    # Convert to upper case for matching
    text_upper = str(text).upper()

    # Check for keywords
    for keyword, standard_name in keyword_map.items():
        if keyword in text_upper:
            return standard_name

    # Return original text if no match found
    return text

# Apply the cleaning
df['SUPPLIER_CLEAN'] = df['SUPPLIER'].apply(clean_company_name)

# --- VALIDATION ---
print("--- Top 40 Suppliers (Cleaned) ---")
print(df['SUPPLIER_CLEAN'].value_counts().head(40))

# OPTIONAL: Check what is left
clean_names = set(keyword_map.values())
uncrunchable = df[
    (df['SUPPLIER_CLEAN'].str.len() > 20) & 
    (~df['SUPPLIER_CLEAN'].isin(clean_names))
]['SUPPLIER_CLEAN'].unique()
print("\n--- Remaining Messy Rows ---")
print(uncrunchable)
--- Top 40 Suppliers (Cleaned) ---
CARGILL                 2616
BARRY CALLEBAUT         2279
OLAM                    2138
SUCDEN                   938
ECOM                     730
THEOBROMA                658
GCB COCOA                621
TOUTON                   426
ACT INTERNATIONAL        299
COMOD                    252
COCOASOURCE              193
AFRICAO                  182
AGRI COMMODITIES         176
CEMOI                    157
UCOM                     156
MONER COCOA              136
TAN MONDIAL              100
JB FOODS                  85
KSW GLOBAL                79
DKS COCOA                 77
IBERCACAO                 69
ALBRECHT & DILL           65
NEDERLAND SA              63
VIGOLIN                   44
YIWU XINDU                39
INDCRESA                  38
FACTA INTERNATIONAL       34
AGROFORCE                 33
ARASCO                    33
WALTER MATTER             29
LOGIKA                    28
BALTIC COCOA              28
PPC GRYF                  25
ASCOT AMSTERDAM           24
TRILINI                   24
COCOA TEAM                22
CHOCOLATES DEL NORTE      22
KATOEN NATIE              19
ROMSHIP                   19
QUAST & CONS              16
Name: SUPPLIER_CLEAN, dtype: int64

--- Remaining Messy Rows ---
['DIVERS  DESTINATAIRES' 'STE COOP UN.PROD AGR DJAK BP 1205SAN-PEDROCITE-'
 'STE COOP AGRI DE TOUIH BP 142 SAN-PEDRO (VILLE)T'
 'STE COOP AGRI DE TOUIHBP 142 SAN-PEDRO (VILLE)TO'
 'SOCIETE COOP AGR EXPL DEP DALOA5(SCAEDA)BP 17 DA'
 'STE COOP DESI-CAO NIAPIDOUBP SASSANDRA (VILLE)NI'
 'STE COOP AGRI DE TOUIH BP 142 SAN -PEDRO (VILLE)'
 'STE COOP AGRICUL DE GAGNY CARBP SAN-PEDROGAGNY C'
 'COMMODITY CTRA DE LA VILA 48 088480 BARCELONE SPA'
 'AGRI MANAGEMENT FZ-LLCRIB 211B,RAK INSURRANCE BUI'
 'I.G.I SPA.ZONA INDUSTRIELE PALOMONTEITALIE']
display(df['SUPPLIER_CLEAN'].value_counts().tail(150))
NEDERLAND SA                                        63
VIGOLIN                                             44
YIWU XINDU                                          39
INDCRESA                                            38
FACTA INTERNATIONAL                                 34
                                                    ..
TME24A0618                                           1
STE COOP AGRICUL DE GAGNY CARBP SAN-PEDROGAGNY C     1
SANSTME24S1124                                       1
TME24A0501                                           1
PALMART                                              1
Name: SUPPLIER_CLEAN, Length: 150, dtype: int64
len(df['SUPPLIER_CLEAN'].unique())
172
df['SUPPLIER_CLEAN']
0        AGRI COMMODITIES
1                  SUCDEN
2              COCOA TEAM
3                    ECOM
4                JB FOODS
               ...       
13483             CARGILL
13484             CARGILL
13485             CARGILL
13486             CARGILL
13487             CARGILL
Name: SUPPLIER_CLEAN, Length: 13488, dtype: object
import pandas as pd

def get_top_contributors(df, entity_col, metric_col, threshold=0.97):
    """
    Returns the dataframe of entities that account for the top 90% 
    of the given metric.
    """
    # 1. Group and sum
    grouped = df.groupby(entity_col, as_index=False)[metric_col].sum()

    # 2. Sort descending
    grouped = grouped.sort_values(by=metric_col, ascending=False).reset_index(drop=True)

    # 3. Cumulative percentage
    total_volume = grouped[metric_col].sum()
    grouped['cumulative_share'] = grouped[metric_col].cumsum() / total_volume

    # 4. Filter top 90%
    cutoff_mask = grouped['cumulative_share'] >= threshold
    if cutoff_mask.any():
        cutoff_index = grouped[cutoff_mask].index[0]
        top_entities = grouped.loc[:cutoff_index].copy()
    else:
        top_entities = grouped.copy()

    return top_entities

# --- CONFIGURATION ---
metrics = ['NET WEIGHT', 'CIF VALUE']

# --- EXECUTION ---
metric_dfs = {}

for metric in metrics:
    # We specifically ask for 'SUPPLIER' here
    metric_dfs[metric] = get_top_contributors(df, 'SUPPLIER_CLEAN', metric)

# --- ACCESS RESULTS ---
df_net = metric_dfs['NET WEIGHT']
df_cif = metric_dfs['CIF VALUE']

# --- COMPARISON LOGIC ---
print("\n" + "="*50)
print("COMPARISON: Overlap between Net Weight and CIF Value")
print("="*50)

# FIX: We must select the specific column ['SUPPLIER'] before making a set
base_companies = set(df_net['SUPPLIER_CLEAN'])
comp_companies = set(df_cif['SUPPLIER_CLEAN'])

# Find overlap
in_both = base_companies.intersection(comp_companies)
only_in_net = base_companies - comp_companies
only_in_cif = comp_companies - base_companies

print(f"Total top Suppliers by NET WEIGHT: {len(base_companies)}")
print(f"Total top Suppliers by CIF VALUE:  {len(comp_companies)}")
print(f"Suppliers in BOTH lists:           {len(in_both)}")

print("-" * 30)

if len(only_in_net) > 0:
    print(f"Suppliers ONLY in Net Weight (Top 5): {list(only_in_net)[:5]}")
else:
    print("All Net Weight suppliers are also in CIF list.")

if len(only_in_cif) > 0:
    print(f"Suppliers ONLY in CIF Value (Top 5):  {list(only_in_cif)[:5]}")
else:
    print("All CIF suppliers are also in Net Weight list.")
==================================================
COMPARISON: Overlap between Net Weight and CIF Value
==================================================
Total top Suppliers by NET WEIGHT: 37
Total top Suppliers by CIF VALUE:  33
Suppliers in BOTH lists:           31
------------------------------
Suppliers ONLY in Net Weight (Top 5): ['DKS COCOA', 'TRILINI', 'INDCRESA', 'ONEM GIDA', 'QUAST & CONS']
Suppliers ONLY in CIF Value (Top 5):  ['IBERCACAO', 'ROMSHIP']
base_companies
{'ACT INTERNATIONAL',
 'AFRICAO',
 'AGRI COMMODITIES',
 'AGROFORCE',
 'ALBRECHT & DILL',
 'ANCILE',
 'ARASCO',
 'ASCOT AMSTERDAM',
 'BARRY CALLEBAUT',
 'CARGILL',
 'CEMOI',
 'COCOA TEAM',
 'COCOASOURCE',
 'COMOD',
 'DKS COCOA',
 'ECOM',
 'FACTA INTERNATIONAL',
 'FUCHS & HOFFMANN',
 'GCB COCOA',
 'INDCRESA',
 'JB FOODS',
 'KATOEN NATIE',
 'KSW GLOBAL',
 'LOGIKA',
 'MONER COCOA',
 'NEDERLAND SA',
 'OLAM',
 'ONEM GIDA',
 'QUAST & CONS',
 'SUCDEN',
 'TAN MONDIAL',
 'THEOBROMA',
 'TOUTON',
 'TRILINI',
 'UCOM',
 'ULKER',
 'WALTER MATTER'}
df[df.SUPPLIER_CLEAN=='UCOM']
YEAR DATE MONTH RGITAR SENS IMMIMP EXPORTER SUPPLIER GEN_CTY_DES_COD DESTINATION ... SH COMMERCIAL PRODUCT DESC NATURE_COLIS UNIT QUANTITY FOB VALUE CIF VALUE NET WEIGHT GROSS WEIGHT SUPPLIER_CLEAN
452 2024 18/01/2024 1 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL,26-28, RUE DANIELLE CASANOVA 75002 PARI ID Indonesie ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 770 73538683 76824372 50050 50566 UCOM
694 2024 25/01/2024 1 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL, 26-28 ,RUE DANIELLE CASANOVA 75002 PA ID Indonesie ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 1540 153647432 153647432 100100 101132 UCOM
772 2024 25/01/2024 1 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL, 26-28 ,RUE DANIELLE CASANOVA 75002 PA ID Indonesie ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 8470 845060876 845060876 550550 556226 UCOM
811 2024 26/01/2024 1 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL 26-28, RUE DANIELLE CASANOVA 75002 PARI ID Indonesie ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 770 76823716 76823716 50050 50566 UCOM
864 2024 2024-02-08 00:00:00 2 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL, 26-28, RUE DANIELLE CASANOVA 75002 PAR MY Malaisie ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 3850 398161963 398161963 250250 252830 UCOM
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
4821 2024 2024-12-05 00:00:00 12 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL, 26-28, RUE DANIELLE CASANOVA75002 PARI BR Bresil ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 7700 2410754800 2410754800 500500 505660 UCOM
4865 2024 2024-12-05 00:00:00 12 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL, 26-28, RUE DANIELLE CASANOVA75002 PARI BR Bresil ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 2310 723226702 723226702 150150 151698 UCOM
4916 2024 2024-12-27 00:00:00 12 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL, 26-28, RUE DANIELLE CASANOVA75002 PARI CA CANADA ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 1925 711996062 711996062 125125 126415 UCOM
5057 2024 2024-12-13 00:00:00 12 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL, 26-28, RUE DANIELLE CASANOVA75002 PARI CA CANADA ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 385 142399081 142399081 25025 25283 UCOM
5262 2024 2024-12-05 00:00:00 12 E EXPORT 4263085W CYRIAN INTERNATIONAL01 BP 2734 ABIDJAN (VILLE) 01 UCOM SARL, 26-28, RUE DANIELLE CASANOVA75002 PARI BR Bresil ... 1801001200 1801001200 - -- Cacao brut en fèves, qualité c... JT JT - Sac en jute 5390 1687528097 1687528097 350350 353962 UCOM

156 rows × 24 columns

Using cocoa bean equivalent factors

import pandas as pd

df_2023 = pd.read_csv("/Users/niamhfrench/Library/CloudStorage/OneDrive-SEI/Documents/TRASE/trase/data/cote_divoire/trade/civ_cocoa_2023_trader_groups_cleaned.csv")
df_2024 = pd.read_csv("/Users/niamhfrench/Library/CloudStorage/OneDrive-SEI/Documents/TRASE/trase/data/cote_divoire/trade/civ_cocoa_2024_trader_groups_cleaned.csv")
# 1. Setup the dataframe (assuming your dataframe is named 'df')
# We drop the NaN row at the end to ensure clean calculations
df = df_2023.dropna(subset=['TRADER_BEQ_VOLUME_EXPORTED'])

# 2. Sort by volume descending (Crucial step for Pareto/cumulative analysis)
df_sorted = df.sort_values(by='TRADER_BEQ_VOLUME_EXPORTED', ascending=False).copy()

# 3. Calculate the cumulative percentage
total_volume = df_sorted['TRADER_BEQ_VOLUME_EXPORTED'].sum()
df_sorted['cumulative_share'] = df_sorted['TRADER_BEQ_VOLUME_EXPORTED'].cumsum() / total_volume

# 4. Filter to keep rows that make up the top 90%
# We use shift(1) < 0.9 to ensure we include the specific trader that crosses 
# the 90% threshold, ensuring we cover *at least* 90% of the volume.
top_90_df = df_sorted[df_sorted['cumulative_share'].shift(1, fill_value=0) < 0.91]

# Optional: View the result
print(top_90_df[['EXPORTER_GROUP_CLEAN', 'TRADER_BEQ_VOLUME_EXPORTED', 'cumulative_share']])

# Get just the list of names
top_90_names = top_90_df['EXPORTER_GROUP_CLEAN'].tolist()
print(f"\nNumber of exporters in top 90%: {len(top_90_names)}")
       EXPORTER_GROUP_CLEAN  TRADER_BEQ_VOLUME_EXPORTED  cumulative_share
0           BARRY CALLEBAUT                2.669343e+08          0.151225
1                   CARGILL                2.535920e+08          0.294892
2                      OLAM                2.263913e+08          0.423148
3                      ECOM                1.854078e+08          0.528187
4                    TOUTON                1.604826e+08          0.619104
5                    SUCDEN                1.344604e+08          0.695280
6                 ETC GROUP                7.167884e+07          0.735888
7   SOCIETE AWAHUS SERVICES                6.819157e+07          0.774520
8          GUAN CHONG COCOA                5.188888e+07          0.803916
9                     CEMOI                3.870722e+07          0.825845
10                      S3C                3.842800e+07          0.847616
11               TANMONDIAL                3.573570e+07          0.867861
12              COCOASOURCE                2.764042e+07          0.883520
13                     SACC                2.137789e+07          0.895631
14       SCAT (COOPERATIVE)                2.037372e+07          0.907173
15                  FILDISI                1.641655e+07          0.916474

Number of exporters in top 90%: 16
# 1. Setup the dataframe (assuming your dataframe is named 'df')
# We drop the NaN row at the end to ensure clean calculations
df = df_2024.dropna(subset=['TRADER_BEQ_VOLUME_EXPORTED'])

# 2. Sort by volume descending (Crucial step for Pareto/cumulative analysis)
df_sorted = df.sort_values(by='TRADER_BEQ_VOLUME_EXPORTED', ascending=False).copy()

# 3. Calculate the cumulative percentage
total_volume = df_sorted['TRADER_BEQ_VOLUME_EXPORTED'].sum()
df_sorted['cumulative_share'] = df_sorted['TRADER_BEQ_VOLUME_EXPORTED'].cumsum() / total_volume

# 4. Filter to keep rows that make up the top 90%
# We use shift(1) < 0.9 to ensure we include the specific trader that crosses 
# the 90% threshold, ensuring we cover *at least* 90% of the volume.
top_90_df = df_sorted[df_sorted['cumulative_share'].shift(1, fill_value=0) < 0.91]

# Optional: View the result
print(top_90_df[['EXPORTER_GROUP_CLEAN', 'TRADER_BEQ_VOLUME_EXPORTED', 'cumulative_share']])

# Get just the list of names
top_90_names = top_90_df['EXPORTER_GROUP_CLEAN'].tolist()
print(f"\nNumber of exporters in top 90%: {len(top_90_names)}")
       EXPORTER_GROUP_CLEAN  TRADER_BEQ_VOLUME_EXPORTED  cumulative_share
0           BARRY CALLEBAUT                2.669343e+08          0.151225
1                   CARGILL                2.535920e+08          0.294892
2                      OLAM                2.263913e+08          0.423148
3                      ECOM                1.854078e+08          0.528187
4                    TOUTON                1.604826e+08          0.619104
5                    SUCDEN                1.344604e+08          0.695280
6                 ETC GROUP                7.167884e+07          0.735888
7   SOCIETE AWAHUS SERVICES                6.819157e+07          0.774520
8          GUAN CHONG COCOA                5.188888e+07          0.803916
9                     CEMOI                3.870722e+07          0.825845
10                      S3C                3.842800e+07          0.847616
11               TANMONDIAL                3.573570e+07          0.867861
12              COCOASOURCE                2.764042e+07          0.883520
13                     SACC                2.137789e+07          0.895631
14       SCAT (COOPERATIVE)                2.037372e+07          0.907173
15                  FILDISI                1.641655e+07          0.916474

Number of exporters in top 90%: 16