I have following data (simplified):
DATETIME | VAL_A | VAL_B | VAL_C | VAL_A_x |
---|---|---|---|---|
1.1.2025 | 1 | 2 | 3 | 4 |
2.1.2025 | 5 | 6 | 7 | 8 |
I have following data (simplified):
DATETIME | VAL_A | VAL_B | VAL_C | VAL_A_x |
---|---|---|---|---|
1.1.2025 | 1 | 2 | 3 | 4 |
2.1.2025 | 5 | 6 | 7 | 8 |
I need to calculate average value for EACH column (dynamic number) that has pair (VAL_A -> VAL_A_x) and REPLACE value in its mother column (VAL_A).
Something VAL_A = (VAL_A + VAL_A_x)/2
.
Then I will delete columns ending with _x
(It is simple).
In the end, this is needed to achieve:
DATETIME | VAL_A | VAL_B | VAL_C |
---|---|---|---|
1.1.2025 | 2.5 | 2 | 3 |
2.1.2025 | 7 | 6 | 7 |
I have a lot of columns without a pair to average with. I have a lot of rows. I don't like to transpose the whole table. Columns are decimal numbers.
I tried to filter columns that are ending with "_x"
= List.Select(Table.ColumnNames(Source), each Text.EndsWith(_,"_x")),
but not getting far from that.
Share Improve this question edited Apr 1 at 19:46 Stefan Billik asked Apr 1 at 12:39 Stefan BillikStefan Billik 131 silver badge5 bronze badges 3 |3 Answers
Reset to default 1Try this:
Custom Function
Be sure to rename this as per the comments
//rename fnAverageColumns
(tbl as table, col as text)=>
[a=List.Select(Table.ColumnNames(tbl), each _ = "DATETIME" or Text.StartsWith(_,col)),
b=Table.SelectColumns(tbl,a),
c=Table.AddColumn(b,"Average", each List.Average(List.Skip(Record.FieldValues(_))), type number),
d=Table.ReplaceValue(
c,
each Record.Field(_,col),
each [Average],
(x,y,z) as number=>z,
{col}),
e=Table.SelectColumns(d,{"DATETIME",col})
][e]
Main Query
let
//Change next line to reflect actual data source
Source = Excel.CurrentWorkbook(){[Name="Table5"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,
{{"DATETIME", type date}} & List.Transform(List.Skip(Table.ColumnNames(Source)), each {_, type number})),
#"Averages" = List.Accumulate(
List.Select(List.Skip(Table.ColumnNames(#"Changed Type")), each not Text.EndsWith(_,"_x")),
Table.SelectColumns(#"Changed Type",{"DATETIME"}),
(s,c)=> Table.Join(s,"DATETIME", fnAverageColumns(#"Changed Type",c), "DATETIME"))
in
#"Averages"
Data
Results
One solution is simple, second one is interesting with List.Accumulate()
I'll have to try both and choose fastest solution.
In the night I decided to replace *_x values with average of * and *_x:
#"DATA" = #"Changed Type"
#"AVERAGED" = Table.FromRecords(Table.TransformRows(#"DATA", each _ & Record.FromList( List.Transform(List.Select(Record.FieldNames(_), each Text.EndsWith(_, "_x")),
(name) => Record.Field(_, name)*0.5 + Record.Field(_, Text.BeforeDelimiter(name, "_x"))*0.5 ), List.Select(Record.FieldNames(_), each Text.EndsWith(_, "_x")))), Value.Type(#"DATA")),
It's not so nice.
The easiest would be to "transpose" or unpivot columns, then to pivot columns back again after doing a Group By
with an extract text on the second occurrence of the delimiter.
Example:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(Source, {"DATETIME"}, "Attribute", "Value"),
#"Added Custom" = Table.AddColumn(#"Unpivoted Other Columns", "Column", each Text.BeforeDelimiter([Attribute], "_", 1)),
#"Grouped Rows" = Table.Group(#"Added Custom", {"DATETIME", "Column"}, {{"Value", each List.Average([Value]), type number}}),
#"Pivoted Column" = Table.Pivot(#"Grouped Rows", List.Distinct(#"Grouped Rows"[Column]), "Column", "Value", List.Sum)
in
#"Pivoted Column"
2.1.2025
[VAL_A]
should be6.5
, shouldn't it? – Ron Rosenfeld Commented Apr 1 at 20:42