<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stacy Mumbi</title>
    <description>The latest articles on DEV Community by Stacy Mumbi (@smumbi_).</description>
    <link>https://dev.to/smumbi_</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4071797%2Fad6f237c-97c0-4a01-aa2d-8024c09f823c.png</url>
      <title>DEV Community: Stacy Mumbi</title>
      <link>https://dev.to/smumbi_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/smumbi_"/>
    <language>en</language>
    <item>
      <title>Building a Power BI Data Model for ShopKe: Understanding Relationships, Schemas and Joins</title>
      <dc:creator>Stacy Mumbi</dc:creator>
      <pubDate>Mon, 14 Sep 2026 04:11:06 +0000</pubDate>
      <link>https://dev.to/smumbi_/building-a-power-bi-data-model-for-shopke-understanding-relationships-schemas-and-joins-4g3c</link>
      <guid>https://dev.to/smumbi_/building-a-power-bi-data-model-for-shopke-understanding-relationships-schemas-and-joins-4g3c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Say your working as a data analyst at &lt;strong&gt;ShopKe&lt;/strong&gt;, a fictional Kenyan e-commerce company selling electronics, fashion and home products. The management team wants to understand sales performance, customer purchasing behavior and product profitability.&lt;/p&gt;

&lt;p&gt;The company has three datasets namely Customers, Products and Orders. Even though these datasets contain valuable information, they need to be properly organized before creating a Power BI dashboard.&lt;/p&gt;

&lt;p&gt;This is where data modelling becomes important. A well designed data model allows Power BI to connect related tables, perform accurate calculations and present meaningful business insights.&lt;/p&gt;

&lt;p&gt;In this article, I will explore data modelling approaches, fact and dimension tables, relationships, filter directions and Power Query joins using &lt;strong&gt;ShopKe&lt;/strong&gt; as a practical example for better understanding.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Data Modelling in Power BI
&lt;/h2&gt;

&lt;p&gt;Data modelling is the process of organizing data into tables and defining relationships between them so that the data can be analyzed properly.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;good data model&lt;/strong&gt; is important because it supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accurate reporting and DAX calculations.&lt;/li&gt;
&lt;li&gt;Better query performance.&lt;/li&gt;
&lt;li&gt;Scalability as data grows.&lt;/li&gt;
&lt;li&gt;Easier report development.&lt;/li&gt;
&lt;li&gt;Improved readability and maintainability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, ShopKe may store customer information in one table and sales transactions in another. By connecting them using &lt;strong&gt;CustomerID&lt;/strong&gt;, Power BI can analyze sales by customer without repeating customer details in every transaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.1 Flat Table
&lt;/h2&gt;

&lt;p&gt;A flat table stores all information in one table.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;th&gt;ProductName&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;SalesAmount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;O001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;Laptop&lt;/td&gt;
&lt;td&gt;Electronics&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;75,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O002&lt;/td&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;td&gt;Mouse&lt;/td&gt;
&lt;td&gt;Electronics&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O003&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;Shirt&lt;/td&gt;
&lt;td&gt;Fashion&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2,500&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────┐
│          SalesData           │
├──────────────────────────────┤
│ OrderID                      │
│ CustomerName                 │
│ ProductName                  │
│ Category                     │
│ Quantity                     │
│ SalesAmount                  │
└──────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advantages&lt;/strong&gt;: Simple to understand, easy to import and good for small datasets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages&lt;/strong&gt;: Repeated information increases redundancy and the table may become difficult to maintain as the business grows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;: Small datasets, quick analysis and simple reporting requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance and complexity&lt;/strong&gt;: It has few relationship complications, but unnecessary columns and repeated values can increase the amount of data stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.2 Star Schema
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;star schema&lt;/strong&gt; contains a central fact table connected directly to multiple dimension tables.&lt;/p&gt;

&lt;p&gt;For ShopKe, FactSales stores transactions, while DimCustomer, DimProduct and DimDate provide descriptive information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbp859fbatv3p9ofpzwh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbp859fbatv3p9ofpzwh1.png" alt="ShopKe data model" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ShopKe data model presented as a star schema&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages&lt;/strong&gt;: Simple to understand, supports readable DAX, reduces unnecessary duplication and  well suited for analytical reporting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages&lt;/strong&gt;: Requires careful relationship design and may involve some repeated descriptive information within dimensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;: Sales, finance, inventory, customer and other business intelligence projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance and complexity&lt;/strong&gt;: A well-designed star schema can support efficient analytical queries and compression while keeping the model relatively easy to navigate.&lt;/p&gt;

&lt;h2&gt;
  
  
  1.3 Snowflake Schema
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;snowflake schema&lt;/strong&gt; is a type of  star schema where dimension tables are further divided into related tables.&lt;/p&gt;

&lt;p&gt;For example, ShopKe may separate product information into Product, Subcategory and Category tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structure&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    ┌──────────────┐
                    │  DimCategory │
                    └──────┬───────┘
                           │ 1
                           │ *
                    ┌──────▼───────┐
                    │DimSubcategory│
                    └──────┬───────┘
                           │ 1
                           │ *
┌─────────────┐     ┌──────▼───────┐
│  FactSales  │ *──1│  DimProduct  │
└─────────────┘     └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwfx86u5i2qyglzyr20l6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwfx86u5i2qyglzyr20l6.png" alt="Snowflake Schema" width="799" height="559"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;An example of how a snowflake schema model would look like&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages&lt;/strong&gt;: Reduces repeated descriptive information and can support difficult hierarchies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disadvantages&lt;/strong&gt;: More tables and relationships increase model complexity and may make report development less intuitive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When to use&lt;/strong&gt;: Complex organizational or geographical hierarchies, normalized data sources and situations where shared reference tables are useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance and complexity&lt;/strong&gt;: It can reduce redundancy, but more relationships may make the model more complicated. In many cases, a star schema is preferred for simplicity.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Fact Tables and Dimension Tables
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fact tables
&lt;/h3&gt;

&lt;p&gt;A fact table stores measurable business events. In ShopKe, FactSales contains individual sales transactions.&lt;/p&gt;

&lt;p&gt;Example fields include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SalesID&lt;/li&gt;
&lt;li&gt;CustomerID&lt;/li&gt;
&lt;li&gt;ProductID&lt;/li&gt;
&lt;li&gt;DateKey&lt;/li&gt;
&lt;li&gt;Quantity&lt;/li&gt;
&lt;li&gt;SalesAmount&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc0kh5fzjgyrtgavteivs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc0kh5fzjgyrtgavteivs.png" alt="FactSales" width="798" height="163"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The FactSales table&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dimension tables
&lt;/h2&gt;

&lt;p&gt;Dimension tables store descriptive attributes used to analyze facts.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DimCustomer&lt;/strong&gt; containing customer names and regions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DimProduct&lt;/strong&gt; containing product names and categories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DimDate&lt;/strong&gt; containing dates, months and years.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Grain of a fact table
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;grain&lt;/strong&gt; describes what one row represents.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One row in &lt;strong&gt;FactSales&lt;/strong&gt; represents one product line in one customer order.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is important because an order may contain several product lines. Therefore, counting rows may not equal counting unique orders.&lt;/p&gt;

&lt;h2&gt;
  
  
  ShopKe's star schema
&lt;/h2&gt;

&lt;p&gt;FactSales connects to the dimensions through keys:&lt;/p&gt;

&lt;p&gt;DimCustomer&lt;code&gt;[CustomerID]&lt;/code&gt; 1 ─── * FactSales&lt;code&gt;[CustomerID]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;DimProduct&lt;code&gt;[ProductID]&lt;/code&gt;   1 ─── * FactSales&lt;code&gt;[ProductID]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;DimDate&lt;code&gt;[DateKey]&lt;/code&gt;        1 ─── * FactSales&lt;code&gt;[DateKey]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;DimLocation&lt;code&gt;[LocationID]&lt;/code&gt; 1 ─── * FactSales&lt;code&gt;[LocationID]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This allows ShopKe to analyze total sales by product, customer or date.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Relationships in Power BI
&lt;/h2&gt;

&lt;p&gt;A &lt;em&gt;relationship&lt;/em&gt; connects tables by use of matching columns. Relationships are necessary because business data is often distributed across several tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Primary keys and foreign keys
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;primary&lt;/strong&gt; key uniquely identifies a row in a table. A &lt;strong&gt;foreign key&lt;/strong&gt; references a key in another table.&lt;/p&gt;

&lt;p&gt;For example, &lt;strong&gt;CustomerID&lt;/strong&gt; is unique in DimCustomer but may repeat in FactSales because one customer can make multiple purchases.&lt;/p&gt;

&lt;p&gt;This creates a &lt;strong&gt;one to many relationship&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relationship cardinalities
&lt;/h2&gt;

&lt;h3&gt;
  
  
  One to Many (1:*)
&lt;/h3&gt;

&lt;p&gt;One row in a dimension relates to many rows in a fact table.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;DimCustomer&lt;code&gt;[CustomerID]&lt;/code&gt; 1 ─── * FactSales&lt;code&gt;[CustomerID]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the most common relationship in a star schema.&lt;/p&gt;

&lt;h3&gt;
  
  
  One to One (1:1)
&lt;/h3&gt;

&lt;p&gt;Each row in one table matches at most one row in another table.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;Employee&lt;code&gt;[EmployeeID]&lt;/code&gt; 1 ─── 1 EmployeeDetails&lt;code&gt;[EmployeeID]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It is appropriate when two tables contain separate information about the same entity and both sides have unique keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  Many to Many (:)
&lt;/h3&gt;

&lt;p&gt;Multiple rows in one table can relate to multiple rows in another table.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;Students * ─── * Courses&lt;/p&gt;

&lt;p&gt;One student can take many courses and one course can have many students.&lt;/p&gt;

&lt;p&gt;A bridge table can be used for a clearer design as shown:&lt;/p&gt;

&lt;p&gt;DimCustomer 1 ─── * BridgeCustomerSegment * ─── 1 DimSegment&lt;br&gt;
Referential integrity and unique values&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Referential integrity&lt;/strong&gt; means foreign keys should correspond to valid keys in the related dimension, where applicable.&lt;/p&gt;

&lt;p&gt;For example, every CustomerID in FactSales should also exist in DimCustomer. Missing or unmatched keys may indicate data quality problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Active and inactive relationships
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;active relationship&lt;/strong&gt; is used automatically for filter propagation.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;inactive relationship&lt;/strong&gt; is not used automatically but can be activated in a DAX measure.&lt;/p&gt;

&lt;p&gt;For example, FactSales may have &lt;code&gt;OrderDate&lt;/code&gt; and &lt;code&gt;ShipDate&lt;/code&gt;. DimDate can have an &lt;strong&gt;active relationship&lt;/strong&gt; with &lt;code&gt;OrderDate&lt;/code&gt; and an &lt;strong&gt;inactive relationship&lt;/strong&gt; with &lt;code&gt;ShipDate&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Filter Direction
&lt;/h2&gt;

&lt;p&gt;Filter direction determines how &lt;strong&gt;filters move between related tables&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single-direction filtering
&lt;/h3&gt;

&lt;p&gt;Filters flow in one direction, mostly from dimensions to facts.&lt;/p&gt;

&lt;p&gt;DimProduct ───────────&amp;gt; FactSales&lt;/p&gt;

&lt;p&gt;If a user selects Electronics in a product slicer, Power BI filters FactSales to show sales for electronics products.&lt;/p&gt;

&lt;p&gt;Single-direction filtering is  recommended for star schemas because it provides predictable behavior and reduces ambiguity.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bidirectional filtering
&lt;/h3&gt;

&lt;p&gt;Filters flow in both directions.&lt;/p&gt;

&lt;p&gt;DimProduct &amp;lt;──────────&amp;gt; FactSales&lt;/p&gt;

&lt;p&gt;This may be useful in specific scenarios, such as certain bridge-table models.&lt;/p&gt;

&lt;p&gt;However, bidirectional filtering should be used carefully because it can create ambiguous filter paths, unexpected results and unnecessary model complexity.&lt;/p&gt;

&lt;p&gt;For ShopKe, I would use single-direction filtering by default and only introduce bidirectional filtering when there is a clear business requirement.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Joins in Power Query
&lt;/h2&gt;

&lt;p&gt;A join combines rows from two tables using matching columns. In Power Query, this is performed using &lt;strong&gt;Merge Queries&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If ShopKe had the following tables:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DimCustomers&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C002&lt;/td&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C003&lt;/td&gt;
&lt;td&gt;Aisha&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;DimOrders&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;O001&lt;/td&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;75,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O002&lt;/td&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;4,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O003&lt;/td&gt;
&lt;td&gt;C002&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;O004&lt;/td&gt;
&lt;td&gt;C004&lt;/td&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;C003 has no order, while C004 appears in Orders but not Customers.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Left Outer Join
&lt;/h3&gt;

&lt;p&gt;Returns all rows from the left table and matching rows from the right table.&lt;/p&gt;

&lt;p&gt;Example: Customers LEFT JOIN Orders.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;O001&lt;/td&gt;
&lt;td&gt;75,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;O002&lt;/td&gt;
&lt;td&gt;4,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C002&lt;/td&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;td&gt;O003&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C003&lt;/td&gt;
&lt;td&gt;Aisha&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use&lt;/strong&gt;: Finding customers who have not placed orders while retaining all customers.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Right Outer Join
&lt;/h3&gt;

&lt;p&gt;Returns all rows from the right table and matching rows from the left table.&lt;/p&gt;

&lt;p&gt;Example: Customers RIGHT JOIN Orders.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;O001&lt;/td&gt;
&lt;td&gt;75,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;O002&lt;/td&gt;
&lt;td&gt;4,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C002&lt;/td&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;td&gt;O003&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C004&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;O004&lt;/td&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use&lt;/strong&gt;: Identifying orders without matching customer records.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.3 Full Outer Join
&lt;/h3&gt;

&lt;p&gt;Returns all rows from both tables, including unmatched records.&lt;/p&gt;

&lt;p&gt;Expected unmatched records:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;O001&lt;/td&gt;
&lt;td&gt;75,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;O002&lt;/td&gt;
&lt;td&gt;4,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C002&lt;/td&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;td&gt;O003&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C003&lt;/td&gt;
&lt;td&gt;Aisha&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;td&gt;NULL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Matching records are also retained.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use&lt;/strong&gt;: Data reconciliation and identifying missing records in either table.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.4 Inner Join
&lt;/h3&gt;

&lt;p&gt;Returns only rows with matching values in both tables.&lt;/p&gt;

&lt;p&gt;Expected output:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;O001&lt;/td&gt;
&lt;td&gt;75,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C001&lt;/td&gt;
&lt;td&gt;Stacy&lt;/td&gt;
&lt;td&gt;O002&lt;/td&gt;
&lt;td&gt;4,500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C002&lt;/td&gt;
&lt;td&gt;Brian&lt;/td&gt;
&lt;td&gt;O003&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use&lt;/strong&gt;: Keeping only customers who have matching orders.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.5 Left Anti Join
&lt;/h3&gt;

&lt;p&gt;Returns rows from the left table that have no matching rows in the right table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: Customers LEFT ANTI JOIN Orders.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C003&lt;/td&gt;
&lt;td&gt;Aisha&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use&lt;/strong&gt;: Finding customers who have never placed an order.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.6 Right Anti Join
&lt;/h3&gt;

&lt;p&gt;Returns rows from the right table that have no matching rows in the left table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: Customers RIGHT ANTI JOIN Orders.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OrderID&lt;/th&gt;
&lt;th&gt;CustomerID&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;O004&lt;/td&gt;
&lt;td&gt;C004&lt;/td&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use&lt;/strong&gt;: Identifying orders with missing customer records.&lt;/p&gt;

&lt;p&gt;In Power Query, a merge may create a nested table column. For joins that return matching records, the column can be expanded to display the required fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Power Query Joins vs Power BI Relationships
&lt;/h2&gt;

&lt;p&gt;Even though both  connect tables, they serve different purposes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Power Query Merge&lt;/th&gt;
&lt;th&gt;Power BI Relationship&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Stage&lt;/td&gt;
&lt;td&gt;Data preparation&lt;/td&gt;
&lt;td&gt;Data modelling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Purpose&lt;/td&gt;
&lt;td&gt;Combine data&lt;/td&gt;
&lt;td&gt;Connect tables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Physically combines columns?&lt;/td&gt;
&lt;td&gt;Yes, in the merged query result&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filter propagation&lt;/td&gt;
&lt;td&gt;Not as a model relationship&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common use&lt;/td&gt;
&lt;td&gt;Bring ProductCategory into a table&lt;/td&gt;
&lt;td&gt;Connect DimProduct to FactSales&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If ShopKe needs to bring &lt;code&gt;ProductCategory&lt;/code&gt; into FactSales, Power Query Merge can combine the columns.However, if DimProduct already contains &lt;code&gt;ProductCategory&lt;/code&gt;, keeping it separate and creating a relationship is better.&lt;/p&gt;

&lt;p&gt;Too much merging can create a wide table with repeated customer and product information. This may cause increased redundancy and  the model being harder to maintain.Keeping fact and dimension tables separate supports a clearer and more scalable star schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Recommended Power BI Model for ShopKe
&lt;/h2&gt;

&lt;p&gt;For ShopKe, I would recommend a star schema with FactSales connected to DimCustomer, DimProduct and DimDate.&lt;/p&gt;

&lt;p&gt;I would use one-to-many relationships from the dimensions to the fact table and single-direction filtering by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; : Separating facts and dimensions can support efficient analytical queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DAX simplicity&lt;/strong&gt; : Measures such as Total Sales can be written directly against FactSales.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readability&lt;/strong&gt; : Each table has a clear purpose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt; : New transactions, customers and products can be added without redesigning the entire model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability&lt;/strong&gt; : Descriptive information can be updated in dimensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report development&lt;/strong&gt; : Users can easily combine dimension attributes with fact measures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example measures:&lt;/p&gt;

&lt;p&gt;Total Sales =&lt;br&gt;
SUM(FactSales&lt;code&gt;[SalesAmount]&lt;/code&gt;)&lt;br&gt;
Total Orders =&lt;br&gt;
DISTINCTCOUNT(FactSales&lt;code&gt;[OrderID]&lt;/code&gt;)&lt;br&gt;
Average Order Value =&lt;br&gt;
DIVIDE(&lt;code&gt;[Total Sales]&lt;/code&gt;, &lt;code&gt;[Total Orders]&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F34orhyqm68et0u4m8xcz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F34orhyqm68et0u4m8xcz.png" alt="New Measures" width="222" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would use bridge tables for genuine many-to-many scenarios and inactive relationships for alternative date analysis when necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Data modelling is the foundation of a reliable Power BI report. It determines how data is organized, how tables interact and how accurately business questions can be answered.&lt;/p&gt;

&lt;p&gt;As much as  flat tables are simple and snowflake schemas can support complex structures, a &lt;strong&gt;star schema&lt;/strong&gt; is most likely the most suitable choice for a  business intelligence project.&lt;/p&gt;

&lt;p&gt;Through the ShopKe example, we have seen how fact and dimension tables work together, how relationships control filter propagation and how Power Query joins prepare data for analysis.&lt;/p&gt;

&lt;p&gt;The most important lesson is that proper Power BI development is not only about creating visuals. It is about designing a model that is accurate, understandable, scalable and useful for decision-making.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A well designed data model turns disconnected data into meaningful business insights&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>data</category>
      <category>database</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building an Interactive Excel Dashboard for E-commerce Product Analysis: A Case Study of Jumia Products</title>
      <dc:creator>Stacy Mumbi</dc:creator>
      <pubDate>Sat, 05 Sep 2026 13:13:23 +0000</pubDate>
      <link>https://dev.to/smumbi_/building-an-interactive-excel-dashboard-for-e-commerce-product-analysis-a-case-study-of-jumia-468e</link>
      <guid>https://dev.to/smumbi_/building-an-interactive-excel-dashboard-for-e-commerce-product-analysis-a-case-study-of-jumia-468e</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;After completing Excel's coursework this week courtesy of the &lt;strong&gt;LuxDevHQ Data Science, Analytics and AI Programme&lt;/strong&gt;, I decided to put what I had learnt into practice by analyzing Jumia product data. I challenged myself to turn the raw data into something useful for analysis and decision making.&lt;/p&gt;

&lt;p&gt;The dataset contained 115 product listings with information such as prices, discounts, reviews and ratings. However, it was far from ready for data analysis. There were missing values, duplicate records, negative review counts, inconsistent formatting and even one product whose price was given as a range.&lt;/p&gt;

&lt;p&gt;So, this project ended up being about much more than creating a dashboard. I first had to understand the data, identify the issues, make reasonable cleaning decisions, document those decisions and then use the cleaned data to build an interactive Excel dashboard.&lt;/p&gt;

&lt;p&gt;In this article, I'll walk through that process, from the initial data-quality audit to the final dashboard and the insights I found from the analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dataset and Business Questions
&lt;/h2&gt;

&lt;p&gt;The dataset, &lt;code&gt;Excel_jumia_dataset.csv&lt;/code&gt;, contained six  fields originally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Product&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Current price&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;old price&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Discount&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Review&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ratingd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last column, &lt;code&gt;Ratingd&lt;/code&gt;, was misspelled in the original dataset and was later corrected to &lt;code&gt;Rating&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One of the first things I noticed was that the dataset didn't contain actual sales, revenue or units sold data. Because of this, I couldn't use sales as a measure of product performance.&lt;/p&gt;

&lt;p&gt;Instead, I used review count as a &lt;strong&gt;proxy for customer engagement&lt;/strong&gt; throughout the project.&lt;/p&gt;

&lt;p&gt;This  was important to take note of because having &lt;strong&gt;more reviews&lt;/strong&gt; doesn't necessarily mean that a product has &lt;strong&gt;higher sales&lt;/strong&gt;. A product that has been listed for a longer period, for example, may simply have had more time to accumulate reviews.&lt;/p&gt;

&lt;p&gt;With that in mind, I focused on the following questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are bigger discounts associated with more reviews?&lt;/li&gt;
&lt;li&gt;Do highly rated products receive more engagement?&lt;/li&gt;
&lt;li&gt;Does product price have any relationship with rating?&lt;/li&gt;
&lt;li&gt;Which products stand out based on ratings, reviews or discounts?&lt;/li&gt;
&lt;li&gt;Which products might need a different pricing, marketing or listing strategy?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data-Quality Audit
&lt;/h2&gt;

&lt;p&gt;Before changing anything, I wanted to understand exactly what I was working with.&lt;/p&gt;

&lt;p&gt;The initial audit showed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;115 rows and 6 columns&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;58 blank Review values&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;58 blank Rating values&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3 exact duplicate rows&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 repeated product names&lt;/strong&gt; with different prices, discounts, or review counts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;57 negative Review values&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1 row where both Current price and Old price were given as ranges&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Ratings were within the expected &lt;strong&gt;0–5 range&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Discounts were within &lt;strong&gt;0–100%&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;No Current Price was &lt;strong&gt;higher&lt;/strong&gt; than the corresponding Old Price&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing that I immediately realised: all &lt;strong&gt;57 non-blank Review values&lt;/strong&gt; were negative.&lt;/p&gt;

&lt;p&gt;That was unusual. Since a review count cannot be negative realistically, I treated this as a likely systematic scraping or formatting issue rather than assuming the values represented something meaningful.&lt;/p&gt;

&lt;p&gt;If only a few values had been negative, I would have been more cautious about changing them. But because every non-blank review value had the same issue, the pattern strongly suggested a consistent data-quality problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzbnwiqsfctg1wlcrvw09.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzbnwiqsfctg1wlcrvw09.png" alt="Raw data" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The original dataset as imported into the Raw_data sheet. The negative &lt;code&gt;Review&lt;/code&gt; values and misspelled &lt;code&gt;Ratingd&lt;/code&gt; header are visible.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning the Data and Why I Made These Decisions
&lt;/h2&gt;

&lt;p&gt;Cleaning the dataset was one of the most important parts of the project. I didn't want to change values simply because they looked inconvenient. For each major cleaning step, I considered what the data was actually telling me and how the decision would affect the analysis.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Fixing the Negative Review Counts
&lt;/h3&gt;

&lt;p&gt;There were 57 negative Review values and all non-blank review values had this issue.&lt;/p&gt;

&lt;p&gt;I created a helper column and used the following formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=IF(E2="","",ABS(VALUE(E2)))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This converted the negative values into positive review counts while keeping genuinely blank cells blank.&lt;/p&gt;

&lt;p&gt;After checking the results, I pasted the corrected values as values so that the cleaned numbers were no longer dependent on the formula.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Handling Missing Reviews and Ratings
&lt;/h3&gt;

&lt;p&gt;Both &lt;code&gt;Review&lt;/code&gt; and &lt;code&gt;Rating&lt;/code&gt; contained &lt;strong&gt;58 blank values&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I intentionally &lt;strong&gt;left these cells blank&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A blank Review means that the review count wasn't captured. A zero means that the product had zero reviews. These are two completely different situations.&lt;/p&gt;

&lt;p&gt;Replacing the blanks with zero would therefore have affected averages, rankings and other calculations in ways that weren't supported by the original data.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Handling the Price Range
&lt;/h3&gt;

&lt;p&gt;One product, a 1/2/3 Seater Elastic Sofa Cover, had its prices listed as ranges:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Current price&lt;/strong&gt;: KSh 1,620–1,980&lt;br&gt;
&lt;strong&gt;Old price&lt;/strong&gt;: KSh 2,200–3,200&lt;/p&gt;

&lt;p&gt;I had three options to choose from:&lt;/p&gt;

&lt;p&gt;Use the lower value&lt;br&gt;
Remove the row&lt;br&gt;
Use the midpoint&lt;/p&gt;

&lt;p&gt;I chose the &lt;strong&gt;midpoint&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using the lower bound would ignore part of the information provided, while removing the row would mean losing a  useful product just because its price was formatted differently.&lt;/p&gt;

&lt;p&gt;The original range was retained elsewhere so that the decision could still be traced back to the source data.&lt;/p&gt;

&lt;p&gt;There was also an interesting consequence of this decision. When I calculated the discount using the midpoint prices, I got &lt;strong&gt;33%&lt;/strong&gt;, while the seller's advertised discount was &lt;strong&gt;38%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Rather than replacing the advertised value, I kept both values. The difference is documented as a result of using an estimated midpoint rather than an exact price.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Removing Duplicates
&lt;/h3&gt;

&lt;p&gt;The dataset contained &lt;strong&gt;three rows&lt;/strong&gt; that were &lt;strong&gt;completely identical&lt;/strong&gt; across all six original fields. I removed these as they were &lt;strong&gt;exact duplicates&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However, there were also &lt;strong&gt;six&lt;/strong&gt; cases where the same product name appeared more than once but the prices, discounts or review counts were different.I kept these records.&lt;/p&gt;

&lt;p&gt;Because Jumia is a marketplace with multiple sellers, the repeated product names could represent different seller listings rather than duplicate records. Removing them without evidence would have meant making an assumption that the data didn't support.&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Fixing Text and Formatting Issues
&lt;/h3&gt;

&lt;p&gt;I also made other formatting corrections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removed "out of 5" from the &lt;code&gt;Rating&lt;/code&gt; values&lt;/li&gt;
&lt;li&gt;Converted &lt;code&gt;Rating&lt;/code&gt; into a numeric decimal&lt;/li&gt;
&lt;li&gt;Changed &lt;code&gt;Ratingd&lt;/code&gt; to &lt;code&gt;Rating&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Standardized &lt;code&gt;old price&lt;/code&gt; to &lt;code&gt;Old Price&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Converted prices from text into numeric currency values&lt;/li&gt;
&lt;li&gt;Formatted prices as &lt;code&gt;KSh #,##0.00&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl4v2lj6vnrlm4oe1dksu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl4v2lj6vnrlm4oe1dksu.png" alt="Cleaned data" width="800" height="433"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The cleaned tblProducts table showing corrected data types, standardized fields and additional analytical columns.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All of these cleaning decisions were documented in the &lt;strong&gt;Data Dictionary&lt;/strong&gt; sheet so that the process could be reviewed and traced back to the original data.&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding Enrichment Fields
&lt;/h2&gt;

&lt;p&gt;Once the basic cleaning was complete, I created additional fields to make the dataset more useful for analysis.&lt;/p&gt;
&lt;h3&gt;
  
  
  Discount Amount and Calculated Discount
&lt;/h3&gt;

&lt;p&gt;I calculated the difference between the Old Price and Current Price to get the &lt;strong&gt;Discount Amount&lt;/strong&gt;.I also calculated the corresponding percentage discount and kept it alongside the original &lt;strong&gt;advertised Discount&lt;/strong&gt;.&lt;br&gt;
This made it possible to compare the advertised discount with the discount calculated from the prices.&lt;/p&gt;
&lt;h3&gt;
  
  
  Rating Category
&lt;/h3&gt;

&lt;p&gt;I grouped products into three rating categories:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Poor&lt;/strong&gt;: &amp;lt; 3&lt;br&gt;
&lt;strong&gt;Average&lt;/strong&gt;: 3–4.5&lt;br&gt;
&lt;strong&gt;Excellent&lt;/strong&gt;: &amp;gt; 4.5&lt;/p&gt;

&lt;p&gt;The original brief left ratings from 4.1 to 4.5 without a category. I therefore followed the suggested option of including this range under Average and documented this as a working assumption.&lt;/p&gt;
&lt;h3&gt;
  
  
  Discount Category
&lt;/h3&gt;

&lt;p&gt;Discounts were grouped into:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Low&lt;/strong&gt;: &amp;lt; 20%&lt;br&gt;
&lt;strong&gt;Medium&lt;/strong&gt;: 20–40%&lt;br&gt;
&lt;strong&gt;High&lt;/strong&gt;: &amp;gt; 40%&lt;/p&gt;
&lt;h3&gt;
  
  
  Price Category
&lt;/h3&gt;

&lt;p&gt;Rather than guessing price cutoffs, I used the data itself to determine the categories.&lt;/p&gt;

&lt;p&gt;I calculated the first and third quartiles of Current Price using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;QUARTILE.INC()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting thresholds were:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Price Q1&lt;/strong&gt;: KSh 493&lt;br&gt;
&lt;strong&gt;Price Q3&lt;/strong&gt;: KSh 1,669.50&lt;/p&gt;

&lt;p&gt;I then used these thresholds  to classify products into &lt;strong&gt;Low, Medium and High&lt;/strong&gt; price categories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Engagement Strength
&lt;/h3&gt;

&lt;p&gt;I also wanted a data-driven way to identify products with relatively high engagement.&lt;/p&gt;

&lt;p&gt;I used the &lt;strong&gt;75th percentile&lt;/strong&gt; of Review count as the threshold:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review Q3&lt;/strong&gt;: 13 reviews&lt;/p&gt;

&lt;p&gt;Products with 13 or more reviews were therefore classified as having &lt;strong&gt;Strong Engagement&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Status
&lt;/h3&gt;

&lt;p&gt;Because the dataset contained many missing ratings and reviews, I added a &lt;code&gt;Data Status&lt;/code&gt; field showing whether each product was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete&lt;/li&gt;
&lt;li&gt;Missing rating&lt;/li&gt;
&lt;li&gt;Missing review&lt;/li&gt;
&lt;li&gt;Missing both&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This made it easier to understand the level of data coverage behind the analysis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Combination Flags
&lt;/h3&gt;

&lt;p&gt;Finally, I created &lt;strong&gt;four&lt;/strong&gt; flags to identify products with interesting combinations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High discount + low rating&lt;/li&gt;
&lt;li&gt;High discount + low engagement&lt;/li&gt;
&lt;li&gt;Many reviews + average rating&lt;/li&gt;
&lt;li&gt;Strong engagement + excellent rating&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whenever one of the required values was missing, the formula returned "Missing" rather than making an assumption.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7lwrehww02ddxxb3b72h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7lwrehww02ddxxb3b72h.png" alt="Formula" width="800" height="18"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example of an Excel formula used to classify products into Rating Categories.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PivotTables and Analysis Workflow
&lt;/h2&gt;

&lt;p&gt;With the data cleaned and enriched, I moved on to the analysis.&lt;br&gt;
One of the main things I wanted to investigate was whether price, discount, rating and review count were related.&lt;/p&gt;

&lt;p&gt;I focused on three relationships:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discount vs. Reviews&lt;/li&gt;
&lt;li&gt;Rating vs. Reviews&lt;/li&gt;
&lt;li&gt;Current Price vs. Rating&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because &lt;code&gt;Review&lt;/code&gt; and &lt;code&gt;Rating&lt;/code&gt; contained missing values, I didn't want blank cells to interfere with the correlation analysis.&lt;/p&gt;

&lt;p&gt;I therefore created helper ranges using &lt;code&gt;FILTER()&lt;/code&gt; to return only rows where both variables in each pair were available. I then used these complete pairs for the correlation calculations and scatter plots.&lt;/p&gt;

&lt;p&gt;The results were:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Relationship&lt;/th&gt;
&lt;th&gt;Pearson r&lt;/th&gt;
&lt;th&gt;R²&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Discount vs. Reviews&lt;/td&gt;
&lt;td&gt;-0.111&lt;/td&gt;
&lt;td&gt;0.012&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rating vs. Reviews&lt;/td&gt;
&lt;td&gt;0.043&lt;/td&gt;
&lt;td&gt;0.002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current Price vs. Rating&lt;/td&gt;
&lt;td&gt;0.110&lt;/td&gt;
&lt;td&gt;0.012&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All three relationships were &lt;strong&gt;very weak&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, the correlation between Discount and Reviews was &lt;strong&gt;-0.111&lt;/strong&gt;, which is very close to zero.&lt;/p&gt;

&lt;p&gt;The R² values were also extremely small, meaning that each variable explained &lt;strong&gt;very little&lt;/strong&gt; of the variation in the other variable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqfjwpsyvlyqjqwmrhkp5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqfjwpsyvlyqjqwmrhkp5.png" alt="Correlation" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Scatter plots for Discount vs. Reviews, Rating vs. Reviews, and Current Price vs. Rating, each with a linear trendline, equation and R² value.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Product Rankings
&lt;/h3&gt;

&lt;p&gt;I also created PivotTables to identify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Top 10 products by Rating&lt;/li&gt;
&lt;li&gt;Bottom 10 products by Rating&lt;/li&gt;
&lt;li&gt;Top 10 products by Reviews&lt;/li&gt;
&lt;li&gt;Top 10 products by Discount&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also used the combination flags to identify products that met the four additional conditions.&lt;/p&gt;

&lt;p&gt;For rating-based rankings, products with missing ratings were excluded.&lt;br&gt;
Where products had the same rating, I used review count as the tie-breaker. For review-count ties, rating was used as the tie-breaker.&lt;/p&gt;

&lt;p&gt;This made the ranking rules explicit rather than leaving the ordering to chance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa3txgi7pu3fezil57ihp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa3txgi7pu3fezil57ihp.png" alt="Top 10 Products by Discount" width="799" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5knc85c9t7w2nnhpk9y8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5knc85c9t7w2nnhpk9y8.png" alt="Top 10 products by rating" width="800" height="306"&gt;&lt;/a&gt;&lt;br&gt;
_PivotTables used to identify the highest and lowest-performing products across ratings and discounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Interactive Dashboard
&lt;/h2&gt;

&lt;p&gt;After completing the analysis, I brought the most useful pieces together into a &lt;strong&gt;single-screen dashboard&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I wanted the dashboard to answer the main questions quickly without requiring someone to scroll through multiple sheets.&lt;/p&gt;

&lt;p&gt;The dashboard includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;KPI Cards&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Total Products&lt;/li&gt;
&lt;li&gt;Average Price&lt;/li&gt;
&lt;li&gt;Average Discount&lt;/li&gt;
&lt;li&gt;Average Rating&lt;/li&gt;
&lt;li&gt;Total Reviews&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Product Ranking Charts&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Top 10 by Rating&lt;/li&gt;
&lt;li&gt;Top 10 by Reviews&lt;/li&gt;
&lt;li&gt;Top 10 by Discount&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationship Analysis&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Discount vs. Reviews&lt;/li&gt;
&lt;li&gt;Rating vs. Reviews&lt;/li&gt;
&lt;li&gt;Price vs. Rating&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each scatter plot includes a trendline, equation and R² value.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Category Analysis&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Rating Mix&lt;/li&gt;
&lt;li&gt;Discount Mix&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Slicers&lt;/strong&gt;
The dashboard has &lt;strong&gt;slicers&lt;/strong&gt; for:

&lt;ul&gt;
&lt;li&gt;Rating Category&lt;/li&gt;
&lt;li&gt;Discount Category&lt;/li&gt;
&lt;li&gt;Price Category&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These slicers are connected to the compatible PivotTables and charts, allowing the dashboard to update when a user filters the data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgot19s72tp7by95fo23n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgot19s72tp7by95fo23n.png" alt="Dashboard" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The completed single-screen dashboard combining KPIs, product rankings, relationship analysis, category charts and interactive slicers.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Findings
&lt;/h2&gt;

&lt;p&gt;After cleaning and analyzing the data, a few findings stood out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Bigger Discounts Didn't Necessarily Mean More Engagement&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The correlation between Discount and Review count was &lt;strong&gt;-0.111&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's really close to zero.&lt;/p&gt;

&lt;p&gt;So in this dataset, products with larger discounts did not necessarily have more reviews.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Price and Rating Were Barely Related&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The correlation between Current Price and Rating was &lt;strong&gt;0.110&lt;/strong&gt;.&lt;br&gt;
This is also a &lt;strong&gt;very weak&lt;/strong&gt; relationship.&lt;/p&gt;

&lt;p&gt;In this dataset, highly rated products were not always more expensive or cheaper than products with lower ratings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Some Heavily Discounted Products Still Had Weak Performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some products combined a &lt;strong&gt;high discount with either a low rating or low engagement&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These products caught my attention because offering a bigger discount may not solve the underlying problem.&lt;/p&gt;

&lt;p&gt;They could instead be worth investigating from a listing-quality perspective, such as product descriptions, images, presentation or customer expectations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Some Products Had Both Strong Engagement and Excellent Ratings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There were also 5 products that stood out for having both strong engagement and excellent ratings.They could provide useful examples of what appears to be working well.&lt;/p&gt;

&lt;p&gt;Even though the dataset doesn't contain enough information to explain why these products perform well, they would be good choices for further investigation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Business Recommendations
&lt;/h2&gt;

&lt;p&gt;Based on the patterns in the data, I would recommend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Not to rely on discounts alone to drive engagement&lt;/strong&gt;. Since discount and review count were almost not related, sellers could test other approaches such as improving product descriptions, images and overall listing quality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Investigating heavily discounted products with low ratings or engagement&lt;/strong&gt;. Instead of immediately offering an even bigger discount, it may be better to first understand why the product isn't attracting positive customer feedback.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Studying products with strong engagement and excellent ratings&lt;/strong&gt;. These products could provide useful examples for understanding what works well across listings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using data carefully when making decisions&lt;/strong&gt;. The results show patterns in this dataset, but they don't prove that changing one variable will cause another to change.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This project also has limitations like any other.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The biggest one is that the dataset doesn't contain sales, revenue, units sold or listing-age data. Because of this, &lt;strong&gt;review count&lt;/strong&gt; is only a proxy for engagement and cannot be treated as a measure of sales performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There is also one product whose price had to be estimated using the midpoint of a range rather than an exact value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;strong&gt;Rating Category&lt;/strong&gt; assumption for ratings between 4.1 and 4.5. I grouped these under "Average" based on the suggested option in the project brief, but this was just a working assumption .&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The correlations in this analysis describe relationships between variables. Correlation does not imply causation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;One of my biggest lessons from this project was that &lt;strong&gt;data analysis starts  before the charts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Initially, the dataset looked small and straightforward. But once I started auditing it, I found several issues that could have easily affected the final results if I had jumped straight into analysis. &lt;/p&gt;

&lt;p&gt;The negative review counts were a good example. If I hadn't investigated that pattern, I could have ended up presenting misleading engagement figures.&lt;/p&gt;

&lt;p&gt;I also learned &lt;strong&gt;the importance of documenting assumptions&lt;/strong&gt;. For example, rather than silently changing the price-range row or filling missing values with zeros, I recorded what I did and why.&lt;/p&gt;

&lt;p&gt;Most importantly, this project helped me &lt;strong&gt;see Excel as more than just a spreadsheet tool&lt;/strong&gt;. I was able to use it for the full analytics process that is  data auditing, cleaning, transformation, analysis, visualization and communication , all within one workbook.&lt;/p&gt;

&lt;p&gt;And probably the biggest lesson was that &lt;strong&gt;a good dashboard isn't just about making something look nice&lt;/strong&gt;. The real value comes from making sure that the numbers behind it are trustworthy and that the story you're telling is actually supported by the data.&lt;/p&gt;

&lt;p&gt;I am honestly still in awe of how such a seemingly small dataset could yield so many other columns and useful insights after proper cleaning and  analysis.&lt;br&gt;
From just a few original columns, I was able to create additional fields, uncover patterns, build meaningful visualizations and turn the data into a dashboard that tells a story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How I love being a data analyst!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Files
&lt;/h2&gt;

&lt;p&gt;The complete project is available here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/SMumbi5144/Jumia_Product_Performance_Dashboard.git" rel="noopener noreferrer"&gt;Jumia_Product_Performance_Dashboard&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Dashboard Worksheet&lt;/strong&gt;: Available in the repository under &lt;code&gt;dashboard&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Raw Dataset&lt;/strong&gt;: Available under &lt;code&gt;data&lt;/code&gt;&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>data</category>
      <category>datascience</category>
      <category>learning</category>
    </item>
    <item>
      <title>Getting Started with Excel for Data Analytics: From Basics to Data Cleaning</title>
      <dc:creator>Stacy Mumbi</dc:creator>
      <pubDate>Sun, 30 Aug 2026 05:47:14 +0000</pubDate>
      <link>https://dev.to/smumbi_/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-54p1</link>
      <guid>https://dev.to/smumbi_/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-54p1</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Data is definitely everywhere because almost all the information we receive everyday can be collected and analysed data, but having a dataset is only the beginning of the data analytics process. Before analysing data and drawing conclusions from it, it is important to make sure that the data is accurate, consistent, complete and in the correct format through a  process called data cleaning.&lt;/p&gt;

&lt;p&gt;During Week 3 of my Data Science and Analytics training at LuxDev Academy, I was introduced to the basics of Microsoft Excel and how it can be used to prepare data for analysis. I used to view Excel as just an application that is used to view spreadsheets, but this week I learnt that it has many useful features for working with real-world datasets. These include sorting, filtering, formatting, removing duplicates, finding and replacing values and using functions such as &lt;strong&gt;TRIM&lt;/strong&gt;, &lt;strong&gt;PROPER&lt;/strong&gt; and &lt;strong&gt;CONCAT&lt;/strong&gt; which are known as &lt;strong&gt;Text Functions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For practice, I decided to work on a synthetic Kenyan &lt;strong&gt;M-Pesa&lt;/strong&gt; transaction dataset generated using &lt;strong&gt;Mockaroo&lt;/strong&gt;. The dataset contains 193 transaction records and includes information such as transaction IDs, transaction dates, sender and receiver names, transaction types, transaction amounts, transaction status, counties and transaction fees.&lt;/p&gt;

&lt;p&gt;Even though the dataset was synthetic and small, it contained several inconsistencies that provided an opportunity to practise the data-cleaning concepts I had learned. In this article, I will walk through how I did the cleaning, from importing the dataset into Excel to identifying and correcting formatting, missing values, duplicates and inconsistencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Generating and Importing the Dataset
&lt;/h2&gt;

&lt;p&gt;I first generated the M-Pesa transactions dataset using &lt;strong&gt;Mockaroo&lt;/strong&gt; and downloaded it as a &lt;strong&gt;CSV(Comma Separated Values)&lt;/strong&gt; file. I chose an M-Pesa dataset because mobile money transactions are really relevant to the Kenyan context as millions of people transact money everyday using M-Pesa and it can contain different types of information that would be useful for data analysis.&lt;/p&gt;

&lt;p&gt;After downloading the CSV file, I opened Microsoft Excel. Instead of opening the file directly through the &lt;strong&gt;File&lt;/strong&gt; section, I practised importing the data through the &lt;strong&gt;Data&lt;/strong&gt; option on the ribbon at the top of the blank workbook: &lt;strong&gt;'Data' then 'Get Data' then 'From File' then 'From Text/CSV'&lt;/strong&gt;. Excel then showed a preview of the data before loading it into the workbook.&lt;/p&gt;

&lt;p&gt;It was a very important first step before beginning any cleaning.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F42m3fquu79dvgy29kqyy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F42m3fquu79dvgy29kqyy.png" alt="_This is how the dataset looked like after loading and before I started cleaning._" width="800" height="426"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;This is how the dataset looked like after loading and before I started cleaning.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Making a Duplicate Sheet Before Cleaning
&lt;/h2&gt;

&lt;p&gt;Before making any changes to the data, I duplicated the worksheet by right-clicking the sheet tab by copying the whole dataset by first using keyboard shortcut &lt;strong&gt;Ctrl+A&lt;/strong&gt; to select the whole dataset,then &lt;strong&gt;Ctrl+C&lt;/strong&gt; to copy, then added a new sheet and then right-clicked in the top-left cell to paste the dataset . This gave me an untouched version of the original dataset to refer back to, while I carried out all my cleaning on the duplicate sheet.&lt;br&gt;
If I made a mistake while cleaning, I still had the original data intact rather than needing to re-download the dataset or opening it from my file explorer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7t2bdqgr12w9h6bsn3im.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7t2bdqgr12w9h6bsn3im.png" alt="_Creating a backup copy of the sheet so the original data stayed untouched._" width="799" height="423"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Creating a backup copy of the sheet so the original data stayed untouched.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Formatting, Sorting and Checking for Duplicates
&lt;/h2&gt;

&lt;p&gt;Once the dataset was loaded, I used &lt;strong&gt;'Home' then 'Format' then 'AutoFit Column Width'&lt;/strong&gt; so that all the values were completely visible, which made it easier to see the data during cleaning.&lt;/p&gt;

&lt;p&gt;I then checked the dataset for duplicate records using &lt;strong&gt;'Data' then 'Data Tools' then 'Remove Duplicates'&lt;/strong&gt;, selecting all columns so that only exact duplicate rows would be removed. Excel returned that no duplicates were found. Even though none were present, the step was important  because checking that a potential problem does not exist is as much a part of data cleaning as fixing one that does.&lt;/p&gt;

&lt;p&gt;I also applied filters via &lt;strong&gt;'Home' then 'Sort &amp;amp; Filter' then 'Filter'&lt;/strong&gt;, which added drop-down buttons to each column header. This made it much faster to look at individual columns. For example, checking 'County' for blanks or checking 'Transaction Status' and 'Transaction Type' for inconsistent entries  without having to scroll through every column.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3dzqla3miy0opq3j6wwn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3dzqla3miy0opq3j6wwn.png" alt="_The Home ribbon tools I relied used for formatting and checking the data._" width="799" height="80"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Home ribbon tools I  used for formatting and creating the drop-downs.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Checking and Correcting Data Types
&lt;/h2&gt;

&lt;p&gt;I then went column by column checking whether Excel had interpreted each one correctly, since a value can look correct visually while having the wrong  data type.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transaction ID&lt;/strong&gt; - changed from Number to &lt;strong&gt;Text&lt;/strong&gt;, since it is an identifier rather than a value that can be calculated or aggregated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transaction Date&lt;/strong&gt; - changed from General to a proper &lt;strong&gt;Date&lt;/strong&gt; format (year-month-day), making it possible to sort and support  analysis later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sender Name / Receiver Name&lt;/strong&gt; - already correctly identified as text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sender Phone&lt;/strong&gt; - converted to &lt;strong&gt;Text&lt;/strong&gt;, since phone numbers are identifiers not quantities that can be aggregated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transaction Type / Transaction Status&lt;/strong&gt; - already identified as text, but needed further cleaning for consistency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transaction Amount / Transaction Fee&lt;/strong&gt; - formatted from &lt;strong&gt;Number&lt;/strong&gt; to &lt;strong&gt;Currency (KES)&lt;/strong&gt;, since these represent monetary values and needed to  clearly show that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Handling Missing Values
&lt;/h2&gt;

&lt;p&gt;Using the drop-downs I had applied earlier, I checked each column for blanks. I found missing values in &lt;strong&gt;County&lt;/strong&gt;, as well as in the numeric fields &lt;strong&gt;Transaction Amount&lt;/strong&gt; and &lt;strong&gt;Transaction Fee&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I did not treat all missing values the same way. For the text column, &lt;strong&gt;County&lt;/strong&gt;, I replaced blanks with "Unknown". For the numerical fields, I left the blanks as they were rather than filling in a made-up value as it would have added incorrect information to the dataset rather than  fixing it.&lt;/p&gt;

&lt;p&gt;This taught me that how you handle a missing value should depend on what the column represents and not a single default rule applied everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Standardising Text with Key Functions
&lt;/h2&gt;

&lt;p&gt;Several columns had inconsistent capitalisation or extra spacing, so this was where most of my actual cleaning work happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Find and Replace (Ctrl + H)&lt;/strong&gt; - used to correct inconsistent entries in Transaction Type (e.g different casings of "Pay Bill") and Transaction Status (e.g "failed" vs "Failed").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TRIM&lt;/strong&gt; - used in a helper column to remove hidden extra spaces from text values that looked correct but weren't matching due to leading spaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PROPER&lt;/strong&gt; - used in a helper column to standardise capitalisation in Sender Name and Receiver Name (e.g turning "MUTUA KARANJA" into "Mutua Karanja").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CONCAT&lt;/strong&gt; - used to restore the leading zero on Kenyan phone numbers after removing  apostrophes and the country-code  had left some numbers starting with "1" instead of "0". The formula I used was &lt;code&gt;=CONCAT("0",D2)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each of these, I applied the formula to the first cell in a row, used AutoFill to apply it down the column, then used &lt;strong&gt;Paste Special for Values only&lt;/strong&gt; to convert the formula results into permanent values in a new column before deleting the helper columns. This kept my final dataset clean while preserving the original column structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F989d7hmacrr5b3u6wst6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F989d7hmacrr5b3u6wst6.png" alt="One of the helper columns" width="262" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For cleaning the sender name column I created a helper column and used the above formulas to clean it.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. What I Learned From the Cleaning Process
&lt;/h2&gt;

&lt;p&gt;Working on this dataset helped me understand that data cleaning is more than  removing duplicates and deleting or filling blank cells.&lt;/p&gt;

&lt;p&gt;This is a brief summary of what I learnt:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The importance of understanding the meaning of each column before deciding how to clean it. A phone number consists of digits, but treating it as numeric wouldn't make sense because there's no meaningful total or average of phone numbers. Also, a Transaction ID may contain only numbers but should be treated as text because it's an identifier, not a value to calculate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Missing values should be handled according to the type and meaning of the data i.e "Unknown" for text fields where appropriate and left blank for numeric fields instead of guessing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sorting and filtering are really important tools as they help you find out what's actually in a column before you touch it. In addition, creating a copy of the original sheet before cleaning meant I could  correct mistakes without risking the original data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Excel usually offers more than one way to solve the same problem like in the case of  PROPER versus Find and Replace and choosing between them often comes down to the type of inconsistency and personal preference.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;My first practical data-cleaning project using Excel gave me a much better understanding of how raw data can be prepared for analysis.&lt;/p&gt;

&lt;p&gt;I started with a synthetic Kenyan M-Pesa transactions dataset generated using Mockaroo and imported it into Excel. Before making any changes, I duplicated the sheet to preserve the original data, then worked through the dataset column by column correcting data types, formatting monetary fields as KES currency, converting dates into the correct format, treating identifiers like Transaction ID and phone numbers as text, handling missing values carefully and standardising text using TRIM, PROPER, Find and Replace and CONCAT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fog1keqx6myyfnltcqqvw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fog1keqx6myyfnltcqqvw.png" alt="_The dataset after cleaning now with consistent formatting and standardized text_." width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The dataset after cleaning now with consistent formatting and standardized text&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The dataset was not too messy, but that actually made it easier for my first practice exercise. It allowed me to focus on understanding the purpose of each Excel tool rather than becoming overwhelmed by a very complicated dataset.&lt;/p&gt;

&lt;p&gt;I learnt that good data cleaning requires both technical Excel skills and an understanding of the data itself. Excel provides the tools, but I still need to make informed decisions about how those tools should be used.&lt;/p&gt;

&lt;p&gt;As I continue learning data analytics, I hope to build on these skills and become more confident in using Excel for larger and more complex datasets. Week 3 has given me a strong foundation and I now have a better understanding of how important data cleaning is before carrying out analysis and visualisation.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>My First Project:From a Local Folder to GitHub Using Git and SSH</title>
      <dc:creator>Stacy Mumbi</dc:creator>
      <pubDate>Sat, 22 Aug 2026 17:59:57 +0000</pubDate>
      <link>https://dev.to/smumbi_/my-first-projectfrom-a-local-folder-to-github-using-git-and-ssh-407h</link>
      <guid>https://dev.to/smumbi_/my-first-projectfrom-a-local-folder-to-github-using-git-and-ssh-407h</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;It's only been two weeks since I enrolled in the &lt;strong&gt;LuxDev Data Science, Analytics and AI program&lt;/strong&gt; yet I've already learnt so much!&lt;br&gt;
One of the first things I've been able to learn is how to take a project from a local folder in my PC and publish it to GitHub using &lt;strong&gt;Git and SSH&lt;/strong&gt;.&lt;br&gt;
For someone who is still building their skills in data and tech,terms like repositories,commits,staging,remotes and SSH keys were new to me at first. Working on my first project helped me understand these commands and  also what happens behind the scenes.&lt;/p&gt;

&lt;p&gt;So for a start,I decided to document my experience of taking &lt;strong&gt;my first GitHub project from a local folder to GitHub using Git and SSH&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;What are Git and GitHub?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Interestingly, I learnt that Git and GitHub are not the same thing. This is why understanding what each of them means became a very important step in my project.&lt;/p&gt;
&lt;h3&gt;
  
  
  Git
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Git&lt;/strong&gt; is a version control system which runs in my PC and helps me keep track of changes made to files in a project.&lt;br&gt;
As I work,I might change my code,update my analysis,add new files or fix mistakes. Git lets me keep track of the changes I make over time instead of having multiple edited copies of the same file. Each saved version is called a &lt;strong&gt;commit&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  GitHub
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt; is an online platform where repositories from Git can be stored and shared.&lt;br&gt;
Git does not need to work with GitHub as I can use it in my PC without uploading my project elsewhere.&lt;br&gt;
However, GitHub becomes useful when I want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep a back up of my projects online&lt;/li&gt;
&lt;li&gt;Show potential employers what I can do&lt;/li&gt;
&lt;li&gt;Share my work &lt;/li&gt;
&lt;li&gt;Collaborate with others &lt;/li&gt;
&lt;li&gt;Build a portfolio &lt;/li&gt;
&lt;li&gt;Contribute to open-source projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a nutshell, this is the journey the local folder in my PC took to reach Github:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Project folder in my PC
         `
Track changes with Git
         `
Commit changes
         `
Push to GitHub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Create the Project Files
&lt;/h3&gt;

&lt;p&gt;I first created my project folder in my PC's file explorer and named it   &lt;strong&gt;Kenya_Health_Records_Analysis&lt;/strong&gt;.&lt;br&gt;
Then I opened Git Bash and navigated to it using these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;Desktop
&lt;span class="nb"&gt;cd &lt;/span&gt;Kenya_Health_Records_Analysis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cd&lt;/code&gt;(change directory) is a command that tells Git to enter a file or folder in simple terms. &lt;br&gt;
I then proceeded to add a data and README.md file in the project folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;data
&lt;span class="nb"&gt;touch &lt;/span&gt;README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;mkdir&lt;/code&gt;(make directory) is used to create a new file or folder from the Git Bash terminal but notice I did not use it to create the README.md file because &lt;code&gt;touch&lt;/code&gt; is used to create files with extensions like .md, .py or .ipynb .&lt;br&gt;
I then copied my &lt;em&gt;Kenya_Health_Records.csv&lt;/em&gt; dataset and pasted it into the newly created data file in my file explorer.&lt;br&gt;
To confirm this in Git Bash I ran the &lt;code&gt;ls&lt;/code&gt; command which lists the contents of a file or folder. &lt;br&gt;
This is what I could see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;data
Kenya_Health_Records.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I went ahead to briefly describe the project in the README.me using the &lt;code&gt;echo&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"# Kenya_Health_Records_Analysis"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;README.md
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;" Using Excel to analyze Kenya health records to uncover,trends,patterns and insights in healthcare data."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;echo&lt;/code&gt; prints text while &lt;code&gt;&amp;gt;&lt;/code&gt;directs the text into the README.md file however &lt;code&gt;&amp;gt;&lt;/code&gt; can replace what is already in the README.md file that is why in the next line I used &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; which adds content below what is already there.&lt;br&gt;
To view the full README.md I used the &lt;code&gt;cat&lt;/code&gt; command (which displays the contents of a file in the terminal) and ran &lt;code&gt;cat README.md&lt;/code&gt; which retrieved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Kenya_Health_Records_Analysis&lt;/span&gt;
Using Excel to analyze Kenya health records to uncover,trends,patterns and insights in healthcare data.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Turning the Folder into a Git Repository
&lt;/h3&gt;

&lt;p&gt;I then ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command initializes a new Git repository and Git begins to manage the project. It also added a new hidden &lt;code&gt;.git&lt;/code&gt; file  in the project folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Checking the Status of My Project
&lt;/h3&gt;

&lt;p&gt;One of the most useful Git commands is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells me what Git can see or what is happening inside my repo. At first it told me that both the data and &lt;code&gt;README.md&lt;/code&gt; were  untracked files meaning that Git had not been told to include them in the project history or to commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Staging the Files
&lt;/h3&gt;

&lt;p&gt;To stage both files I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dot tells git to add everything in the current directory.&lt;br&gt;
I then checked the status again using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The files appeared under the changes to be committed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Creating My First Commit
&lt;/h3&gt;

&lt;p&gt;I then created my first commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add Kenya Health Record Analysis"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-m&lt;/code&gt; allows me to provide a message that explains what I changed.&lt;br&gt;
Hence a commit message can explain what happened at different points in time in the project's history if written clearly.&lt;br&gt;
I then ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This retrieved my unique commit ID and my commit message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Creating a GitHub Repository
&lt;/h3&gt;

&lt;p&gt;After creating the project locally, I went to GitHub and created a new repository and named it the same way I had in my File Explorer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kenya_Health_Records_Analysis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would become an online version of my local Git repository. I also learnt that even though I created the repo and named it the same way,it does not automatically upload my local files.&lt;br&gt;
I still needed to connect my local repo to the GitHub repo and &lt;strong&gt;push&lt;/strong&gt; the changes and this where an SSH Key comes in.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 7: Defining an SSH Key
&lt;/h3&gt;

&lt;p&gt;To me, it sounded like such a complex tech term but it was actually just a simple concept.&lt;br&gt;
&lt;strong&gt;SSH(Secure Shell)&lt;/strong&gt; provides a secure way for my PC to connect with my GitHub account.&lt;br&gt;
So after creating the repo on GitHub I was given two link options to connect to it;&lt;code&gt;HTTPS&lt;/code&gt; and &lt;code&gt;SSH&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 8: Connecting my Local Repository to GitHub
&lt;/h3&gt;

&lt;p&gt;Since I then had both my local Git and GitHub respositories, I needed to connect them using a &lt;strong&gt;remote&lt;/strong&gt;.&lt;br&gt;
A &lt;strong&gt;remote&lt;/strong&gt; is a reference to another repository hosted online.&lt;br&gt;
I then copied the SSH key for my GitHub repository and ran this in Git:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add origin git@github.com:SMumbi5144/Kenya_Health_Analysis.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;origin&lt;/code&gt; is the name given to the remote repository.&lt;br&gt;
The SSH address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git@github.com:SMumbi5144/Kenya_Health_Records_Analysis.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;tells Git where the remote repo is.&lt;br&gt;
To check if the two repos had connected I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 9: Pushing the Project to GitHub
&lt;/h3&gt;

&lt;p&gt;Once I had confirmed the two had connected, I pushed my local repo to GitHub by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;git push&lt;/code&gt; - tells Git to upload my commits to a remote repository.&lt;br&gt;
&lt;code&gt;origin&lt;/code&gt; - refers to the GitHub repository I had added as my remote.&lt;br&gt;
&lt;code&gt;-u&lt;/code&gt; - sets an upstream relationship between my local &lt;code&gt;main&lt;/code&gt; branch and the remote &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 10: Seeing My Project on GitHub
&lt;/h3&gt;

&lt;p&gt;This was the most exciting part of the process. For a beginner like me, it was quite the journey.&lt;br&gt;
I refreshed my GitHub and I could then see my local project files online.&lt;br&gt;
I could therefore view the project online,share it with others and continue working on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I learnt to Avoid
&lt;/h3&gt;

&lt;p&gt;We all make mistakes as we learn and this project was no exception.&lt;br&gt;
Therefore, in order to successfully upload my local files to my GitHub repository I learnt that I should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Not forget to initialize Git using &lt;code&gt;git init&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Not forget to stage files using &lt;code&gt;git add .&lt;/code&gt; else any changes I make will not be part of my next commit.&lt;/li&gt;
&lt;li&gt;Never assume commit means upload, to send to GitHub I ought to use &lt;code&gt;git push&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Avoid using unclear commit messages since they will not help me understand the project history easily.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;My first project taught me more than just a few commands. It taught me patience and the importance of paying attention to detail and being systematic since a command will only work efficiently if the correct  command is used. These are very important qualities for a data professional to develop so as to enhance the quality of their work.&lt;/p&gt;

&lt;p&gt;I also learnt some cool concepts such as how a version control system works, how an SSH Key can connect my PC to GitHub and  how I can manage and share my projects. &lt;/p&gt;

&lt;p&gt;As I continue developing my skills at and outside LuxDev Academy, GitHub will help me document my projects and build a portfolio that shows what I can do.&lt;/p&gt;

&lt;p&gt;This first project was the beginning of my journey towards becoming a better data professional.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>git</category>
      <category>github</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
