CoolFace
Apppublic

Akila-5/customer-segmentation-dashboard

sourceHugging Faceupdated 20d agoView on Hugging Face
0likes
script.js1599 linesDownload Raw Back to root
1/* =========================================================2   CUSTOMER SEGMENTATION ANALYSIS3   Complete JavaScript Project4   Platform: Hugging Face Spaces5   Technology: HTML + CSS + JavaScript + Chart.js6 7   Dataset:8   - 500 synthetic customers9   - Demographic information10   - Income11   - Purchases12   - Purchase frequency13   - Total spending14   - Preferred category15   - Membership16   - Location17 18   Machine Learning:19   - K-Means Clustering20   - Features used:21       1. Income22       2. Purchases23       3. Total Spending24   ========================================================= */25 26 27/* =========================================================28   1. CREATE CUSTOMER DATASET29   ========================================================= */30 31const customers = [];32 33 34/*35   A deterministic random number generator is used so that36   the dashboard produces consistent results every time.37*/38 39let seed = 12345;40 41function random() {42 43    seed = (seed * 9301 + 49297) % 233280;44 45    return seed / 233280;46}47 48 49/* Generate random integer */50 51function randomInt(min, max) {52 53    return Math.floor(random() * (max - min + 1)) + min;54 55}56 57 58/* Select random item from an array */59 60function randomItem(array) {61 62    return array[Math.floor(random() * array.length)];63 64}65 66 67/* Dataset options */68 69const genders = [70    "Male",71    "Female"72];73 74 75const locations = [76    "Chennai",77    "Coimbatore",78    "Madurai",79    "Trichy",80    "Salem",81    "Thanjavur",82    "Bangalore",83    "Hyderabad"84];85 86 87const categories = [88    "Electronics",89    "Clothing",90    "Groceries",91    "Beauty",92    "Home",93    "Sports"94];95 96 97const memberships = [98    "Basic",99    "Silver",100    "Gold",101    "Platinum"102];103 104 105const frequencies = [106    "Occasional",107    "Monthly",108    "Bi-weekly",109    "Weekly"110];111 112 113/*114   Create 500 customers.115 116   The values are generated to represent realistic117   customer behavior.118*/119 120for (let i = 1; i <= 500; i++) {121 122    const age = randomInt(18, 70);123 124    const gender = randomItem(genders);125 126    /*127       Income between approximately ₹20,000 and ₹180,000128    */129 130    const income = randomInt(20000, 180000);131 132 133    /*134       Purchase frequency135    */136 137    const purchaseFrequency = randomItem(frequencies);138 139 140    let purchases;141 142 143    if (purchaseFrequency === "Occasional") {144 145        purchases = randomInt(5, 18);146 147    }148 149    else if (purchaseFrequency === "Monthly") {150 151        purchases = randomInt(19, 36);152 153    }154 155    else if (purchaseFrequency === "Bi-weekly") {156 157        purchases = randomInt(30, 55);158 159    }160 161    else {162 163        purchases = randomInt(45, 65);164 165    }166 167 168    /*169       Spending is influenced by income and purchases.170    */171 172    let spending =173        (income * (0.15 + random() * 0.45))174        + (purchases * randomInt(300, 900));175 176 177    /*178       Add some variation.179    */180 181    spending = Math.round(spending);182 183 184    /*185       Keep spending within a realistic range.186    */187 188    spending = Math.max(5000, Math.min(330000, spending));189 190 191    /*192       Membership is influenced by spending.193    */194 195    let membership;196 197    if (spending >= 180000) {198 199        membership = randomItem(["Gold", "Platinum"]);200 201    }202 203    else if (spending >= 90000) {204 205        membership = randomItem(["Silver", "Gold"]);206 207    }208 209    else {210 211        membership = randomItem(["Basic", "Silver"]);212 213    }214 215 216    customers.push({217 218        Customer_ID:219            "C" + String(i).padStart(4, "0"),220 221        Age: age,222 223        Gender: gender,224 225        Income: income,226 227        Location: randomItem(locations),228 229        Membership: membership,230 231        Preferred_Category: randomItem(categories),232 233        Purchases: purchases,234 235        Purchase_Frequency: purchaseFrequency,236 237        Total_Spending: spending238 239    });240 241}242 243 244/* =========================================================245   2. BASIC CALCULATIONS246   ========================================================= */247 248 249/* Total customers */250 251const totalCustomers = customers.length;252 253 254/* Average income */255 256const averageIncome =257    customers.reduce(258        (sum, customer) => sum + customer.Income,259        0260    ) / totalCustomers;261 262 263/* Total spending */264 265const totalSpending =266    customers.reduce(267        (sum, customer) => sum + customer.Total_Spending,268        0269    );270 271 272/* Average purchases */273 274const averagePurchases =275    customers.reduce(276        (sum, customer) => sum + customer.Purchases,277        0278    ) / totalCustomers;279 280 281/* =========================================================282   3. DISPLAY KPI VALUES283   ========================================================= */284 285document.getElementById("totalCustomers").textContent =286    totalCustomers;287 288 289document.getElementById("avgIncome").textContent =290    formatCurrency(averageIncome);291 292 293document.getElementById("totalSpending").textContent =294    formatCurrency(totalSpending);295 296 297document.getElementById("avgPurchases").textContent =298    averagePurchases.toFixed(1);299 300 301/* =========================================================302   4. CURRENCY FORMATTER303   ========================================================= */304 305function formatCurrency(value) {306 307    return "₹" + Math.round(value).toLocaleString("en-IN");308 309}310 311 312/* =========================================================313   5. STANDARDIZATION314   ========================================================= */315 316/*317   K-Means works better when features are standardized.318 319   We use:320   - Income321   - Purchases322   - Total Spending323*/324 325function standardize(values) {326 327    const means = [];328 329    const standardDeviations = [];330 331 332    for (let column = 0; column < values[0].length; column++) {333 334        const columnValues =335            values.map(row => row[column]);336 337 338        const mean =339            columnValues.reduce(340                (a, b) => a + b,341                0342            ) / columnValues.length;343 344 345        const variance =346            columnValues.reduce(347                (sum, value) =>348                    sum + Math.pow(value - mean, 2),349                0350            ) / columnValues.length;351 352 353        const standardDeviation =354            Math.sqrt(variance) || 1;355 356 357        means.push(mean);358 359        standardDeviations.push(standardDeviation);360 361    }362 363 364    return values.map(row =>365 366        row.map(367            (value, index) =>368                (value - means[index]) /369                standardDeviations[index]370        )371 372    );373 374}375 376 377/* =========================================================378   6. EUCLIDEAN DISTANCE379   ========================================================= */380 381function distance(point1, point2) {382 383    let total = 0;384 385    for (let i = 0; i < point1.length; i++) {386 387        total +=388            Math.pow(389                point1[i] - point2[i],390                2391            );392 393    }394 395    return Math.sqrt(total);396 397}398 399 400/* =========================================================401   7. K-MEANS CLUSTERING402   ========================================================= */403 404function kMeans(data, k = 3, iterations = 100) {405 406    /*407       Select initial centroids from the dataset.408    */409 410    let centroids = [411 412        [...data[0]],413 414        [...data[Math.floor(data.length / 2)]],415 416        [...data[data.length - 1]]417 418    ];419 420 421    let assignments =422        new Array(data.length).fill(0);423 424 425    for (let iteration = 0; iteration < iterations; iteration++) {426 427        let changed = false;428 429 430        /* ---------------------------------------------431           Assign each customer to nearest centroid432           --------------------------------------------- */433 434        for (let i = 0; i < data.length; i++) {435 436            let nearestCluster = 0;437 438            let nearestDistance =439                distance(440                    data[i],441                    centroids[0]442                );443 444 445            for (let cluster = 1; cluster < k; cluster++) {446 447                const currentDistance =448                    distance(449                        data[i],450                        centroids[cluster]451                    );452 453 454                if (currentDistance < nearestDistance) {455 456                    nearestDistance = currentDistance;457 458                    nearestCluster = cluster;459 460                }461 462            }463 464 465            if (assignments[i] !== nearestCluster) {466 467                assignments[i] = nearestCluster;468 469                changed = true;470 471            }472 473        }474 475 476        /* ---------------------------------------------477           Calculate new centroids478           --------------------------------------------- */479 480        const sums =481            Array.from(482                { length: k },483                () => [0, 0, 0]484            );485 486 487        const counts =488            new Array(k).fill(0);489 490 491        for (let i = 0; i < data.length; i++) {492 493            const cluster =494                assignments[i];495 496 497            counts[cluster]++;498 499 500            for (let j = 0; j < data[i].length; j++) {501 502                sums[cluster][j] +=503                    data[i][j];504 505            }506 507        }508 509 510        for (let cluster = 0; cluster < k; cluster++) {511 512            if (counts[cluster] === 0) {513 514                centroids[cluster] =515                    [...data[randomInt(0, data.length - 1)]];516 517            }518 519            else {520 521                centroids[cluster] =522                    sums[cluster].map(523                        value =>524                            value / counts[cluster]525                    );526 527            }528 529        }530 531 532        if (!changed) {533 534            break;535 536        }537 538    }539 540 541    return {542 543        assignments,544        centroids545 546    };547 548}549 550 551/* =========================================================552   8. PREPARE FEATURES553   ========================================================= */554 555const featureData = customers.map(customer => [556 557    customer.Income,558 559    customer.Purchases,560 561    customer.Total_Spending562 563]);564 565 566/* Standardize */567 568const standardizedData =569    standardize(featureData);570 571 572/* Run K-Means */573 574const clustering =575    kMeans(576        standardizedData,577        3,578        100579    );580 581 582/* Store cluster number in each customer */583 584customers.forEach((customer, index) => {585 586    customer.Cluster =587        clustering.assignments[index];588 589});590 591 592/* =========================================================593   9. CALCULATE CLUSTER STATISTICS594   ========================================================= */595 596const clusterStatistics = [];597 598 599for (let cluster = 0; cluster < 3; cluster++) {600 601    const members =602        customers.filter(603            customer =>604                customer.Cluster === cluster605        );606 607 608    const count =609        members.length;610 611 612    const avgIncome =613        members.reduce(614            (sum, customer) =>615                sum + customer.Income,616            0617        ) / count;618 619 620    const avgSpending =621        members.reduce(622            (sum, customer) =>623                sum + customer.Total_Spending,624            0625        ) / count;626 627 628    const avgPurchases =629        members.reduce(630            (sum, customer) =>631                sum + customer.Purchases,632            0633        ) / count;634 635 636    clusterStatistics.push({637 638        cluster,639 640        count,641 642        avgIncome,643 644        avgSpending,645 646        avgPurchases647 648    });649 650}651 652 653/* =========================================================654   10. SORT CLUSTERS BY SPENDING655   ========================================================= */656 657const sortedClusters =658    [...clusterStatistics].sort(659        (a, b) =>660            a.avgSpending - b.avgSpending661    );662 663 664/*665   Lowest spending = Budget666   Middle spending = Regular667   Highest spending = High Value668*/669 670const clusterNames = {};671 672 673clusterNames[674    sortedClusters[0].cluster675] = "Budget Customers";676 677 678clusterNames[679    sortedClusters[1].cluster680] = "Regular Customers";681 682 683clusterNames[684    sortedClusters[2].cluster685] = "High Value Customers";686 687 688/* =========================================================689   11. ADD SEGMENT NAME TO CUSTOMERS690   ========================================================= */691 692customers.forEach(customer => {693 694    customer.Segment =695        clusterNames[customer.Cluster];696 697});698 699 700/* =========================================================701   12. SEGMENT COUNTS702   ========================================================= */703 704const segmentNames = [705 706    "Budget Customers",707 708    "Regular Customers",709 710    "High Value Customers"711 712];713 714 715const segmentCounts =716    segmentNames.map(717        name =>718            customers.filter(719                customer =>720                    customer.Segment === name721            ).length722    );723 724 725/* =========================================================726   13. CUSTOMER SEGMENT DOUGHNUT CHART727   ========================================================= */728 729new Chart(730 731    document.getElementById("segmentChart"),732 733    {734 735        type: "doughnut",736 737        data: {738 739            labels: segmentNames,740 741            datasets: [742 743                {744 745                    label: "Customers",746 747                    data: segmentCounts748 749                }750 751            ]752 753        },754 755        options: {756 757            responsive: true,758 759            maintainAspectRatio: false,760 761            plugins: {762 763                legend: {764 765                    position: "bottom"766 767                }768 769            }770 771        }772 773    }774 775);776 777 778/* =========================================================779   14. INCOME VS SPENDING SCATTER CHART780   ========================================================= */781 782const scatterData =783    customers.map(customer => ({784 785        x: customer.Income,786 787        y: customer.Total_Spending788 789    }));790 791 792new Chart(793 794    document.getElementById("incomeSpendingChart"),795 796    {797 798        type: "scatter",799 800        data: {801 802            datasets: [803 804                {805 806                    label: "Customers",807 808                    data: scatterData809 810                }811 812            ]813 814        },815 816        options: {817 818            responsive: true,819 820            maintainAspectRatio: false,821 822            scales: {823 824                x: {825 826                    title: {827 828                        display: true,829 830                        text: "Annual Income (₹)"831 832                    }833 834                },835 836                y: {837 838                    title: {839 840                        display: true,841 842                        text: "Total Spending (₹)"843 844                    }845 846                }847 848            }849 850        }851 852    }853 854);855 856 857/* =========================================================858   15. AGE DISTRIBUTION859   ========================================================= */860 861const ageGroups = [862 863    "18-25",864 865    "26-35",866 867    "36-45",868 869    "46-55",870 871    "56-65",872 873    "66-70"874 875];876 877 878const ageCounts =879    ageGroups.map(group => {880 881        const [min, max] =882            group.split("-").map(Number);883 884 885        return customers.filter(886            customer =>887                customer.Age >= min &&888                customer.Age <= max889        ).length;890 891    });892 893 894new Chart(895 896    document.getElementById("ageChart"),897 898    {899 900        type: "bar",901 902        data: {903 904            labels: ageGroups,905 906            datasets: [907 908                {909 910                    label: "Customers",911 912                    data: ageCounts913 914                }915 916            ]917 918        },919 920        options: {921 922            responsive: true,923 924            maintainAspectRatio: false,925 926            scales: {927 928                y: {929 930                    beginAtZero: true,931 932                    title: {933 934                        display: true,935 936                        text: "Number of Customers"937 938                    }939 940                }941 942            }943 944        }945 946    }947 948);949 950 951/* =========================================================952   16. PURCHASE FREQUENCY953   ========================================================= */954 955const frequencyCounts =956    frequencies.map(957        frequency =>958            customers.filter(959                customer =>960                    customer.Purchase_Frequency === frequency961            ).length962    );963 964 965new Chart(966 967    document.getElementById("purchaseChart"),968 969    {970 971        type: "bar",972 973        data: {974 975            labels: frequencies,976 977            datasets: [978 979                {980 981                    label: "Customers",982 983                    data: frequencyCounts984 985                }986 987            ]988 989        },990 991        options: {992 993            responsive: true,994 995            maintainAspectRatio: false,996 997            scales: {998 999                y: {1000 1001                    beginAtZero: true,1002 1003                    title: {1004 1005                        display: true,1006 1007                        text: "Number of Customers"1008 1009                    }1010 1011                }1012 1013            }1014 1015        }1016 1017    }1018 1019);1020 1021 1022/* =========================================================1023   17. CUSTOMER PREFERENCES1024   ========================================================= */1025 1026const preferenceCounts =1027    categories.map(1028        category =>1029            customers.filter(1030                customer =>1031                    customer.Preferred_Category === category1032            ).length1033    );1034 1035 1036new Chart(1037 1038    document.getElementById("preferenceChart"),1039 1040    {1041 1042        type: "bar",1043 1044        data: {1045 1046            labels: categories,1047 1048            datasets: [1049 1050                {1051 1052                    label: "Customers",1053 1054                    data: preferenceCounts1055 1056                }1057 1058            ]1059 1060        },1061 1062        options: {1063 1064            responsive: true,1065 1066            maintainAspectRatio: false,1067 1068            scales: {1069 1070                y: {1071 1072                    beginAtZero: true,1073 1074                    title: {1075 1076                        display: true,1077 1078                        text: "Number of Customers"1079 1080                    }1081 1082                }1083 1084            }1085 1086        }1087 1088    }1089 1090);1091 1092 1093/* =========================================================1094   18. MEMBERSHIP DISTRIBUTION1095   ========================================================= */1096 1097const membershipCounts =1098    memberships.map(1099        membership =>1100            customers.filter(1101                customer =>1102                    customer.Membership === membership1103            ).length1104    );1105 1106 1107new Chart(1108 1109    document.getElementById("membershipChart"),1110 1111    {1112 1113        type: "doughnut",1114 1115        data: {1116 1117            labels: memberships,1118 1119            datasets: [1120 1121                {1122 1123                    label: "Customers",1124 1125                    data: membershipCounts1126 1127                }1128 1129            ]1130 1131        },1132 1133        options: {1134 1135            responsive: true,1136 1137            maintainAspectRatio: false,1138 1139            plugins: {1140 1141                legend: {1142 1143                    position: "bottom"1144 1145                }1146 1147            }1148 1149        }1150 1151    }1152 1153);1154 1155 1156/* =========================================================1157   19. CUSTOMER SEGMENT SUMMARY TABLE1158   ========================================================= */1159 1160const table =1161    document.getElementById("segmentTable");1162 1163 1164table.innerHTML = "";1165 1166 1167segmentNames.forEach(segment => {1168 1169    const members =1170        customers.filter(1171            customer =>1172                customer.Segment === segment1173        );1174 1175 1176    const avgIncome =1177        members.reduce(1178            (sum, customer) =>1179                sum + customer.Income,1180            01181        ) / members.length;1182 1183 1184    const avgSpending =1185        members.reduce(1186            (sum, customer) =>1187                sum + customer.Total_Spending,1188            01189        ) / members.length;1190 1191 1192    const avgPurchases =1193        members.reduce(1194            (sum, customer) =>1195                sum + customer.Purchases,1196            01197        ) / members.length;1198 1199 1200    const row =

Showing the first 1,200 of 1599 lines. Download the file for the rest.