Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

A new Data Days event is coming soon! This time we’re going bigger than ever. Fabric, Power BI, SQL, AI and more. Don't miss out.

Reply
orionjtaylor
Frequent Visitor

Create rows for missing dates within groups

I have data with gaps by state-county, like:

 

StateCountyFirst_SeenLast_SeenDatePopulation
NYNew York2020-01-012020-06-302020-01-0117
NYNew York2020-01-012020-06-302020-01-0217
NYNew York2020-01-012020-06-302020-01-0319
NYNew York2020-01-012020-06-302020-01-0531
NYNew York2020-01-012020-06-302020-01-2550
NYNew York2020-01-012020-06-302020-01-2633
...     
NYNew York2020-01-012020-06-302020-06-3022
CALos Angeles2020-02-152020-03-152020-02-15886
CALos Angeles2020-02-152020-03-152020-02-16889
CALos Angeles2020-02-152020-03-152020-03-14855
CALos Angeles2020-02-152020-03-152020-03-15849

 

I want to create rows for missing dates within each State-County group in my table, and then linearly interpolate values of population over these. For instance, since NY-New York has data on 2020-01-03 and 2020-01-05 but not 2020-01-04, I would want to insert a row with linearly interpolated population for that date (19+31)/[length of gap = 2]=25 like:

 

...     
NYNew York2020-01-012020-06-302020-01-0319
NYNew York2020-01-012020-06-302020-01-0425
NYNew York2020-01-012020-06-302020-01-0531
...     

 

Is there a way to easily create rows for these missing dates within a group on (State, County), and/or to then linearly interpolate Population (or multiple columns) over these new rows?

1 ACCEPTED SOLUTION
Anonymous
Not applicable

@orionjtaylor 

 

Here's PQ code in M that does linear interpolation. It's an example of how to do it natively, so to speak. It could be refined further to use a function to return the interpolated value. This code works fine if the following assumptions about the data set are met: 

 

1) For each point/row that has a missing value there is a point that does have a value, its order is before the current point and it belongs to the same category and subcategory as the current point.

2) For each point/row that has a missing value there is a point that does have a value, its order is after the current point and it belongs to the same category and subcategory as the current point.

 

These are needed in order to be able to interpolate because you can't do it when there are no points with values on either side of a point with a missing value.

 

 

// f_InterpolateLinearly
(pointX as nullable number, 
    lowerPointX as nullable number, 
    lowerPointY as nullable number,
    upperPointX as nullable number,
    upperPointY as nullable number ) as nullable number =>
let
    slope = (upperPointY - lowerPointY) / (upperPointX - lowerPointX),
    value = slope * (pointX - lowerPointX) + lowerPointY
in
    value

// T
let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("bdA9CsMwDAXgu3hOIZJjxxnbHKBDoIvxkP5snUJ7/9pyCXlYg4z4eCCeYzTX7fnaTGfm9ZPf5Xt/yHJb3yZ10VDez2VOZSMxBhOyQFZsaGMOyIn53Xi/MIIJBaB6YWpj1IPVE0SAvmJZL2UO1cgCVhsUc4p5xUaw/+WgBCewUD+6b4NMirFiShNWmjA2yWVFsUuum9IP", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Cat = _t, Subcat = _t, Val = _t, Column1 = _t]),
    #"Promoted Headers" = Table.PromoteHeaders(Source, [PromoteAllScalars=true]),
    #"Changed Type" = Table.TransformColumnTypes(#"Promoted Headers",{{"Cat", type text}, {"Subcat", type text}, {"Val", Int64.Type}, {"Order", Int64.Type}}),
    #"Sorted Rows" = Table.Sort(#"Changed Type",{{"Cat", Order.Ascending}, {"Subcat", Order.Ascending}, {"Order", Order.Ascending}}),
    #"Added Custom" = Table.AddColumn(#"Sorted Rows", "Info", 
        each 
            if _[Val] <> null then null
            else
                Table.Last(
                    Table.SelectRows(#"Sorted Rows",
                        (r) => r[Order] < _[Order] 
                                and r[Cat] = _[Cat] 
                                and r[Subcat] = _[Subcat]
                                and r[Val] <> null
                    )[[Order], [Val]]
                )
    ),
    #"Expanded Info" = Table.ExpandRecordColumn(#"Added Custom", "Info", {"Order", "Val"}, {"Info.Order", "Info.Val"}),
    #"Renamed Columns" = Table.RenameColumns(#"Expanded Info",{{"Info.Order", "LowerOrder"}, {"Info.Val", "LowerVal"}}),
    #"Added Info2" = Table.AddColumn(#"Renamed Columns", "Info2", 
        each 
            if _[Val] <> null then null
            else
                Table.First(
                    Table.SelectRows(#"Sorted Rows",
                        (r) => r[Order] > _[Order] 
                                and r[Cat] = _[Cat] 
                                and r[Subcat] = _[Subcat]
                                and r[Val] <> null
                    )[[Order], [Val]]
                )
    ),
    #"Expanded Info2" = Table.ExpandRecordColumn(#"Added Info2", "Info2", {"Order", "Val"}, {"Info2.Order", "Info2.Val"}),
    #"Renamed Columns1" = Table.RenameColumns(#"Expanded Info2",{{"Info2.Order", "UpperOrder"}, {"Info2.Val", "UpperVal"}}),
    #"Added Custom1" = Table.AddColumn(#"Renamed Columns1", "Interpolation", each f_InterpolateLinearly(
    [Order],
    [LowerOrder],
    [LowerVal],
    [UpperOrder],
    [UpperVal]
)),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom1",{"LowerOrder", "LowerVal", "UpperOrder", "UpperVal"}),
    #"Added Custom2" = Table.AddColumn(#"Removed Columns", "FinalVal", each if [Val] = null then [Interpolation] else [Val]),
    #"Removed Columns1" = Table.RemoveColumns(#"Added Custom2",{"Interpolation"})
in
    #"Removed Columns1"

 

Just paste this code into Advanced Editor (as is) and watch this being evaluated step by step. Use the Applied Steps pane for that.

View solution in original post

6 REPLIES 6
Greg_Deckler
Community Champion
Community Champion

@orionjtaylor There might be:

Linear Interpolation - Microsoft Power BI Community

Mind the Gap (Irregular Time Series) - Microsoft Power BI Community

 

Also: Linear Interpolation with Power BI - Microsoft Power BI Community

 

 



Follow on LinkedIn
@ me in replies or I'll lose your thread!!!
Instead of a Kudo, please vote for this idea
Become an expert!: Enterprise DNA
External Tools: MSHGQM
YouTube Channel!: Microsoft Hates Greg
Latest book!:
DAX For Humans

DAX is easy, CALCULATE makes DAX hard...

Thanks @Greg_Deckler,

 

I completed the first portion of my task on my own luckily. Now, I'm stuck at the linear interpolations.

 

My data looks like this now:

 

StateCountyDatePopulation
NYNew York2020-01-01105
NYNew York2020-01-02106
NYNew York2020-01-03null
NYNew York2020-01-04null
NYNew York2020-01-05null
NYNew York2020-01-06114

 

I want to create a simple time trend interpolation over Population for each State/County group in Power Query M, such that the filled data looks like:

 

StateCountyDatePopulation
NYNew York2020-01-01105
NYNew York2020-01-02106
NYNew York2020-01-03108
NYNew York2020-01-04110
NYNew York2020-01-05112
NYNew York2020-01-06114

 

This seems like a simple task, but most of the information I've seen online makes this look like an incredibly convoluted task where one must create their own interpolation function. Do you know if there's a simple way to do this?

@Greg_Deckler also looks like perhaps both of those posts use DAX, but correct me if I'm wrong! (I am very new to Power BI in general. This kind of interpolation would be trivial in Python...)

Anonymous
Not applicable

@orionjtaylor 

 

Then do it in Python. You can use Python in Power Query as far as I know...

@Anonymous didn't realize that was an option. That does the trick as anticipated, although I maintain they should have a native solution for this! Anyway, thanks!

Anonymous
Not applicable

@orionjtaylor 

 

Here's PQ code in M that does linear interpolation. It's an example of how to do it natively, so to speak. It could be refined further to use a function to return the interpolated value. This code works fine if the following assumptions about the data set are met: 

 

1) For each point/row that has a missing value there is a point that does have a value, its order is before the current point and it belongs to the same category and subcategory as the current point.

2) For each point/row that has a missing value there is a point that does have a value, its order is after the current point and it belongs to the same category and subcategory as the current point.

 

These are needed in order to be able to interpolate because you can't do it when there are no points with values on either side of a point with a missing value.

 

 

// f_InterpolateLinearly
(pointX as nullable number, 
    lowerPointX as nullable number, 
    lowerPointY as nullable number,
    upperPointX as nullable number,
    upperPointY as nullable number ) as nullable number =>
let
    slope = (upperPointY - lowerPointY) / (upperPointX - lowerPointX),
    value = slope * (pointX - lowerPointX) + lowerPointY
in
    value

// T
let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("bdA9CsMwDAXgu3hOIZJjxxnbHKBDoIvxkP5snUJ7/9pyCXlYg4z4eCCeYzTX7fnaTGfm9ZPf5Xt/yHJb3yZ10VDez2VOZSMxBhOyQFZsaGMOyIn53Xi/MIIJBaB6YWpj1IPVE0SAvmJZL2UO1cgCVhsUc4p5xUaw/+WgBCewUD+6b4NMirFiShNWmjA2yWVFsUuum9IP", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [Cat = _t, Subcat = _t, Val = _t, Column1 = _t]),
    #"Promoted Headers" = Table.PromoteHeaders(Source, [PromoteAllScalars=true]),
    #"Changed Type" = Table.TransformColumnTypes(#"Promoted Headers",{{"Cat", type text}, {"Subcat", type text}, {"Val", Int64.Type}, {"Order", Int64.Type}}),
    #"Sorted Rows" = Table.Sort(#"Changed Type",{{"Cat", Order.Ascending}, {"Subcat", Order.Ascending}, {"Order", Order.Ascending}}),
    #"Added Custom" = Table.AddColumn(#"Sorted Rows", "Info", 
        each 
            if _[Val] <> null then null
            else
                Table.Last(
                    Table.SelectRows(#"Sorted Rows",
                        (r) => r[Order] < _[Order] 
                                and r[Cat] = _[Cat] 
                                and r[Subcat] = _[Subcat]
                                and r[Val] <> null
                    )[[Order], [Val]]
                )
    ),
    #"Expanded Info" = Table.ExpandRecordColumn(#"Added Custom", "Info", {"Order", "Val"}, {"Info.Order", "Info.Val"}),
    #"Renamed Columns" = Table.RenameColumns(#"Expanded Info",{{"Info.Order", "LowerOrder"}, {"Info.Val", "LowerVal"}}),
    #"Added Info2" = Table.AddColumn(#"Renamed Columns", "Info2", 
        each 
            if _[Val] <> null then null
            else
                Table.First(
                    Table.SelectRows(#"Sorted Rows",
                        (r) => r[Order] > _[Order] 
                                and r[Cat] = _[Cat] 
                                and r[Subcat] = _[Subcat]
                                and r[Val] <> null
                    )[[Order], [Val]]
                )
    ),
    #"Expanded Info2" = Table.ExpandRecordColumn(#"Added Info2", "Info2", {"Order", "Val"}, {"Info2.Order", "Info2.Val"}),
    #"Renamed Columns1" = Table.RenameColumns(#"Expanded Info2",{{"Info2.Order", "UpperOrder"}, {"Info2.Val", "UpperVal"}}),
    #"Added Custom1" = Table.AddColumn(#"Renamed Columns1", "Interpolation", each f_InterpolateLinearly(
    [Order],
    [LowerOrder],
    [LowerVal],
    [UpperOrder],
    [UpperVal]
)),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom1",{"LowerOrder", "LowerVal", "UpperOrder", "UpperVal"}),
    #"Added Custom2" = Table.AddColumn(#"Removed Columns", "FinalVal", each if [Val] = null then [Interpolation] else [Val]),
    #"Removed Columns1" = Table.RemoveColumns(#"Added Custom2",{"Interpolation"})
in
    #"Removed Columns1"

 

Just paste this code into Advanced Editor (as is) and watch this being evaluated step by step. Use the Applied Steps pane for that.

Helpful resources

Announcements
May Power BI Update Carousel

Power BI Monthly Update - May 2026

Check out the May 2026 Power BI update to learn about new features.

Fabric SQL PBI Data Days

Data Days 2026 coming soon!

Sign up to receive a private message when registration opens and key events begin.

New to Fabric survey Carousel

New to Fabric Survey

If you have recently started exploring Fabric, we'd love to hear how it's going. Your feedback can help with product improvements.

Power BI DataViz World Championships carousel

Power BI DataViz World Championships - June 2026

A new Power BI DataViz World Championship is coming this June! Don't miss out on submitting your entry.