【问题标题】:Merge and Stack Multiple Sets of Columns dynamically - Power Query动态合并和堆叠多组列 - Power Query
【发布时间】:2021-02-18 22:26:23
【问题描述】:

我有一个如下所示的单个 csv 数据集。我有多个这样的 csv 文件,一旦我找出单个文件的正确转换,我想将它们组合起来。这是包含此数据的Sample Excel File:

进入这个预期的输出:

输入数据大致有 4 个部分:

1] 前 3 列用于创建 Questions、Answers 和 Label 列。

2] 百分比列的一部分。

3] 一段统计测试列。

4] 1 列的部分。

我想Merge 每组列R.1....R10,然后Unpivot (Stack) 它们一个接一个,如输出所示。 R1...R10 的列数可能每次都不同,但每个部分的列数相同,即 Percentage columns、Stat testing columns 和 1 columns。

在谷歌搜索时,我遇到了一个Imke Feldmannpost,关于使用自定义函数动态合并和反透视列。但是,我无法动态选择和合并列的不同部分。此外,我发现 Bill Szysz 的 post 有点相似,并试图找出一种方法来修改他的第二个解决方案,即 Combine Method 在类似的帖子中。这是 Bill Szysz 的组合方法解决方案。

let
    Source = Table.PromoteHeaders(Excel.CurrentWorkbook(){[Name="UglyData"]}[Content], [PromoteAllScalars=true]),
    Lists = Table.FromColumns({List.Transform({0..((List.Count(Table.ColumnNames(Source))-6)/5)-1}, each List.Range(Table.ColumnNames(Source), _*5+6, 5)) }),
    AlmostReady = Table.Combine(Table.AddColumn(Lists, "Columns", each Table.FromColumns({Table.Column(Source, Table.ColumnNames(Source){0})} & {List.Repeat({[Column1]{0}}, Table.RowCount(Source))} & List.Transform(List.Skip([Column1], 1), each Table.Column(Source, _)), {Table.ColumnNames(Source){0}, "Name"} & List.Transform(List.Skip([Column1], 1), each Text.BeforeDelimiter(_, "_")) )   )[Columns]),
    Ready = Table.AddColumn(AlmostReady, "Total", each List.Sum(List.Skip(Record.ToList(_), 2)))
in
    Ready

问题是,Bill 使用固定的列数和行数(5 和 6),而我的列数和行数可能会改变。例如今天每个部分有 10 组列,明天可能有 5 或 20 组。但是每个部分的列数将始终相同,即百分比部分、统计部分和数字部分。此外,列的顺序可能会改变,但在各个部分中保持相同的顺序:

例如:

百分比部分  | |统计部分         | |数字部分    |

R1 | R3 | R2 | R5 | R4 | | R1 | R3 | R2 | R5 | R4 | | R1 | R3 | R2 | R5 | R4 |

这个数据很棘手,超出了我的业余技能。这可以吗?

【问题讨论】:

  • 这是一个复杂的问题,似乎需要几种不同的技术来解决。如果您可以将其分解为更简单的子问题并分别提出问题,那么您可能会更幸运地得到答案,因为这些问题会更容易回答,并且更有可能对未来的读者有用。
  • 是的。这就是为什么超出我的理解水平。这只是一个 csv 文件。一旦我找到了 1 个 csv 的确切转换,然后我计划将其转换为函数并将转换应用于一起导入的其他 csv 文件(以组合它们)。希望你得到我想要做的。
  • 但我认为@horseyride 在下面给出了一个优雅的部分解决方案,在过去的 1 周里让我绞尽脑汁。唯一的办法是以某种方式将问题、答案和标签分隔为单独的列,然后将 3 个表组合在一起(第一、第二、第三)以获得最终输出,如工作簿中所示。
  • 是的。这解决了它的一部分。然后你需要做一些事情,比如填写 A 列,将该索引与问题和答案编号匹配(可能通过子查询?),将标签列(百分比/统计/数字)添加到每个第一/第二/第三表,将它们附加在一起,然后排序。
  • 你能举例说明你的意思吗?

标签: excel csv merge multiple-columns powerquery


【解决方案1】:

这里是部分答案,因为我无法完全弄清楚您在寻找什么

它创建了三个表,每个表都有前三列,然后是后面的 XX 列。您可以根据需要将它们组合起来并随心所欲地使用它们

let Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
List = Table.ColumnNames (Source),
Count = List.Count (List),
First = Table.SelectColumns(Source,List.FirstN(List,3)  & List.RemoveFirstN(List.RemoveLastN(List,(Count-3)/3*2),4)),
Second = Table.SelectColumns(Source,List.FirstN(List,3)  &  List.RemoveFirstN(List.RemoveLastN(List,(Count-3)/3),4+(Count-3)/3)),
Third = Table.SelectColumns(Source,List.FirstN(List,3)  &  List.RemoveFirstN(List,4+(Count-3)/3*2))
in Third

看看这是否适合你

let Source = Csv.Document(File.Contents("C:\temp\SampleCSV.csv"),[Delimiter=",", Encoding=1252, QuoteStyle=QuoteStyle.None]),
#"Promoted Headers" = Table.PromoteHeaders(Source, [PromoteAllScalars=true]),
// get list and count of columns
List = Table.ColumnNames (#"Promoted Headers" ),
Count = List.Count (List),
// get list of columns from first table and preserve to rename in last step
FirstNames = List.RemoveFirstN(List.RemoveLastN(List,(Count-3)/3*2),4),
// divide the table into three tables by section and combine
Headers = List.Combine ({{"Que","Label","Agg"},FirstNames,{"Answer","Question"}}),
First = Table.Skip(Table.DemoteHeaders(Table.SelectColumns(#"Promoted Headers" ,List.FirstN(List,3)  & FirstNames)),1),
Second = Table.Skip(Table.DemoteHeaders(Table.SelectColumns(#"Promoted Headers" ,List.FirstN(List,3)  &  List.RemoveFirstN(List.RemoveLastN(List,(Count-3)/3),4+(Count-3)/3))),1),
Third = Table.Skip(Table.DemoteHeaders(Table.SelectColumns(#"Promoted Headers" ,List.FirstN(List,3)  &  List.RemoveFirstN(List,4+(Count-3)/3*2))),1),
Combined = Table.Combine({First,Second,Third}),
// pull out the Question, Answer. Label, Que and fill down
#"Added Index" = Table.AddIndexColumn(Combined, "Index", 0, 1),
#"Added Custom" = Table.AddColumn(#"Added Index", "Answer", each try if  #"Added Index"{[Index]-1}[Column1] <> "" and [Column1] = "" then [Column2] else null otherwise null),
#"Added Custom1" = Table.AddColumn(#"Added Custom", "Custom", each try if [Column1]<> "" then [Column2] else null otherwise null),
#"Added Custom2" = Table.AddColumn(#"Added Custom1", "Custom3", each try if #"Added Index"{[Index]-1}[Column1] <> "" or [Column3]="" then "kill" else null otherwise "kill"),
#"Replaced Value" = Table.ReplaceValue(#"Added Custom2","",null,Replacer.ReplaceValue,{"Column1"}),
#"Filled Down" = Table.FillDown(#"Replaced Value",{"Answer", "Custom","Column1"}),
#"Filtered Rows" = Table.SelectRows(#"Filled Down", each ([Custom3] = null)),
#"Removed Columns" = Table.RemoveColumns(#"Filtered Rows",{"Index","Custom3"}),
// rename and reorder
#"Rename Columns" = Table.RenameColumns( #"Removed Columns", List.Zip( { Table.ColumnNames( #"Removed Columns" ),  Headers } )),
#"Reordered Columns" = Table.ReorderColumns(#"Rename Columns",List.Combine({{"Que", "Question", "Answer", "Label", "Agg"}, List.Sort(FirstNames)}))
in #"Reordered Columns"

【讨论】:

  • 这很有趣!我如何堆叠这些列表以生成工作簿中显示的最终输出?我是PQ的业余爱好者。
  • 您先降级标题然后跳过第一行,这真是太巧妙了。我真的很喜欢你干净优雅的方法。但是,我不明白这一行,Added Custom2 = Table.AddColumn(#"Added Custom1", "Question", each if [Answer] &lt;&gt; null or [Custom] &lt;&gt; null or [Column2] = null then "kill" else "ok"),每行都显示Kill。最终结果是,我得到了一个经过过滤的空表。
  • 这里是与要导入的 CSV 相同的源文件。 link
  • 天才!这样做。唯一的事情是标签的排序,其中百分比应该是第一行,统计测试第二行,数字第三行等,如输出所示。但这绝对是答案。非常感谢! :-)
  • 在合并之前将自定义列 =1 =2 或 =3 添加到三个表中,将名称添加到 Headers,然后再使用。或者先尝试重新排序三个表的组合
猜你喜欢
  • 1970-01-01
  • 2020-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多