乐于分享
好东西不私藏

EXCEL|Power Query自定义函数综合实战-表格降维技巧之NxM层级结构化表格

EXCEL|Power Query自定义函数综合实战-表格降维技巧之NxM层级结构化表格
在现实工作中,我们还会遇到更复杂的结构化表格,比如3x2、3x3层级的结构化表格。通过前面几节的学习,我们可以总结出的核心规律是:行标题上的多层标题需要在填充后合并列,列标题上的多层标题则需要转置后填充。我们用N表示行标题的层级数,用M标题的层级数,则NxM层级结构化表格转换过程的具体 步骤如下:
1)在Excel中行维度的前N-1列都有合并单元格,所以需要向下填充N-1列;
2)使用指定分隔符合并行维度的前N列,测试表格转换为1xM层级的情形。
3)转置。
4)列维度的前M-1列都包含合并单元格,所以需要向下填充M-1列。
5)提升标题。
6)选中前M列,逆透视其他列。
7)将属性列按指定分隔符拆分列。
8)重命名。
我们以3x2层级结构化表格为例。如下图所示。行标题上有年、季度和月份3个维度,列标题上有产品种类和产品名称两个维度。
这种情形下的主要处理步骤及对应的M函数如下。
1)向下填充前两列,即年与季度列,对应的M函数:Table.FillDown()。
2)使用分隔符"|"合并年、季度和月份这3列,对应M函数:Table.CombineColumns()。
3)转置,对应M函数:Table.Transpose()。
4)向下填充第一列,即产品种类列,对应M函数:Table.FillDown()。
5)提升标题,对应M函数:Table.PromoteHeaders()。
6)选中前两列,逆透视其他列,对应M函数:Table.UnpivotOtherColumns()。
7)按分隔符"|"拆分属性列,对应M函数:Table.SplitColumn()。
8)重命名列,对应M函数:Table.RenameColumns()。
通过以上8个步骤就完成了3x2层级结构化表格的降维转换。转换后结果如下图所示。
既然数据转换的过程是固定的,借助M函数就可以将整个过程"打包"成自定义函数。自定义函数时最重要的操作之一是找到标准化输入的部分,也就是函数的参数部分。然后明确相应步骤需要用到的M函数及其参数的类型。
此案例中我们可以将源表、列维度以及行维度作为参数建立自定义函数,行及列维度以列表的形式提供,以标题为成员,比如,行标题是{年,季度,月份},列标题是{产品种类,产品名称}。通过List.Count()函数可以获得N及M的值。通过文本参数指定逆透视以后数值列的名称,如销量或者销售额。
因此我们将自定义函数的参数标准化为以下方式:
(源表,行标题,列标题,值名称)=>
自定义函数需要声明以下4个参数。
1)源:用于转换的源表,就是加载到Power Query里的数据表;
2)行标题:包含行维度标题的列表,需要以列表的形式输入;
3)列标题:包含列维度标题的列表,需要以列表的形式输入;
4)值名称:逆透视后数值列的名称,需要以文本形式输入。
对于函数的主体,我们可以结合之前的转换步骤进行修改,选择的查询需要是行及列维度都大于或等于2的。我们这里复制查询"2x2层级"并进行修改。修改以后自定义函数如下图所示。
自定义表格降维函数的M代码如下。

(源表, 行标题, 列标题, 值名称)=>

let

    所有表列 = Table.ColumnNames(源表),

    N = List.Count(行标题),

    M = List.Count(列标题),

    //提取表列及N、M的数值,方便后续步骤直接调用

    向下填充行 = Table.FillDown(源表,List.FirstN(所有表列,N-1)),

    合并列 = Table.CombineColumns(向下填充行,List.FirstN(所有表列,N),

    Combiner.CombineTextByDelimiter("|", QuoteStyle.None),"已合并"),

    转置表 = Table.Transpose(合并列),

    //填充行标题后,转置表

   向下填充列 = Table.FillDown(转置表,List.FirstN(所有表列,M-1)),

    提升标题 = Table.PromoteHeaders(向下填充列, PromoteAllScalars=true]),

    逆透视其他列 = Table.UnpivotOtherColumns(提升标题,

                             List.FirstN(Table.ColumnNames(提升标题),M),

                              "属性", 值名称),

      //填充并提升列标题,后逆透视

     按分隔符拆分列 = Table.SplitColumn(逆透视其他列, "属性",                                         Splitter.SplitTextByDelimiter("|",QuoteStyle.Csv),                              行标题),

    重命名列 = Table.RenameColumns(按分隔符拆分列,

                     List.Zip(

                     {

                     List.FirstN(Table.ColumnNames(按分隔符拆分列),M),

                     列标题

                     })

                     )

in

    重命名列

降维函数定义好以后就可以在应用步骤中直接调用了。调用函数时需要保证参数的格式是正确的。源表的顶端不能有空行,也不能有其他无关的空列。行标题及列标题按要求以列表的形式提供,且按正确的顺序列出。所有的标题都需要是文本类型的。比如转换3x3层级结构化表格时,按以下格式调用函数即可。
=降维函数(源表,{"年","季度","月份"},{"地区","产品种类","产品名称"},"销售额")
降维函数适用于任意NxM层级结构化表格,对于1x1,2x1,2x3等层级的结构化表格同样使用。

相关学习资料