我要统计各媒体的投放数据,就找管后台的小朋友要一下数据,然后,他给我发来了这个表:
作为懒人,最简单的办法是分别剪切空列分隔开的后面两个数据块,然后粘贴到第一个数据块下,再用筛选大法剔除无关紧要的数据,再用数据透视表拉出各媒体的汇总数据即可。
但作为懒人中的懒人+处女座,我拿到这个表就想以后我要是天天遇到这种表、而且里边有几十个几百个这样的,我怎么办?
答案还是要祭出微软出品的数据处理神器PowerQuery。
分析表结构
对数据源进行分析后发现,要感谢同事小朋友用两个空列把数据分成了三个数据块。要是没有这两个用来分隔的空列,想哭都哭不出了。
所以,有了这两个分隔列把数据分成三块之后,我们就可以在PowerQuery中,借助剪切粘贴一样的思路,将第二、三个数据块追加到第一个数据块之后,然后再剔除不需要的行,即可。
引入数据源
第一步是引入数据源:
= Excel.Workbook(File.Contents("C:UserswanghtDesktop统计.xlsx"), null, true)
= 源{[Item="Sheet0",Kind="Sheet"]}[Data]
得到的结果是一个超级宽的表:
得到三个数据块
这是最关键的一步。这时我发现用作分隔符的空列影响了后续操作,所以需要将其剔除。一种办法是直接过滤column5和column10。但这类似于硬编码,所以我选择了另外一种方式。
我利用最后得到的数据列名称不包括“Column”这个单词的方式来动态过滤分隔列,即剔除第一行,然后把原来的第二行作为标题:
= Table.Skip(Sheet0_Sheet,1)
= Table.PromoteHeaders(删除的顶端行, [PromoteAllScalars=true])
然后在此基础上剔除用作分隔符的空列:
= Table.SelectColumns(提升的标题,List.Select(Table.ColumnNames(提升的标题),each Text.Start(_,6)<>"Column"))
接下来,就可以直接用Table.SelectColumns()函数来分别获得三个数据块,然后将其合并:
= Table.Combine({Table.DemoteHeaders(Table.SelectColumns(自定义1,List.Range(Table.ColumnNames(自定义1),0,4))),Table.DemoteHeaders(Table.SelectColumns(自定义1,List.Range(Table.ColumnNames(自定义1),4,4))),Table.DemoteHeaders(Table.SelectColumns(自定义1,List.Range(Table.ColumnNames(自定义1),8,4)))})
注意代码中我用了Table.DemoteHeaders()函数,如果不使用这个函数将标题降级,那么我们合并后的表格还是12列,并且三个数据块彼此是错位的。因为每个数据块的列名称都不一样。通过将每个数据块的标题降级后,就让三个数据块的列标题都变成了Column1,Column2,Column3和Column4这样的。
由于这三个数据块的结构一模一样,只是List.Range()函数的第二个参数不一样,所以我猜测可以用List.Generate()函数一步生成三个数据块,可惜我还没掌握这个函数,所以这里又不得不采取了硬编码的方式,是个遗憾。
得到的结果如下:
提升合并后的表格标题并剔除空行
通过前面的步骤,我们将需要的数据制作成了一个窄表格,该表格的列数就等于最后我们需要获取的数据的列数,列标题和我们要获取的数据的列标题一样。
接下来筛选掉空行。通过观察可以发现,直接在“展现”、“点击”或“点击率”来筛选空行效率是最高的。这样不仅剔除了空行,还剔除了我们不需要的客户名称。
= Table.PromoteHeaders(自定义2, [PromoteAllScalars=true])
= Table.SelectRows(提升的标题1, each ([展现] <> null))
得到的结果是这样:
剔除多余的标题行
上一步完成后,我们发现还多了标题行。去除多余的标题行的最佳办法并不是在第一列筛选“媒体名称”,因为这其实还是硬编码方法。最佳办法是更改“展现”、“点击”或“点击率”列的格式,将其变为整数或小数格式,这样一来,包含文本的行会报错,然后删除错误行即可:
= Table.TransformColumnTypes(筛选的行,{{"点击", Int64.Type}})
= Table.RemoveRowsWithErrors(更改的类型4, {"点击"})
最后的处理
删除不需要的行,根据需要进行其他处理,比如我删除了点击率,根据媒体进行分组,分别对展现和点击求和:
= Table.RemoveColumns(删除的错误,{"点击率"})
= Table.Group(删除的列, {"媒体名称"}, {{"展现", each List.Sum([展现]), type number}, {"点击", each List.Sum([点击]), type number}})
反思
这个例子,如果分布在一张sheet中的数据是以表格方式存在:
处理起来就没有难度:将原始文件放到单独的文件夹中,然后用PowerQuery引入一个来自于文件夹的源,即可处理(不推荐引入来自文件的源,有兴趣的可以试试看)。
如果原始文件没有那两个空列把数据分成三块,处理起来也非常麻烦,估计要用vba来判定每一个数据块的边界。
最后,寻找三个数据块时,由于我对List.Generate()函数不熟,因此还是采取了硬编码的方式,是一个比较大的遗憾。
结语
这个例子因为是纯PowerQuery操作,比较偏门,估计有不少人不明觉厉。但如果您觉得这个帖子对您有用,还是欢迎转发、收藏、评论或关注。如果您能给出Table.Gernerate()函数实现三个数据块的自动获取,我将不胜感激。
网友评论