<?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: Denis Ndiritu</title>
    <description>The latest articles on DEV Community by Denis Ndiritu (@sir_masha_g).</description>
    <link>https://dev.to/sir_masha_g</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%2F4071756%2F9e8394bf-5234-420e-8c28-b78440adc810.png</url>
      <title>DEV Community: Denis Ndiritu</title>
      <link>https://dev.to/sir_masha_g</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sir_masha_g"/>
    <language>en</language>
    <item>
      <title>From Raw Data to Business Decisions: Building a Power BI Solution for JCars Logistics</title>
      <dc:creator>Denis Ndiritu</dc:creator>
      <pubDate>Sat, 26 Sep 2026 13:40:44 +0000</pubDate>
      <link>https://dev.to/sir_masha_g/from-raw-data-to-business-decisions-building-a-power-bi-solution-for-jcars-logistics-3d8h</link>
      <guid>https://dev.to/sir_masha_g/from-raw-data-to-business-decisions-building-a-power-bi-solution-for-jcars-logistics-3d8h</guid>
      <description>&lt;p&gt;JCars Logistics imports, sells, and delivers vehicles across regions in Kenya. I was handed a single raw flat file - 32 columns, 277 rows - describing sales orders, customers, vehicles, branches, payments, deliveries, logistics costs, returns, cancellations, and customer experience. The task: turn it into a reliable, interactive Power BI solution that helps management actually understand how the business is performing.&lt;/p&gt;

&lt;p&gt;No cleaning had been done. Nothing was standardized. That was the point - the assessment was as much about finding the problems as fixing them.&lt;/p&gt;

&lt;p&gt;This article walks through that journey: investigation, cleaning, modelling, DAX, dashboard design, and what I found along the way.&lt;/p&gt;

&lt;p&gt;Step 1: Understanding the Data Before Touching It&lt;/p&gt;

&lt;p&gt;Before writing a single transformation, I established the grain: one row = one vehicle sales order, identified by Order Id. The columns broke down into four natural groups - order/transaction details, customer details, vehicle details, and location/branch details. That grouping is what eventually became the star schema (more on that later).&lt;/p&gt;

&lt;p&gt;Step 2: The Data Quality Audit&lt;/p&gt;

&lt;p&gt;This dataset earned its "raw" label. A few of the more interesting problems:&lt;/p&gt;

&lt;p&gt;Order IDs weren't really IDs. They arrived with inconsistent prefixes (LC, LCL-, ORD, plain numbers), some blank, some N/A, and - worse - several duplicated across completely unrelated rows. I rebuilt the column entirely using an incremental index (starting at 1000, prefixed ORD-), landing on 276 clean, unique order identifiers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Added Index" = Table.AddIndexColumn(#"Removed Top Rows", "Index", 1000, 1, Int64.Type)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#"Inserted Prefix" = Table.AddColumn(#"Added Index", "Order Id", each "ORD-" &amp;amp; Text.From([Index]), type text),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dates were a mess of formats. Order Date and Delivery Date mixed Excel serial numbers, multiple locales (en-US vs en-GB), plain-text errors like #DATE!, and outright invalid dates (2026-13-04, 31/02/2026). I built a try...otherwise parsing chain that attempts each known format in sequence and falls back to null only when nothing matches - rather than guessing.&lt;/p&gt;

&lt;p&gt;Branches hid behind 64 different labels. Yards, HQs, city names, and abbreviations were all technically "the same place" under different labels. I cross-referenced the Sales Rep assignments - reps listed under "Thika," "Thika Yard," and "Thika Branch" turned out to be the exact same people - which confirmed these were naming variants of 8 actual branches, not distinct locations.&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%2F4oxsho4oycyw7qogi7vu.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%2F4oxsho4oycyw7qogi7vu.png" alt="Final Branch Value Distribution" width="798" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A typo pattern nobody would catch by eye. Several Sales Rep names had the number 1 substituted for the letter I (e.g., At1eno instead of Atieno) - likely a font/OCR-style substitution upstream. Combined with double-spaced names creating false duplicates, the rep list initially showed 20 "distinct" values that were really only 10 people. The code block below shows how the cleanup for the column was done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CleanSalesRep = (raw as nullable text) as nullable text =&amp;gt;
        let
            v0 = Text.Trim(Text.Clean(raw ?? "")),
            v1 = Text.Replace(v0, "1", "i"),      
            v2 = Text.Proper(v1),
            v3 = Text.Replace(v2, "  ", " "),
            v4 = Text.Trim(v3)
    in
        if v4 = null or v4 = "" then "Unknown"
        else if v4 = "Mercy" then "Mercy Atieno"
        else if v4 = "Kevin" then "Kevin Mwangi"
        else if v4 = "Grace" then "Grace Njeri"
        else if v4 = "Mary" then "Mary Wanjiku"
        else if v4 = "Peter" then "Peter Kiptoo"
        else if v4 = "Faith" then "Faith Achieng"
        else if v4 = "Daniel" then "Daniel Kimani"
        else if v4 = "Aisha" then "Aisha Mohamed"
        else if v4 = "Brian" then "Brian Otieno"
        else if v4 = "Samuel" then "Samuel Mutua"
        else v4,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Discounts exceeding 100%. A handful of rows showed discount values like 1.2, which could mean 120% (a data error) or a misplaced decimal meant to be 12%. Rather than guess - either interpretation could be wrong, and guessing wrong is worse than leaving it blank - these were nullified and flagged for follow-up with the data source, rather than silently "corrected" into a number that might be equally incorrect.&lt;/p&gt;

&lt;p&gt;Suspicious customer ages. The value 121 appeared three times, and -5 appeared three times too - clear signs of placeholder or default values rather than real ages. Since there was no date-of-birth field to cross-check against, these (along with 0) were treated as invalid and nullified rather than assumed.&lt;/p&gt;

&lt;p&gt;Step 3: Standardizing Currency&lt;/p&gt;

&lt;p&gt;Monetary columns (Unit Selling Price, Unit Cost, Discount, Delivery Fee, Logistics Cost, Revenue Recorded) arrived as text, mixing four currencies - KES, USD, EUR, ZAR - identified inconsistently by prefixes (Ksh, $, €, R) and magnitude suffixes (K for thousand, M for million).&lt;/p&gt;

&lt;p&gt;Any value with no explicit currency marker was assumed to be KES. Everything else was converted using one consistent exchange rate set applied across the whole project:&lt;/p&gt;

&lt;p&gt;Currency    Rate to KES&lt;br&gt;
USD 129.50&lt;br&gt;
EUR 135.50&lt;br&gt;
ZAR 7.10&lt;/p&gt;

&lt;p&gt;_Source: &lt;a href="https://www.investing.com/currencies" rel="noopener noreferrer"&gt;https://www.investing.com/currencies&lt;/a&gt; _&lt;/p&gt;

&lt;p&gt;Step 4: Cleaning in Power Query - and a Performance Lesson&lt;/p&gt;

&lt;p&gt;Each problematic column got its own dedicated M function - dates, categorical text, monetary values, discounts, ratings - rather than one-off inline fixes scattered everywhere.&lt;/p&gt;

&lt;p&gt;One mistake worth sharing: early on, I cleaned categorical columns (Region, County, Branch, Sales Rep, Lead Source, Car Make, Car Model) using long chains of Table.ReplaceValue steps - one per misspelling. Each of those steps re-scans and rematerializes the entire table, which meant the query got progressively slower as more steps piled up.&lt;/p&gt;

&lt;p&gt;The fix was switching to a single Table.TransformColumns call per column, with the mapping logic expressed as one if...then...else if chain inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;powerquery
#"Cleaned Region" = Table.TransformColumns(#"Previous Step", {
    {"Region", each
        let v = Text.Proper(Text.Trim(_)) in
        if v = "Nbi" or v = "Nrb" or v = "Nairobii" then "Nairobi"
        else if v = "Rift" or v = "Rift-Valley" then "Rift Valley"
        else if v = "Msa Region" or v = "Cost" then "Coast"
        else if v = null or v = "" then null
        else v
    , type text}
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same result, a fraction of the applied steps, and a noticeably faster refresh.&lt;/p&gt;

&lt;p&gt;Step 5: From Flat File to Star Schema&lt;/p&gt;

&lt;p&gt;A flat table repeats every customer's, vehicle's, and branch's details on every single transaction row - that's redundant, harder to filter efficiently, and makes relationships harder to express. So the cleaned data was restructured into a star schema:&lt;/p&gt;

&lt;p&gt;Fact_Sales - one row per order, holding the measures and foreign keys&lt;br&gt;
Dim_Vehicle - Car Make, Car Model, Vehicle Type, Vehicle Year, Fuel Type, Transmission, Color&lt;br&gt;
Dim_Customer - Customer Name, Customer Type, Customer Age&lt;br&gt;
Dim_Branch - Region, County, City, Branch&lt;br&gt;
Dim_SalesRep - Sales Rep&lt;br&gt;
Dim_Date - a DAX-generated calendar table&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%2F5j7hxng6gyc0mgsr2q3t.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%2F5j7hxng6gyc0mgsr2q3t.png" alt="Jcars Data Model View" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two modelling decisions worth explaining:&lt;/p&gt;

&lt;p&gt;Why Customer Age lives in Dim_Customer, not Fact_Sales. Since there's no true Customer ID in the source data, Name + Type + Age was used as a proxy identity key for deduplication. This is an honest limitation, not a hidden one - two different customers sharing all three attributes would incorrectly merge into one customer record. Worth flagging to management if customer-level analysis becomes more important later.&lt;/p&gt;

&lt;p&gt;Why some fields stayed in the fact table. Lead Source, Payment Method, Payment Status, Delivery Status, Returned, Customer Rating, and Review Count describe the transaction, not a reusable entity - splitting them into tiny standalone dimensions would add joins with no analytical payoff.&lt;/p&gt;

&lt;p&gt;Building the fact table meant merging each dimension's descriptive columns back in as a lookup and keeping only the surrogate key. The one gotcha that cost some debugging time: Power Query's merge treats null = null as a non-match. If a descriptive column had blanks on both the fact and dimension side, that merge would silently fail for those rows. The fix was ensuring consistent non-null placeholders (e.g., "Unknown") flowed through from the cleaning stage, and spot-checking each merge with a temporary Table.RowCount() column before trusting it.&lt;/p&gt;

&lt;p&gt;Step 6: DAX Measures&lt;/p&gt;

&lt;p&gt;With a proper model in place, measures could finally express real business logic instead of relying on default aggregations. A sample:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dax
Total Revenue (Calculated) = 
SUMX(Fact_Sales, Fact_Sales[Units Sold] * Fact_Sales[Unit Selling Price] * (1 - Fact_Sales[Discount]))

Revenue Variance = [Total Revenue (Calculated)] - [Total Revenue (Recorded)]

Gross Profit Margin % = DIVIDE([Gross Profit], [Total Revenue (Recorded)])

Return Rate = 
DIVIDE(
    CALCULATE(DISTINCTCOUNT(Fact_Sales[Order Id]), Fact_Sales[Returned] = "Yes"),
    [Total Orders]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Revenue Variance is doing double duty as a validation check - comparing the recorded revenue against an independently calculated figure lets discrepancies surface naturally instead of blindly trusting one number.&lt;/p&gt;

&lt;p&gt;Step 7: The Executive Dashboard&lt;/p&gt;

&lt;p&gt;Page 1 had one job: let a manager understand "how is the business doing?" in under a minute, without needing anything explained.&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%2Fajv5noao22vsdp4vpbyf.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%2Fajv5noao22vsdp4vpbyf.png" alt="Executive Dashboard" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's organized into five zones - KPI cards up top (Revenue, Units, Gross Profit, Margin, Orders), a chronological revenue trend line, Top-10 bar charts for Branches and Car Makes, a regional revenue map, and a payment-status breakdown by value.&lt;/p&gt;

&lt;p&gt;One small addition made a disproportionate difference: a conditionally-formatted Return Rate card - green under 30%, red above. It sounds trivial, but it turned into a genuine debugging lesson: even though the card displays as a percentage, Power BI's conditional formatting engine evaluates the underlying decimal (0.3), not the display value (30). My first attempt used whole-number thresholds (30 instead of 0.3), which meant the "red" rule was mathematically impossible to trigger and the "green" rule matched everything. The card looked "done" and was quietly wrong the entire time. Worth double-checking on any rate-based conditional formatting, not just this one.&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%2Fd9n0ethaseawpmpj0d2n.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%2Fd9n0ethaseawpmpj0d2n.png" alt="Return Rate" width="229" height="132"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 8: What I Found - Key Insights&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The return rate is unusually high overall with BMW standing out sharply. 32% of all orders were returned. Nakuru Branch leads (16 of 33 orders). Whether it is a problem with Nakuru, it is an issue that needs investigation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Digital lead sources bring high-value customers than manual ones. Instagram orders average Kes 6.5 million and Facebook Kes 5.9 million compared to Walk-Ins at Kes 3.1 million. This suggests marketing spend on social channels may be attracting a meaningfully higher-spending customers segment, worth validating with a large sample before reallocating budget on it alone.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customer ratings and revenue are unrelated. The correlation between Customer Rating and Revenue Recorded is -0.02. Happier customers aren't spending more, and higher-value customers aren't necessarily happier. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recommendations for Management&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Open a formal quality investigation into Nakuru Branch operations. The return rate at Nakuru Branch is at 48.5%, and highest of any branch. Conduct an audit into the delivery handling and customer communication&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reassess how marketing spend is allocated across lead sources. Since our analysis shows social media sourced orders are higher compared against methods such as walk-ins, testing could be done to assess a shift towards social channels,and could be done over a long period before a permanent reallocation is done.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Audit and correct the pricing model for Toyota. Toyota is the highest revenue make with around 560 million (0.45% margin), while Subaru, returns a 6.96 % margin. Management should investigate whether the current selling prices cover the true cost to deliver.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Closing Thoughts&lt;/p&gt;

&lt;p&gt;The hardest part of this project wasn't the DAX or the visuals - it was resisting the urge to "fix" ambiguous data by guessing. Nullifying an unclear value and documenting why is a more honest analytical decision than quietly inventing a number that looks plausible. That discipline - document the assumption, apply it consistently, and let management know where the data itself sets the limit - is the difference between a dashboard that looks finished and one that's actually trustworthy.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Presenting, Linking and Presenting Data in Power BI</title>
      <dc:creator>Denis Ndiritu</dc:creator>
      <pubDate>Tue, 15 Sep 2026 05:34:04 +0000</pubDate>
      <link>https://dev.to/sir_masha_g/presenting-linking-and-presenting-data-in-power-bi-165i</link>
      <guid>https://dev.to/sir_masha_g/presenting-linking-and-presenting-data-in-power-bi-165i</guid>
      <description>&lt;p&gt;As a data analyst, you are presented with data that can span from a single sheet with a few thousand rows, to a full worksheet with sheets, that have thousands and thousands of rows. Microsoft Excel will properly handle the single sheet effortlessly, allowing you to clean this data, and even present it using the available charts provided for you. However, when you have the complex data, Microsoft Excel might not be the best tool to analyze this data. First, you will need something that is efficient in terms of processing this complex data, present your data in a more, efficient manner, possibly have it in a few separate but linked tables, and provide a better manner to scale your data. This is where Power BI comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Power BI?
&lt;/h2&gt;

&lt;p&gt;Power BI is a business analytics and data visualization platform provided by Microsoft, that turns raw, scattered data into interactive, easy-to-understand charts and dashboards. Power BI, can be used to connect data from over 100 data sources, including Excel spreadshets, SQL databases, cloud services, etc. In this article, we look at three aspects of Power BI that are central to how data is connected: data modelling, relationships, and joins.&lt;/p&gt;

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

&lt;p&gt;Data modelling is the process of structuring and organizing, and connecting data so that it can be analyzed correctly and efficiently. It involves creating relationships between tables, knowing which table holds what information, and deciding how the tables will connect to one another. A well designed data model matters more than tidiness: it directly affects how fast reports run, how simple of complex the DAX calculations become, how well the model scales as data grows, and how easy it is for someone or you as the author to maintain.&lt;/p&gt;

&lt;p&gt;Data Modelling comes in different approaches, each with its own place.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Flat Table&lt;/strong&gt;: Flat table in data modelling, also called one big table (OBT), is a data modelling approach where all transactional data and descriptive attributes are combined into a single, denormalized table. Instead of having data separated into multiple connected tables, every column will reside in one place. &lt;br&gt;
At a glance, this is simple to read. However, it comes with real costs:there is massive data redundancy (the same customer details repeat on every row), update anomalies (if a customer changes their email, every one of their historical rows must be updates), and an inability to filter and aggregate cleanly, since the tabes mixes several different grains at once - a single row is simultaneously describing and order, a customer, and a product.&lt;br&gt;
A flat table is appropriate only for small, one-off, or throwaway analyses - a quick ad hoc check, or data that already arrives denormalized and will not be reused. For any report that will grow, refresh regularly, or need ore than one grain of analysis, a flat table works against Power BI development best practices, which favor a star schema layout.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Star Schema Layout&lt;/strong&gt;: A star schema, the recommended data modelling technique in Power BI, is a technique, where a central fact table connects to multiple dimensions table in a star-like structure. It's core components include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fact Tables&lt;/strong&gt;: Fact tables sit at the centre and store quantitative or numerical transactionsl data (e.g sales amounts, quantitis, revenue) alongside foreign keys that point out to each dimension.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dimension Tables&lt;/strong&gt;: They surround the fact table and hold descriptive attributes e.g. product names, customer details, geography, and date, which provide context for filtering and grouping. Each dimension table contains a key column (or columns) that uniquely identifies each row, plus supporting descriptive columns.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dimension tables generally hold a relatively small number of rows. Fact tables, on the other hand, can contain a large number of rows and continue to grow over time.&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%2Fck9jqy4k8183kd7rafmi.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%2Fck9jqy4k8183kd7rafmi.png" alt="Star Schema - FactOrderDetails connects one hop to each surrounding dimension." width="543" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Star Schema is preferred in Power BI for several reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Faster Performance&lt;/strong&gt; - There are fewer joins for the engine to resolve, since every dimension is a single hop from the fact table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simpler DAX&lt;/strong&gt; - Star schema makes Data Analytics Expressions (DAX) calculations cleaner, more predictable, and less prone to error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less Redundancy&lt;/strong&gt; - The star schema stores descriptive text once in dimension tables rather than repeating it across rows in transaction logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-to-Many Relationships&lt;/strong&gt; - The relationships connect the "one" side (dimension table) to the "many" side (fact table) with filters flowing strictly from dimensions to facts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Even so, a star schema is not entirely free of trade-offs. Each dimension carries a small amount of denormalization of its own - for instance, a product's category name is stored directly on the product row rather than in a separate table - which is a deliberate compromise made in exchange for speed and simplicity, and is quite different from the redundancy problem a flat table has. A star schema also assumes the business process is reasonably well understood upfront, since the fact table's grain has to be decided early and is expensive to change later.&lt;br&gt;
A star schema is appropriate for the large majority of Power BI reporting models. It is the default recommendation for new projects, unless there is a specific reason - usually a very large, shared, hierarchical dimension - to normalize further.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Snow Flake Schema: A snowflake scheme takes a star schema one step further, where some dimension tables are normalized into sub-dimensions, E.g instead of a DimProduct holding the category name directly, that column is split out into a separate DimCategory table, and DimProduct links to it instead.&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%2Fozhmnx5uis36wiic6vf0.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%2Fozhmnx5uis36wiic6vf0.png" alt="Snowflake schema - DimCategory is normalied out of DimProduct, adding a second relationship hop." width="725" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While normalization in a snowflake model is high, it comes with disadvantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Power BI loads more tables, which is less efficient from a storage and performance perspective.&lt;/li&gt;
&lt;li&gt;Longer relationship filter propagation chains need to be traveresed, and this might be less efficient that filters applied to a single table.&lt;/li&gt;
&lt;li&gt;The Data pane presents more model tables to report authors, which can result in a less intuitive experience, especially when snowflake dimension tables contain only one or two columns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A snowflake schema is appropriate when a dimension is large, genuinely hierarchical, and reused by more than one fact table - enough that the storage saved by normalizing it outweighs the cost of the extra relationship hop. Outside of that specific case, it is usually better to flatten the dimension back into a star using Power Query before loading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fact Tables and Dimenstion Tables
&lt;/h2&gt;

&lt;p&gt;Fact and dimension tables were introduced briefly above, but the distinction deserves a closer look on its own, since almost every modelling decision in Power BI comes back to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fact table&lt;/strong&gt; - Stores the measurable business events - things that happened, with numbers attached. Its rows are typically numerous, and its numeric columns are measures: values meant to be summed, averaged, or counted, such as Quantity, UnitPrice, Discount, or Amount. Alongside these measures, a fact table holds foreign keys pointing out to each relevant dimension. Common examples include FactSales, FactOrders, and FactTransactions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dimension table&lt;/strong&gt; - Stores the descriptive attributes used to slice, filter, and label the facts - the “who, what, where, and when” of a business event. Its rows are comparatively few, and it is identified by a primary key. Typical examples are DimCustomer, DimProduct, DimDate, and DimLocation.&lt;/p&gt;

&lt;p&gt;The difference between a measure and an attribute matters here: a measure produces a meaningful result when aggregated - SUM(Quantity) makes sense - while an attribute is a label used to group or filter (summing a CustomerID, or averaging a City name, is meaningless). This is why fact tables tend to be "tall and narrow" - few columns, many rows - while dimension tables are "wide and short" - many descriptive columns, fewer rows.&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%2Fjw25f0tui3a3ru8jnm6d.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%2Fjw25f0tui3a3ru8jnm6d.png" alt="A central fct table connected to four dimensions, each contributing its primary key as a foreign key in the fact table." width="525" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;When discussing data models, we slightly mentioned relationships.&lt;/p&gt;

&lt;p&gt;A Relationship connect two or more tables using a shared column or key so that reports can filter and aggregate data correctly across them. Without a relationship, tables sit in the model completely isolated from one another. &lt;br&gt;
Some of the key terms used in relationships include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary key(PK):&lt;/strong&gt; This is a column in a table that uniquely identifies each row, with no duplicates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foreign key(FK):&lt;/strong&gt; This is a column in another table that refers to the primary key described above. They can also repeat in a table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cardinality:&lt;/strong&gt; Whether "one" side and "many" side columns contain unique values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Referential Integrity:&lt;/strong&gt; Ensures that every foreign key value in the fact table should exist in the dimension's Primary key column. Orphaned keys referencing a key not existing in the dimension table shows up as a blank/unknown member in visuals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active and Inactive Relationships:&lt;/strong&gt; An active relationship in Power BI is the default path used automatically for filtering and calculations, while an inactive relationship is ignored until explicitly activated using DAX.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly why, for example, CustomerID is unique in DimCustomer. Each customer appears exactly once, but the same CustomerID repeats many times in FactSales, once for every order that customer has places. The dimenstion describes the customer once, while the fact table will record every even that customer was involved in.&lt;/p&gt;

&lt;p&gt;Let's now look at the types of relationships that apply in PowerBI:&lt;/p&gt;

&lt;h2&gt;
  
  
  Types of relationships
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One-to-many(1:*)&lt;/strong&gt; - In this relationship, one row in the dimension relates to many rows in the fact. It is used whenever a dimension describes many fact events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-to-one(1:1)&lt;/strong&gt; - Each row in one table matches exactly one row in the other, both sides being unique. A proper example is with an employee table and and employe badge table, one badge per employee. It is however rare, and indicates that the two tables should simply be merged into one, since they carry no extra "many" value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Many-to-many(* : *)&lt;/strong&gt; - In this relationship, neither side is unique, e.g. a student table and a course table where each student takes many courses and each course has many students. This relationship is supported natively by Power BI via a shared column with duplicates on both sides, but it should be used cautiously as it can produce ambiguous or unexpected duplicate results. The remedy is usually to introduce proper bridge/junction tables that turns it into two clean one-to-many relationships instead.&lt;/li&gt;
&lt;/ol&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%2Fh1884pxj967gj4l691fd.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%2Fh1884pxj967gj4l691fd.png" alt="The three relationship cardinalities. Only 1:many gives an unambiguous single filter path by default." width="700" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As much as relationships have been established, we need to understand that they are not just connections. They also define which way filters travel. In power BI, filters will travel in two ways, which we will discuss below.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Single Direction&lt;/strong&gt; - This is the default filter direction for  1:many relationships. Filterig the "one" side (dimension) filters the "many" side(fact), but not the reverse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Both/bidirectional&lt;/strong&gt;: Filters flow both ways. Selecting a product in a dimension table filters the fact table, and filering the fact table can filter back and affect the visible rows in the dimension table.&lt;/li&gt;
&lt;/ol&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%2F6jtiewmks85n41d6unma.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%2F6jtiewmks85n41d6unma.png" alt="Single-direction filtering versus bidirectional filtering between the same two tables." width="697" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;A join physically combined rows from tables in Power Query, based on matching key columns, before the data ever gets loaded into the model. Joins are performed using the &lt;strong&gt;Merge Queries&lt;/strong&gt; feature to combine two tables. The following are the joins we have in Power Query:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Left Outer Join:&lt;/strong&gt; This join keeps all rows from the first (left) table and matching rows from the second (right) table. Unmatched rows show as null.&lt;/li&gt;
&lt;li&gt;Right Outer Join: Keeps all rows from the second (right) table, and matching rows from the first (left) table.&lt;/li&gt;
&lt;li&gt;Full Outer Join: This join returns all rows from both tables, matching or not.&lt;/li&gt;
&lt;li&gt;Inner Join: This join returns only rows that have matching values in both tables.&lt;/li&gt;
&lt;li&gt;Left Anti-Join: Returns only the rows from the first(left) table that have no match in the second table.&lt;/li&gt;
&lt;li&gt;Right Anti-Join: Returns only the rows from the second (right) table that have no match in the first table.&lt;/li&gt;
&lt;/ol&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%2Fltg1vn7mgr0xuddbo6z4.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%2Fltg1vn7mgr0xuddbo6z4.png" alt="The six Power Query join tyes, shown as shaded regions of table T1 and table T2." width="800" height="625"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Source(&lt;a href="https://excelunplugged.com/2022/03/08/join-types-in-power-query-part-1-join-types/" rel="noopener noreferrer"&gt;Excel Unplugged&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;It is worth nothing the difference between merging tables in Power Query and creating relationships in the Power BI data model.&lt;br&gt;
&lt;strong&gt;Does a Power Query merge physically combine data?&lt;/strong&gt; Yes. A merge copies matching columns from the second table into the first, producing one wider, denormalied table. &lt;br&gt;
&lt;strong&gt;Does creating a relationship combine the tables?&lt;/strong&gt; No. The tables remain fully separate in teh model, each with its won rows and columns. A relationship is basically a live link used at query time to propagate filters, not a physical copy of data.&lt;br&gt;
&lt;strong&gt;At what stage does each happen?&lt;/strong&gt; Merges happen in the Power Query Editor, during the transform/ETL stage, before data is loaded. Relationships are created afterward, in Model view, nce the tables already exist in the model.&lt;br&gt;
&lt;strong&gt;When would you choose a merge instead of a relationship?&lt;/strong&gt; When a single flattened table is needed for a specific purpose e.g. exporting a denormalized extract, or resolving a snowflaked dimension back into its parent so the model does not need the extra relationship hop.&lt;br&gt;
&lt;strong&gt;How can excessive merging affect a model's structure?&lt;/strong&gt; Merging fact-level detail into dimenstions, or merging multiple fact tables together, recreated the flat-table problem discussed earlier: redundancy returns, file size grows, refreshes slow down, and the odel loses the single clean grain per table that made the star schema fast and prdicatable.&lt;br&gt;
&lt;strong&gt;Why keep the fact and dimension tables separate?&lt;/strong&gt; Separation preserves a single source of truth for every attribute, keeps the fact table narrow and fast to scan, and lets Power BI's relationship enginde do the aggregation work it is build for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Power BI Model
&lt;/h2&gt;

&lt;p&gt;Weighing everything discussed above, the recommended approach for a typical business intelligence project is a star schema, built with single-direction, one-to-many relationships flowing from each dimension into the fact table, with bidirectional filtering reserved only for specific, justified cases such as a many-to-many bridge table.&lt;/p&gt;

&lt;p&gt;This recommendation holds up against each of the factors that matter in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance - a star schema aligns with how Power BI's VertiPaq engine compresses and scans data; narrow, single-hop relationships resolve fastest.&lt;/li&gt;
&lt;li&gt;DAX simplicity - SUM, CALCULATE, and time-intelligence functions behave predictably when every dimension sits one hop from the fact table; both flat tables and snowflakes complicate this in different ways.&lt;/li&gt;
&lt;li&gt;Model readability - a star schema is visually obvious in Model view; the fact table and its surrounding dimensions are immediately clear to anyone opening the file.&lt;/li&gt;
&lt;li&gt;Scalability - adding a new dimension, such as DimPromotion, is a single new relationship, not a redesign of the whole model.&lt;/li&gt;
&lt;li&gt;Data redundancy - dimensions carry a small, deliberate amount of denormalization (like a flattened category name), a reasonable trade for speed, and nowhere near the repetition problem of a flat table.&lt;/li&gt;
&lt;li&gt;Maintainability - a clear separation between facts and dimensions makes future changes, such as renaming a column or adding an attribute, low-risk and localized to one table.&lt;/li&gt;
&lt;li&gt;Ease of reporting - report authors work with a small, well-labelled set of dimension fields to slice by, rather than searching through one enormous table.&lt;/li&gt;
&lt;li&gt;Filter propagation - single-direction relationships give unambiguous, predictable filtering, which becomes essential once a report has more than one or two slicers.&lt;/li&gt;
&lt;li&gt;Model complexity - a star schema keeps the number of relationship hops to one, which keeps the whole model easy to hold in your head.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A snowflake schema is only worth its added complexity when a dimension is genuinely large, hierarchical, and shared across multiple fact tables - enough that the storage and maintenance savings outweigh the extra relationship hop and DAX complexity it introduces. A flat table should be reserved for small, one-off analyses that will never need to scale. For everything else - which, in practice, is most Power BI projects - the star schema, with single-direction, one-to-many relationships, is the right default.&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>data</category>
      <category>microsoft</category>
    </item>
    <item>
      <title>Getting Started With Excel for Data Analytics: From Basics to Data Cleaning</title>
      <dc:creator>Denis Ndiritu</dc:creator>
      <pubDate>Tue, 01 Sep 2026 03:31:34 +0000</pubDate>
      <link>https://dev.to/sir_masha_g/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-560e</link>
      <guid>https://dev.to/sir_masha_g/getting-started-with-excel-for-data-analytics-from-basics-to-data-cleaning-560e</guid>
      <description>&lt;p&gt;In today's world, decisions are not based on intuition or guesses. They are not based on what one thinks is the right thing. If you own a business, you would like to make a decision based on certain trends. If you are a teacher, you may want to see the progress of a student over a certain period. This and more requires one key ingredient; data. This data is collected using various methods, over a long period of time, and you are able to analyze it to get meaningful information from it. As the name says, the final output, informs you on a decision you should make, based on the trends that your data has shown.&lt;/p&gt;

&lt;p&gt;The data, however, may not be &lt;strong&gt;clean&lt;/strong&gt;. The data can contain duplicates, extra spaces on certain values, blank rows and columns, wrong data types on values, inconsistent cases, and many more. Getting insights from such data may not give you accurate insights. This is where data cleaning comes in handy.&lt;/p&gt;

&lt;p&gt;You would get provided with a piece of data either in &lt;strong&gt;csv&lt;/strong&gt; or &lt;strong&gt;xlsx&lt;/strong&gt; format, and use Microsoft Excel to start the cleaning process. Let's dig deep into this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opening An Excel File
&lt;/h2&gt;

&lt;p&gt;First things first, we would want to open our data in Microsoft Excel. We also need to make sure that we have a copy of our raw data somewhere safe so that we can come to it for any references. To safely get the data from the excel file open Microsoft Excel and click &lt;strong&gt;Blank workbook&lt;/strong&gt;. This will open a new workbook with no information in it. If you had already opened it, then simply navigate to &lt;strong&gt;File&lt;/strong&gt; and click &lt;strong&gt;Blank workbook&lt;/strong&gt; to create a new workbook.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Data From our Raw File
&lt;/h2&gt;

&lt;p&gt;We now have our blank workbook. We now need to get our data into the workbook so that we can get started with the cleaning process. To do this, we will navigate to the &lt;strong&gt;Data&lt;/strong&gt; tab on our top bar menu. We shall then click the &lt;strong&gt;Get Data&lt;/strong&gt; button that has a cylinder+table icon. Once clicked, we get a few options. Microsoft provided a ton of options which you can choose to get your data from, depending on your source. You can get data from files e.g &lt;strong&gt;Excel Workbook&lt;/strong&gt;, &lt;strong&gt;Text/CSV&lt;/strong&gt;, &lt;strong&gt;XML&lt;/strong&gt;, &lt;strong&gt;JSON&lt;/strong&gt;, &lt;strong&gt;PDF&lt;/strong&gt;, &lt;strong&gt;Folder&lt;/strong&gt;, or &lt;strong&gt;SharePoint Folder&lt;/strong&gt;. You can even get data from &lt;strong&gt;Database&lt;/strong&gt;, &lt;strong&gt;Azure&lt;/strong&gt; etc.&lt;/p&gt;

&lt;p&gt;Once you identify you source e.g. CSV, simply select it. You will then get a window to navigate to where your raw data is located. Navigate to that location and select your data. Click the &lt;strong&gt;Open&lt;/strong&gt; button or double click your data source. This will then open a preview of the data inside the selected file, showing the encoding format of the file, the delimiter, and the data inside the file. Click the &lt;strong&gt;Load&lt;/strong&gt; button at the bottom of your preview window.&lt;/p&gt;

&lt;p&gt;This will now open your raw data inside a table. Note that this is now single worksheet that you have of your raw data. In our worksheet, we may want to duplicate our data so that we can separate it from the raw worksheet, and now what we shall clean. If you did the above steps properly, you would notice a tab at the right part of your window saying &lt;strong&gt;Queries &amp;amp; Connections&lt;/strong&gt;. What happened is that the &lt;strong&gt;Get Data&lt;/strong&gt; created a live connection to the external data source using an underlying query. When we click on this query, we are taken to the &lt;strong&gt;Power Query Editor&lt;/strong&gt; where we can now make certain changes. These changes are structured as steps which are recorded and can be undone. The changes do not touch your worksheet until you &lt;strong&gt;Close &amp;amp; Load&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Should One Use Power Query Over Normal Excel?
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Power Query Editor&lt;/strong&gt; is preferred over traditional Excel the moment that your data cleaning would need automation, has grown in terms of volume, or needs to have steps reproducible. This enhances visibility of steps done on your data, which can also be repeated over and over again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying Data Types in Excel
&lt;/h2&gt;

&lt;p&gt;An excel file can have as low as one column and as many columns as possible. Each column holds information, which has been stored in a certain data type. It is important that you ensure that each column has consistent data type depending on what the column is. &lt;/p&gt;

&lt;p&gt;A data type is a classification that specifies which type of value a field or variable can hold. Excel recognizes the following data types in cells: &lt;strong&gt;Text&lt;/strong&gt;, &lt;strong&gt;Number&lt;/strong&gt;, &lt;strong&gt;Dates&lt;/strong&gt;, &lt;strong&gt;Times&lt;/strong&gt;, &lt;strong&gt;Logical (Boolean) values&lt;/strong&gt;, and &lt;strong&gt;Errors&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When cleaning your data, it is therefore important to ensure that each column has a consistent data type across its cells. Cleaning up data is very simple. Simply select the column you would like to specify its data type. In the &lt;strong&gt;Home&lt;/strong&gt; tab, in the &lt;strong&gt;Number&lt;/strong&gt; menu, specify the data type. Repeat the steps for all the other columns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Similar Values in a Column, Duplicates or Not?
&lt;/h2&gt;

&lt;p&gt;When cleaning our data, we mentioned that we may have values that repeat themselves. At times, this might be erroneous, while some may have repetitive values, but values in the subsequent columns be different, which might change how we handle the duplicate values.&lt;/p&gt;

&lt;p&gt;For example, if we were checking for duplicates on a column such as a product name, and the product had batch numbers, it would not be a surprise when we have repeating product names, but different batch numbers. This would suggest that we have variations of our product, due to the batch number. In such a case, we would not remove the duplicate product. However, if the batch number was the same across the same product, this would highly suggest that some of the records are duplicates, which would necessitate us to remove one record, and remain with a single non-duplicate record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Formatting Data
&lt;/h2&gt;

&lt;p&gt;We had already started formatting our data but had not gone through other methods of formatting our data. In the &lt;strong&gt;Power Query Editor&lt;/strong&gt;, one can format columns as they would wish to. Some options provided are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;lowercase&lt;/strong&gt; -&amp;gt; Normalizes the selected column to have all its values as lowercase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UPPERCASE&lt;/strong&gt; -&amp;gt; Normalizes the selected column to have its values as upper case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capitalize Each Word&lt;/strong&gt; -&amp;gt; Capitalizes the first letter of each word in each cell in the selected column.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trim&lt;/strong&gt; -&amp;gt; Removes leading and trailing whitespaces in each cell of the selected column.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean&lt;/strong&gt; -&amp;gt; This will remove all non-printable characters in each cell of the selected column.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add Prefix&lt;/strong&gt; -&amp;gt; This will add a text that you will specify and will be appended before each value in the cells of the column you have selected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add Suffix&lt;/strong&gt; -&amp;gt; This will add a text that you will specify and will be appended after each value in the cells of the column you have selected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are some of the ways you can manipulate your text values in Excel to have consistency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sorting and Filtering
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sorting
&lt;/h3&gt;

&lt;p&gt;When cleaning your data, you may want it to appear in a certain order. You may want the first column to be sorted in ascending order. You may also want to combine sorting so that your data is arranged based on more than one column. This is where sorting comes in. Sorting does not add or remove any data. It just changes how they order themselves to allow one to see patterns, trends or even outliers. Some of the methods of sorting include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Alphabetical (A to Z or Z to A&lt;/strong&gt; -&amp;gt; This sorting method is used for text columns e.g. product names, or employee names.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Numerical (Smallest to Largest or Largest to Smallest)&lt;/strong&gt; -&amp;gt; This is used for financial or quantity data and can be used for cases such as getting the lowest prices, finding the product with the highest quantity etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chronological (Oldest to Newest or Newest to Oldest&lt;/strong&gt; -&amp;gt; This can used to track dates e.g. oldest student in a class, the nearest deadline etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Level Sorting&lt;/strong&gt; -&amp;gt; This kind of sorting allows one to sort data by more than one column at a time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Filtering
&lt;/h3&gt;

&lt;p&gt;You may want to see data based on specific criteria. This is made possible by &lt;strong&gt;Microsoft Excel&lt;/strong&gt; using the magic of &lt;strong&gt;Filters&lt;/strong&gt;. Filters allows you to focus on what you need, while temporarily hiding the rows that don't meet the criteria specified. You can always get the full data back by clearing your filter. Some of the filter methods include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Checkbox Filtering&lt;/strong&gt; -&amp;gt; The filter allows you to just check or uncheck boxes. Rows with the unchecked values will be filtered out, remaining with what has been checked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text Filtering&lt;/strong&gt; -&amp;gt; The text filters allow one to search for values based on criteria such as &lt;strong&gt;Equals&lt;/strong&gt;, &lt;strong&gt;Does Not Equal&lt;/strong&gt;, &lt;strong&gt;Begins With&lt;/strong&gt;, &lt;strong&gt;Ends With&lt;/strong&gt;, &lt;strong&gt;Contains&lt;/strong&gt;, and &lt;strong&gt;Does Not Contain&lt;/strong&gt;. This will also provide you with a custom filter to create your own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Number Filtering&lt;/strong&gt; -&amp;gt; This allows you to filter numbers according to criteria such as &lt;strong&gt;Equals&lt;/strong&gt;, &lt;strong&gt;Does Not Equal&lt;/strong&gt;, &lt;strong&gt;Greater Than&lt;/strong&gt;, &lt;strong&gt;Greater Than Or Equal To&lt;/strong&gt;, &lt;strong&gt;Less Than&lt;/strong&gt;, &lt;strong&gt;Less Than Or Equal To&lt;/strong&gt;, &lt;strong&gt;Between&lt;/strong&gt;, &lt;strong&gt;Top 10&lt;/strong&gt;, &lt;strong&gt;Above Average&lt;/strong&gt;, and &lt;strong&gt;Below Average&lt;/strong&gt;. You can also create custom filters just like with the text filters.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Functions
&lt;/h2&gt;

&lt;p&gt;We have cleaned our data, we have sorted it, and we have also filtered. We would want to have a bit of insights now. To do this, we need to use the functions provided by Microsoft Excel.&lt;/p&gt;

&lt;p&gt;Instead of rearranging, we will now use functions to analyze our data. In this article, we shall talk about statistical functions and date functions offered in excel to help in analyzing data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Statistical Functions
&lt;/h3&gt;

&lt;p&gt;Statistical functions allow you to get a single value (&lt;strong&gt;metric&lt;/strong&gt;) from a range of data points. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MIN&lt;/strong&gt; and &lt;strong&gt;MAX&lt;/strong&gt; -&amp;gt; The two functions help you get the lowest and maximum values in a range respectively. You can get, for example, the highest salary given to your employees, or the lowest age among your staff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AVERAGE&lt;/strong&gt; -&amp;gt; This function will add up all selected values and divide by the total count.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MEDIAN&lt;/strong&gt; -&amp;gt; Median is used to identify the exact middle number in a sorted list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MODE&lt;/strong&gt; -&amp;gt; The Mode function allows you to find the value that appears the most in your dataset.
### Date Functions
Date functions are important when used in a dataset, as they can help you extract and analyze your data by time periods. For example:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YEAR&lt;/strong&gt; -&amp;gt; The &lt;strong&gt;YEAR&lt;/strong&gt; function extracts the four-digit year from a full date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MONTH&lt;/strong&gt; -&amp;gt; The &lt;strong&gt;MONTH&lt;/strong&gt; function pulls the month from a full date, returning a value from 1 (January) to 12 (December).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DAY&lt;/strong&gt; -&amp;gt; The &lt;strong&gt;DAY&lt;/strong&gt; function pulls the day from a full date, returning a value ranging from 0 to 31.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;This is just a scratch to the powerful world of Excel, and yet we can do much with the little we have covered. It is important that one understands all skills, as they build up as one continues exploring more and more functionalities of &lt;br&gt;
&lt;strong&gt;Microsoft Excel&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>datascience</category>
    </item>
    <item>
      <title>Understanding The Git Workflow: Working Directory, Staging, Commit and Push</title>
      <dc:creator>Denis Ndiritu</dc:creator>
      <pubDate>Sun, 23 Aug 2026 15:13:55 +0000</pubDate>
      <link>https://dev.to/sir_masha_g/understanding-the-git-workflow-working-directory-staging-commit-and-push-24b0</link>
      <guid>https://dev.to/sir_masha_g/understanding-the-git-workflow-working-directory-staging-commit-and-push-24b0</guid>
      <description>&lt;p&gt;Imagine working on a project for several weeks. You make hundreds of changes across dozens of files. Then your computer crashes. Which version of your project was working yesterday? What did you change? Which changes did your colleague make? And how do you combine everyone's work without overwriting each other's changes?&lt;/p&gt;

&lt;p&gt;This is where Git comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Git?
&lt;/h2&gt;

&lt;p&gt;Git is an open-source system that enables users to manage their projects, from a single file to large projects. Git is basically a version control system. It provides the necessary resource to help one manage files in the local machine, track the files that have been changed, attach a pointer which marks files which were changed, who did it, and when, and to make it redundant, these files can be pushed into a remote shareable project called repository in &lt;em&gt;Github&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Git also has something very key that is called &lt;em&gt;branches&lt;/em&gt;. A branch is basically an isolated area of your project where you can work on a copy of the main project without making changes to the main work. Once you are done working on your branch, Git makes it possible to merge all the changes to the main branch.&lt;/p&gt;

&lt;p&gt;For this article, I will cover these concepts, guiding one on the step by step process of how to do all this. This article assumes that one has Git installed and configured, and has a Github account. We shall also assume that one has a text editor installed, or is conversant with commands in the terminal. We shall cover these concepts in another article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Project On Your Machine
&lt;/h2&gt;

&lt;p&gt;To start, we need to create a folder where we shall be working on our project. On your machine, you can use the good old right click and select New Folder, or, if in terminal, use the command &lt;em&gt;mkdir &lt;/em&gt; as follows:&lt;br&gt;
&lt;code&gt;mkdir new_project&lt;/code&gt;&lt;br&gt;
This creates a folder called new_project&lt;/p&gt;

&lt;p&gt;We shall then open our folder in the terminal, so that we can do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initialize Git&lt;/li&gt;
&lt;li&gt;Create a file&lt;/li&gt;
&lt;li&gt;Stage it&lt;/li&gt;
&lt;li&gt;Commit it&lt;/li&gt;
&lt;li&gt;Link local repository to remote repository&lt;/li&gt;
&lt;li&gt;Push to Github account&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Initializing Git
&lt;/h3&gt;

&lt;p&gt;At this point, we have our folder. So to open it in terminal, we can open our favorite terminal, or simply open our folder in our text editor. Once this is done, we can now initialize Git using this command:&lt;br&gt;
&lt;code&gt;git init&lt;/code&gt;&lt;br&gt;
This command simply initializes a local Git repository in your project folder. You can confirm this by confirming that we have a &lt;em&gt;.git&lt;/em&gt; folder inside our main folder. During initialization, you will note that you will be in a default branch called &lt;em&gt;main&lt;/em&gt; or &lt;em&gt;master&lt;/em&gt;. To confirm this, simply run the command:&lt;br&gt;
&lt;em&gt;git branch&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating a File
&lt;/h3&gt;

&lt;p&gt;In our terminal, we can be able to create a file using the command:&lt;br&gt;
&lt;code&gt;touch &amp;lt;filename&amp;gt;&lt;/code&gt;&lt;br&gt;
This will create a file inside our main folder. For this case let's call our file &lt;em&gt;main.py&lt;/em&gt; At this point, you can run certain commands like:&lt;br&gt;
&lt;code&gt;git status&lt;/code&gt;&lt;br&gt;
which allows us to see files that we have not started to track, files we have modified, files we have staged, files we have modified after staging, and so on. Files that are not tracked means that they will not be pushed to Github once we get to that.&lt;/p&gt;

&lt;p&gt;We can now write a simple sentence on our terminal using a command called &lt;em&gt;echo&lt;/em&gt; as follows:&lt;br&gt;
&lt;code&gt;echo "print('This is a new file')" &amp;gt; main.py&lt;/code&gt;&lt;br&gt;
The echo command prints text, but when used together with the greater than sign (&lt;em&gt;&amp;gt;&lt;/em&gt;) and the file name, will write the text into the file specified. At this point, we are on our working directory. Git does not know what it needs to stage. So how do we stage files?&lt;/p&gt;
&lt;h3&gt;
  
  
  Staging a File(s)
&lt;/h3&gt;

&lt;p&gt;Staging a file basically tells Git that we want to commit our changes that we have made so far. Moreover, it will also stage any new, modified, or deleted paths too. We can do this by basically staging everything or staging a single file, or staging specific files.&lt;br&gt;
To do so, we can do the following&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; // Stages everything that is yet to be tracked.
git add &amp;lt;filename&amp;gt; // Stages a single file.
git add &amp;lt;filename_1&amp;gt; &amp;lt;filename_2&amp;gt; ... // Stages specific files.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we are in the staging area. We know what we want to commit/update in our remote repository. In the next stage, we will commit the staged files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Committing a File(s)
&lt;/h3&gt;

&lt;p&gt;We now commit our changes so Git records a snapshot of what we have done. This is important, as git uses these commits to help the user go back to a certain point in your branch.&lt;br&gt;
To create a commit, We use this command:&lt;br&gt;
&lt;code&gt;git commit -m "Add main Python file"&lt;/code&gt;&lt;br&gt;
The commit message should be in double quotes. Once this is done, we need to to point our local folder to our remote repository. If not created, you will need to create a repository.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: At this stage of our workflow, we are now in the local repository. We have a full committed history of what we have done, but it is local. We are yet to update on our remote repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Link Our Local Repository to Remote Repository
&lt;/h3&gt;

&lt;p&gt;We will first create a repository on Github. To do this, simply navigate to your Github account on your browser and click &lt;em&gt;New Repository&lt;/em&gt; button on your Repositories page. You will then provide a name for your repository, provide a description, and you can later have it as Private or Public of other users to access it. Once that is done, you can click the &lt;em&gt;Create repository&lt;/em&gt; button. For this case, our repository is called &lt;em&gt;health_records_analysis&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This has now created our repository. This repository contains a link which we can share to other users, and this is the link that we need to link our local folder with the newly created repository. To do this, simply access it once you scroll down in the page you are in the simply copy the http link. This is what we shall use. The link usually looks like this &lt;em&gt;&lt;a href="http://github.com/" rel="noopener noreferrer"&gt;http://github.com/&lt;/a&gt;/&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We will then go back to the terminal we were in and enter the following command&lt;br&gt;
&lt;code&gt;git remote add origin &amp;lt;repository_link&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Great! We can now conduct the final step, &lt;em&gt;pushing&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pushing Our Changes To Github
&lt;/h3&gt;

&lt;p&gt;To push to Github, we only need a single command:&lt;br&gt;
&lt;code&gt;git push -u origin main&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;git push&lt;/em&gt; will send our local commit to the remote repository&lt;br&gt;
&lt;em&gt;origin&lt;/em&gt; basically is the name of our remote repository&lt;br&gt;
&lt;em&gt;main&lt;/em&gt; is the branch we are pushing to&lt;br&gt;
&lt;em&gt;-u&lt;/em&gt; will establish origin/main as the remote branch.&lt;/p&gt;

&lt;p&gt;You can confirm this by going back to your Github account and refresh. You will see the file we just pushed, and the commit message. As you may have guessed, this is the remote repository. This is now where we have pushed our changes, and all this can be shared to relevant users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Learning Git is important as a person working with any kind of projects that require proper tracking, can be collaborative, and even makes your work neat. It is a skill that is important, and one that I, personally has had fun learning, and look forward to sharing my progress.&lt;/p&gt;

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