我有一张时间序列数据表,其中每个条目都与日期间隔相关联。有没有办法将不同的时间序列组合并合并为一个时间序列?
给出输入表1:
|Role|From |To |Value|
|A |01.01.2017|15.01.2017| 1|
|A |16.01.2017|01.02.2017| 2|
|A |02.02.2017|28.02.2017| 2|
|B |16.01.2017|05.03.2017| 5|
|B |06.03.2017|31.03.2017| 7|
我可以使用PowerQueryin将此自动转换为以下内容(请注意合并间隔的使用):
|From|01.01.2017|16.01.2017|02.02.2017|01.03.2017|06.03.2017|
|To |15.01.2017|01.02.2017|28.02.2017|05.03.2017|31.03.2017|
|A | 1| 2| 2| | |
|B | | 5| 5| 5| 7|
|Sum | 1| 7| 7| 5| 7|
答案 0 :(得分:1)
以下是您的代码版本。它有点短,可能更直接。它也返回与示例中完全相同的结果。
let
// Data source
SourceTable = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Data = Table.TransformColumnTypes(SourceTable,{{"Role", type text}, {"From", type datetime}, {"To", type datetime}, {"Value", Int64.Type}}),
//Get a list of roles.
// Roles = {"A", "B", "C", "D"}, //Example line. Comment it
Roles = List.Transform(Table.Distinct(Table.SelectColumns(SourceTable, {"Role"}))[Role], each Text.Trim(Text.Upper(_))),
// Create table of all possible intervals
UnionTables = Table.TransformColumnTypes(
Table.Combine({
Table.SelectColumns(SourceTable, "From"),
Table.SelectColumns(Table.AddColumn(Table.SelectColumns(SourceTable, "To"), "From", each Date.AddDays([To], 1)), {"From"}) //Add 1 day to ensure next interval starts at the same date to produce no fake 1-day intervals
}),
{{"From", type datetime}}),
SortDates = Table.Sort(Table.Distinct(UnionTables), {{"From", Order.Ascending}}),
AddIndex = Table.AddIndexColumn(SortDates, "Index", 0, 1),
AllIntervals = Table.RemoveRowsWithErrors(Table.AddColumn(AddIndex, "To", each Date.AddDays(AddIndex[From]{[Index] + 1}, -1), type datetime)), //Substract 1 day to revert intervals to their original values
AddColumns = Table.Combine(List.Transform(Roles, (Role) => Table.AddColumn(Table.SelectColumns(AllIntervals, {"From", "To"}), Role, (x) => List.Sum(Table.SelectRows(Data, (y) => Text.Upper(Text.Trim(y[Role])) = Role and ((y[From] >= x[From] and y[To] <= x[To]) or (y[From] <= x[From] and y[To] >= x[To])))[Value]), type number))),
GetDistinctRows = Table.Distinct(AddColumns),
FilterOutNulls = Table.SelectRows(GetDistinctRows, each List.MatchesAny(Record.FieldValues(Record.SelectFields(_, Roles)), (x) => x <> null) /*List.Match(Table.ColumnNames(AddColumns), Roles) <> null*/),
AddSum = Table.AddColumn(FilterOutNulls, "Sum", each List.Sum(Record.FieldValues(Record.SelectFields(_, Roles)))),
ListOfNonNullColumns =
List.Select(
List.Transform(Roles, (x) => if (
Table.RowCount(
Table.SelectRows(AddSum, (y) =>
List.Sum(
Record.FieldValues(
Record.SelectFields(y, {x})
)
) > 0
)
)
) > 0 then x else null)
, each _ <> null),
CleanAndReorder = Table.SelectColumns(AddSum, List.Combine({{"From", "To"}, ListOfNonNullColumns, {"Sum"}})),
DemoteHeaders = Table.DemoteHeaders(CleanAndReorder),
Result = Table.Transpose(DemoteHeaders)
in
Result
答案 1 :(得分:0)
我找到了一种方法,用M代码进行下面的电源查询,并对各个步骤进行评论:
let
// Data source
SourceTable = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
Data = Table.TransformColumnTypes(SourceTable,{{"Role", type text}, {"From", type datetime}, {"To", type datetime}, {"Value", Int64.Type}}),
// Create table of all possible intervals
AllDates = Table.Sort(
Table.Distinct(
Table.Combine({
Table.RenameColumns(Table.SelectColumns(SourceTable, "From"), {"From", "Date"}),
Table.RenameColumns(Table.SelectColumns(SourceTable, "To"), {"To", "Date"})
})
), {{"Date", Order.Ascending}}
),
RenameFrom = Table.RenameColumns(
Table.AddIndexColumn(AllDates, "Index", 0, 1), {"Date", "From"}
),
AllIntervals = Table.RemoveRowsWithErrors( Table.AddColumn(RenameFrom, "To", each RenameFrom[From]{[Index] + 1})),
// Join Data with all possible intervals
InsertedCustom = Table.AddColumn(Data, "temp", each AllIntervals),
ExpandedTable = Table.ExpandTableColumn(InsertedCustom, "temp", { "From", "To" }, { "From2", "To2" }),
ExpandedTableWithValidValue = Table.AddColumn(ExpandedTable, "ValidValue", each ( if ([From] < [To2] and [To] > [From2]) then [Value] else 0) ),
ExpandedTableRevised = Table.RenameColumns( Table.RemoveColumns (ExpandedTableWithValidValue , { "Value", "From", "To" } ) , { { "ValidValue", "Value" }, {"From2", "From"}, { "To2", "To" } } ),
// Group and sum Data
#"Grouped Rows" = Table.Group(ExpandedTableRevised, List.RemoveItems(Table.ColumnNames(ExpandedTableRevised), { "Value" } ), {{"Value", each List.Sum([Value]), type number}}),
#"Pivoted Column" = Table.Pivot(#"Grouped Rows", List.Distinct(#"Grouped Rows"[Role]), "Role", "Value", List.Sum),
#"Summed By Role" = Table.AddColumn(#"Pivoted Column", "Sum", each List.Sum(Record.ToList(Record.RemoveFields(_, { "From", "To" }))) ),
// Transpose data with intervals, values and sum to target result structure
ResultDataTable = Table.Transpose(#"Summed By Role"),
// Create First column with labels for result structure
FirstColumnRoles= Table.Distinct(Table.SelectColumns(SourceTable, "Role")),
FirstColumnWithFromToLabels = Table.InsertRows(FirstColumnRoles, 0, { [Role="From"], [Role="To"] }),
FirstColumnWithSum = Table.InsertRows ( FirstColumnWithFromToLabels , Table.RowCount(FirstColumnWithFromToLabels ), {[Role="Sum"]}),
FirstColumn = Table.AddIndexColumn(FirstColumnWithSum , "Index", 0, 1),
// Merge First column of labels with data structure and clean up redundant columns
ResultTable = Table.RemoveColumns(
Table.ReorderColumns( Table.Join( FirstColumn, "Index", Table.AddIndexColumn(ResultDataTable , "Index", 0, 1), "Index"), { "Index", "Role"}),
"Index"
),
Custom1 = ResultTable
in
Custom1