DEV Community

Cover image for πŸ“Š Building a Netflix Content Dashboard with ML.NET
reshma p
reshma p

Posted on

πŸ“Š Building a Netflix Content Dashboard with ML.NET

πŸš€ In this project, I built a modular dashboard to analyze Netflix content trends using ML.NET, CsvHelper, and Razor Pages β€” with bargraph visualizations for genre, country, and release year insights.

πŸ” Tech Stack

  • ML.NET: SdcaMaximumEntropy for multiclass classification
  • CsvHelper.Configuration: Clean parsing of Netflix dataset
  • Razor Pages: UI with dropdown filters and summary cards
  • Chart.js: Interactive bargraphs for visual storytelling
  • LINQ: Dynamic filtering by genre, type, country, and year

πŸ“ Dataset

Used the Netflix Movies and TV Shows dataset from Kaggle:

  • Fields: Title, Type, Country, Genre, Release Year, Rating

🧠 ML.NET Model: Content Type Classifier trained model in console app

    var pipeline = mlContext.Transforms.Text.FeaturizeText("TitleFeats", nameof(TitleData.Title))
           .Append(mlContext.Transforms.Text.FeaturizeText("GenreFeats", nameof(TitleData.Genre)))
           .Append(mlContext.Transforms.Text.FeaturizeText("DescFeats", nameof(TitleData.Description)))
           .Append(mlContext.Transforms.Text.FeaturizeText("DurationFeats", nameof(TitleData.Duration)))
           .Append(mlContext.Transforms.Conversion.MapValueToKey("Label", nameof(Type)))
           .Append(mlContext.MulticlassClassification.Trainers.SdcaMaximumEntropy("Label", "Features"))
           .Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"));
           return pipeline;
Enter fullscreen mode Exit fullscreen mode

Initialize ML.NET Context

var mlContext = new MLContext();
Enter fullscreen mode Exit fullscreen mode

Define Paths

var modelPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "models", "Model.zip");
var dataPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "models", "netflix_titles.csv");
Enter fullscreen mode Exit fullscreen mode

Load Data with ML.NET

IDataView dataView = mlContext.Data.LoadFromTextFile<TitleData>(
    dataPath, separatorChar: ',', hasHeader: true);

var dataEnumerable = mlContext.Data.CreateEnumerable<TitleData>(
    dataView, reuseRowObject: false).Take(100).ToList();
Enter fullscreen mode Exit fullscreen mode

This gives us a sample of 100 titles for quick dashboard rendering.

Parse CSV with CsvHelper

List<TitleData> records;
using (var reader = new StreamReader(dataPath))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
    csv.Context.RegisterClassMap<TitleDataMap>();
    records = csv.GetRecords<TitleData>().ToList();
}
Enter fullscreen mode Exit fullscreen mode

CsvHelper ensures clean mapping and parsing of the full dataset.

ξ·™ξ·š
Predicts whether a title is a Movie or TV Show based on its name and genre.

πŸ“Š Dashboard Visuals

🎬 Movies vs TV Shows


            TypeCounts = records
             .GroupBy(p => p.Type)
             .Select(g => new TypeCount
             {
                 Type = g.Key,
                 Count = g.Count()
             })
             .ToList();
Enter fullscreen mode Exit fullscreen mode
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
    const typectx = document.getElementById('typeChart').getContext('2d');
    const typeChart = new Chart(typectx, {
        type: 'bar',
        data: {
            labels: @Html.Raw(Json.Serialize(type)),
            datasets: [{
                label: 'Movies vs TV Shows on Netflix',
                data: @Html.Raw(Json.Serialize(values)),
                backgroundColor: ['#4e79a7', '#f28e2b'],
                // borderWidth: 1
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,

            scales: {
                y: {
                    beginAtZero: true,
                    title: {
                        display: true,
                        text: 'Count'
                    }
                },
                x: {
                    title: {
                        display: true,
                        text: 'Type'
                    }
                }
            }
        }
    });
</script>
Enter fullscreen mode Exit fullscreen mode

🌍 Top 10 Countries Producing Netflix Content
Bargraph: Country-wise content count

 TopCountries = records
           .Where(r => !string.IsNullOrWhiteSpace(r.Country))
           .SelectMany(r => r.Country.Split(','))
           .Select(c => c.Trim())
           .GroupBy(c => c)
           .Select(g => new CountryCount
           {
               Country = g.Key,
               Count = g.Count()
           })
           .OrderByDescending(c => c.Count)
           .Take(10)
           .ToList();
Enter fullscreen mode Exit fullscreen mode
<script>
    const countryctx = document.getElementById('countryChart').getContext('2d');
    const countrychart = new Chart(countryctx, {
        type: 'bar',
        data: {
            labels: @Html.Raw(Json.Serialize(Model.TopCountries.Select(c => c.Country))),
            datasets: [{
                label: 'Top 10 Countries producing Netflix content',
                data: @Html.Raw(Json.Serialize(Model.TopCountries.Select(c => c.Count))),
                backgroundColor: 'rgba(255, 99, 132, 0.6)'
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            scales: {
                y: {
                    beginAtZero: true,
                    title: {
                        display: true,
                        text: 'Number of Titles'
                    }
                },
                x: {
                    title: {
                        display: true,
                        text: 'Country'
                    }
                }
            }
        }
    });
</script>
Enter fullscreen mode Exit fullscreen mode

πŸ“… Content by Release Year
Bargraph: Titles released per year

            YearCounts = records
                .Select(r => new
                {
                    ParsedYear = int.TryParse(r.Year, out var y) ? y : 0
                })
                .Where(x => x.ParsedYear > 1900)
                .GroupBy(x => x.ParsedYear)
                .Select(g => new YearCount
                {
                    Year = g.Key,
                    Count = g.Count()
                })
                .OrderBy(y => y.Year)
                .ToList();
Enter fullscreen mode Exit fullscreen mode
<script>
    const yearctx = document.getElementById('yearChart').getContext('2d');
    const yearchart = new Chart(yearctx, {
        type: 'bar',
        data: {
            labels: @Html.Raw(Json.Serialize(Model.YearCounts.Select(y => y.Year))),
            datasets: [{
                label: 'Netflix Content by Release Year',
                data: @Html.Raw(Json.Serialize(Model.YearCounts.Select(y => y.Count))),
                backgroundColor: 'rgba(54, 162, 235, 0.6)'
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            scales: {
                y: {
                    beginAtZero: true,
                    title: {
                        display: true,
                        text: 'Number of Titles'
                    }
                },
                x: {
                    title: {
                        display: true,
                        text: 'Release Year'
                    }
                }
            }
        }
    });
</script>
Enter fullscreen mode Exit fullscreen mode

🎭 Top Genres on Netflix
Bargraph: Genre frequency across all titles

 TopGenres = records
           .Where(r => !string.IsNullOrWhiteSpace(r.Genre))
           .SelectMany(r => r.Genre.Split(','))
           .Select(g => g.Trim())
           .GroupBy(g => g)
           .Select(g => new GenreCount
           {
               Genre = g.Key,
               Count = g.Count()
           })
           .OrderByDescending(g => g.Count)
           .Take(10)
           .ToList();
Enter fullscreen mode Exit fullscreen mode
<script>
    const genrectx = document.getElementById('genreChart').getContext('2d');
    const genreChart = new Chart(genrectx, {
        type: 'bar',
        data: {
            labels: @Html.Raw(Json.Serialize(Model.TopGenres.Select(g => g.Genre))),
            datasets: [{
                label: 'Top 10 Genres on Netflix',
                data: @Html.Raw(Json.Serialize(Model.TopGenres.Select(g => g.Count))),
                backgroundColor: 'rgba(153, 102, 255, 0.6)'
            }]
        },
        options: {
            indexAxis: 'y', // Horizontal bar chart
            responsive: true,
            maintainAspectRatio: false,
            scales: {
                y: {
                    beginAtZero: true,
                    title: {
                        display: true,
                        text: 'Number of Titles'
                    }
                },
                x: {
                    title: {
                        display: true,
                        text: 'Genre'
                    }
                }
            }
        }
    });
</script>
Enter fullscreen mode Exit fullscreen mode

πŸ–₯️ Razor Pages UI

  • Dropdown filters: Genre, Country, Type, Year
  • Summary cards: Total titles, Movies, TV Shows
  • LINQ-powered filtering for real-time updates
  • Chart.js for interactive visuals

πŸ‘‰ GitHub: https://github.com/reshmapotthuri/ML_NetflixAnalysis

βœ… Conclusion

This project demonstrates how ML.NET can be seamlessly integrated into real-world dashboards β€” from classifying Netflix content with SdcaMaximumEntropy by combining Razor Pages, CsvHelper, and Chart.js

Top comments (0)