Power Query 加入最小差异
Power Query join on the least difference
如何根据列之间的最小差异对两个表进行 Power Query 连接。我的意思是数字之间的绝对差异。
我关注了这篇很棒的文章:https://exceed.hr/blog/merging-with-date-range-using-power-query/
我尝试类似地添加此自定义列,其中 L 代表 Tab1,R 代表 Tab2:
= Table.AddColumn(
Source,
"LeastAbsDifference",
(L) =>
Table.SelectRows( Tab2,
(R) => L[category] = R[category] and Number.Abs(L[target] - R[actual]) )
)
它产生错误:
Expression.Error: 我们无法将值 4 转换为逻辑类型。
要重新创建的表示例:
// Tab1
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTJVitWJVnKCs5whrFgA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [category = _t, target = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"target", Int64.Type}})
in
#"Changed Type"
// Tab2
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTJUitWBsIzgLGMwywnIMoGzTOEsM6XYWAA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [category = _t, actual = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"actual", Int64.Type}})
in
#"Changed Type"
这是一种方法:
- 附加两个表
- 按类别分组
- 将所需列作为组聚合输出
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTJVitWJVnKCs5whrFgA", BinaryEncoding.Base64),
Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [category = _t, target = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"target", Int64.Type}}),
Source2 = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTJUitWBsIzgLGMwywnIMoGzTOEsM6XYWAA=",
BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [category = _t, actual = _t]),
#"Changed Type1" = Table.TransformColumnTypes(Source2,{{"actual", Int64.Type}}),
//append the tables
append = Table.Combine({#"Changed Type",#"Changed Type1"}),
//Group by category, then output the desired columns
#"Grouped Rows" = Table.Group(append, {"category"}, {
{"target", each [target]{0},Int64.Type},
{"actual", (t)=> t[actual]{
List.PositionOf(List.Transform(t[actual], each Number.Abs(t[target]{0} - _)),
List.Min(List.Transform(t[actual], each Number.Abs(t[target]{0} - _))),Occurrence.First)},Int64.Type},
{"least difference", (t)=> List.Min(List.Transform(t[actual], each Number.Abs(t[target]{0} - _))),Int64.Type
}})
in
#"Grouped Rows"
上面代码的输出
我要感谢 Kristian Rados 的帮助,他在他的文章的评论中提供了我的问题的答案:Merging with date range using Power Query 非常感谢,并承蒙作者的礼貌,我引用了完整回答:
您的公式产生错误的原因是 Table.SelectRows 函数的第二个参数。在其中,您需要使用布尔 (true/false) 表达式过滤 table。在您的情况下,带有 Number.Abs 函数的代码部分 returns 是一个数字而不是 true/false (例如 L[target] – R[actual] = 5-1=4 )。尝试以这种方式过滤 table 是可行的,但它需要您使用多个嵌套环境,这将导致非常复杂的公式和缓慢的性能。
我建议尝试不同的方法。通过使用堆栈溢出中的示例,我重现了该问题。下面是我想出的完整 M 代码以及下面的解释:
let
Source = Tab1,
#"Merged Queries" = Table.NestedJoin(Source, {"category"}, Tab2, {"category"}, "Tab2", JoinKind.LeftOuter),
#"Expanded Tab2" = Table.ExpandTableColumn(#"Merged Queries", "Tab2", {"actual"}, {"actual"}),
#"Inserted Subtraction" = Table.AddColumn(#"Expanded Tab2", "Least difference", each Number.Abs([target] - [actual]), Int64.Type),
#"Grouped Rows" = Table.Group(#"Inserted Subtraction", {"category"}, {{"All", each Table.First(Table.Sort(_, {{"Least difference", Order.Ascending}}))}}),
#"Expanded All" = Table.ExpandRecordColumn(#"Grouped Rows", "All", {"target", "actual", "Least difference"}, {"target", "actual", "Least difference"})
in
#"Expanded All"
首先,我们使用类别列合并查询。在扩展 table 之后,我们减去两列以获得目标和实际之间的绝对差异。最后,我们按类别分组,并按 Least difference 列按升序对 table 进行排序(分组行内的 Table.Sort 函数)。在此之后,我们取第一行嵌套的table(Table.First函数),最后展开记录列。
如何根据列之间的最小差异对两个表进行 Power Query 连接。我的意思是数字之间的绝对差异。
我关注了这篇很棒的文章:https://exceed.hr/blog/merging-with-date-range-using-power-query/
我尝试类似地添加此自定义列,其中 L 代表 Tab1,R 代表 Tab2:
= Table.AddColumn(
Source,
"LeastAbsDifference",
(L) =>
Table.SelectRows( Tab2,
(R) => L[category] = R[category] and Number.Abs(L[target] - R[actual]) )
)
它产生错误: Expression.Error: 我们无法将值 4 转换为逻辑类型。
要重新创建的表示例:
// Tab1
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTJVitWJVnKCs5whrFgA", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [category = _t, target = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"target", Int64.Type}})
in
#"Changed Type"
// Tab2
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTJUitWBsIzgLGMwywnIMoGzTOEsM6XYWAA=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [category = _t, actual = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"actual", Int64.Type}})
in
#"Changed Type"
这是一种方法:
- 附加两个表
- 按类别分组
- 将所需列作为组聚合输出
let
Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTJVitWJVnKCs5whrFgA", BinaryEncoding.Base64),
Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [category = _t, target = _t]),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"target", Int64.Type}}),
Source2 = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WclTSUTJUitWBsIzgLGMwywnIMoGzTOEsM6XYWAA=",
BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [category = _t, actual = _t]),
#"Changed Type1" = Table.TransformColumnTypes(Source2,{{"actual", Int64.Type}}),
//append the tables
append = Table.Combine({#"Changed Type",#"Changed Type1"}),
//Group by category, then output the desired columns
#"Grouped Rows" = Table.Group(append, {"category"}, {
{"target", each [target]{0},Int64.Type},
{"actual", (t)=> t[actual]{
List.PositionOf(List.Transform(t[actual], each Number.Abs(t[target]{0} - _)),
List.Min(List.Transform(t[actual], each Number.Abs(t[target]{0} - _))),Occurrence.First)},Int64.Type},
{"least difference", (t)=> List.Min(List.Transform(t[actual], each Number.Abs(t[target]{0} - _))),Int64.Type
}})
in
#"Grouped Rows"
上面代码的输出
我要感谢 Kristian Rados 的帮助,他在他的文章的评论中提供了我的问题的答案:Merging with date range using Power Query 非常感谢,并承蒙作者的礼貌,我引用了完整回答:
您的公式产生错误的原因是 Table.SelectRows 函数的第二个参数。在其中,您需要使用布尔 (true/false) 表达式过滤 table。在您的情况下,带有 Number.Abs 函数的代码部分 returns 是一个数字而不是 true/false (例如 L[target] – R[actual] = 5-1=4 )。尝试以这种方式过滤 table 是可行的,但它需要您使用多个嵌套环境,这将导致非常复杂的公式和缓慢的性能。
我建议尝试不同的方法。通过使用堆栈溢出中的示例,我重现了该问题。下面是我想出的完整 M 代码以及下面的解释:
let
Source = Tab1,
#"Merged Queries" = Table.NestedJoin(Source, {"category"}, Tab2, {"category"}, "Tab2", JoinKind.LeftOuter),
#"Expanded Tab2" = Table.ExpandTableColumn(#"Merged Queries", "Tab2", {"actual"}, {"actual"}),
#"Inserted Subtraction" = Table.AddColumn(#"Expanded Tab2", "Least difference", each Number.Abs([target] - [actual]), Int64.Type),
#"Grouped Rows" = Table.Group(#"Inserted Subtraction", {"category"}, {{"All", each Table.First(Table.Sort(_, {{"Least difference", Order.Ascending}}))}}),
#"Expanded All" = Table.ExpandRecordColumn(#"Grouped Rows", "All", {"target", "actual", "Least difference"}, {"target", "actual", "Least difference"})
in
#"Expanded All"
首先,我们使用类别列合并查询。在扩展 table 之后,我们减去两列以获得目标和实际之间的绝对差异。最后,我们按类别分组,并按 Least difference 列按升序对 table 进行排序(分组行内的 Table.Sort 函数)。在此之后,我们取第一行嵌套的table(Table.First函数),最后展开记录列。