适用于 Python 程序员的 Power BI 的 Power Query (M)
概述
自2019 年 4 月以来,Python 一直是 Power BI 的一部分。这在理论上很棒。 Python 是一种伟大的语言,以其在数据科学界的突出地位而闻名。它有各种各样的工具来执行数据整理、计算、可视化等等!
这在实践中也很棒。具有预先存在的 Python 代码的分析师将有一个相对容易的时间来加入 Power BI,更不用说 Python 带来的开发时间的轻松。但是,将两个不同的堆栈放在一起通常会遇到很多障碍。它可以是技术的、组织的、文化的、基础设施相关的,或者任何你想分类的东西。重点是,用户总是不可避免地会选择软件的原生工具。 (是的微软,我们很多人仍然在 VBA 中编写代码)。
在这篇文章中,我将尝试整理一份 Python 程序员(例如,我)会感兴趣的 Power Query (M) 功能的“备忘单”。(作为免责声明,我也是这方面的新手)。
Power Query (M) 和 DAX
PowerBI 带有两种内置语言:Power Query 和 DAX(数据分析表达式)。
DAX 在_主页 > 计算_ 功能区中可用。最好在数据视图(在窗口的左侧,以及报表视图和模型视图)上执行此操作以解锁新列选项。这是一个示例 DAX:
Revenue = [Sales] * [PricePerUnit]
进入全屏模式 退出全屏模式
此 DAX 表达式创建一个名为Revenue的新列,它是Sales列和ProductPerUnit列的乘积。 Excel 用户应该对这个操作相当熟悉。
另一方面,Power Query (M) 在 Power Query 编辑器中可用,您可以在 Home > Queries > Transform Data 中启动它。在 Power Query 编辑器中,您还可以通过 Home > Query > Advance Editor 启动 Advance Editor。
M是 Power Query 背后的公式语言 (i.e.,let...in)。您在 Power Query GUI 中执行的操作在幕后转换为M。幸运的是,就搜索引擎而言,两者几乎可以互换使用。
这是一个示例M代码:
let
src = Table.FromList({
"Foo", "Spam", "Bar", "Ham", "Baz"
}),
output = Table.SelectRows(
src,
each ([Column1] = "Spam")
)
in
output
进入全屏模式 退出全屏模式
该片段显示了两个_steps_:步骤src启动表和步骤output过滤所需值。这种逐步的数据转换是大多数程序员所熟悉的。
Power Query 和 DAX 的能力肯定会有重叠。当然,一个功能在另一个功能中会更容易,反之亦然。但归根结底,这一切都归结为偏好。
这两个视频都是介绍M的精彩资源。两位资源人员都来自 Power BI 客户咨询团队。我敦促每个人至少观看两个视频的前 5 或 10 分钟,这样我们就可以了解一些基础知识。
Power BI 中的 M 简介 - Chris Webb
Power BI 开发营三月 M 编程简介
话不多说,直接进入正文吧!
备忘单:常用类型和操作
蟒蛇 3
米
评论
# Comments
//single-line和/* multi-line*/
42
42
-42
-42
+42
+42
--42
--42
不是 42 # 错误
M 没有真实值
不是 0 # 真
M 没有虚假值
42 u003du003d 42
42 u003d 42
5 + 2
5 + 2
5 - 2
5 - 2
5 * 2
5 * 2
4 / 3
4 / 3
两者都是 1.3333333333333333
2 // 3
M中没有原生楼层划分,但 DAX 有FLOOR
'Hello World'
"Hello World"
M字符串字面量是严格的引号"
'Hello ' + 'World!'
"Hello " & "World!"
'HeLLo wOrLd'.upper()
Text.Upper("HeLLo wOrLd")
结果是HELLO WORLD
'HeLLo wOrLd'.lower()
Text.Lower("HeLLo wOrLd")
结果是hello world
zoz100057
Text.Contains("Hello World", "Wo")
'len('Hello World')
Text.Length("Hello World")
['Foo', 'Bar']
{ "Foo", "Bar" }
['Foo', 'Bar'] + ['Spam', 'Ham']
{ "Foo", "Bar" } & { "Spam", "Ham" }
['Foo', 'Bar', 'Baz'].pop()
List.RemoveLastN({ "Foo", "Bar", "Baz" })
Python 的list.pop修改列表但返回删除的元素。 M 的List.RemoveLastN返回结果列表。
zoz100069
{ 0 .. 9}
Python 的range是一个生成器,而不是一个列表。
range(1,11)
{ 1 .. 10}
这不是一个完整的列表,但希望它足以让中级 Python 用户了解 Python 的数据模型与 M 之间的细微差别。
-
文档:M中的文本函数
-
文档:列出 M 中的函数
备忘单:是
Python 的is运算符评估两个对象是否引用同一个对象。
示例 Python 代码:
a = {}
b = {}
c = a
a == b # True, both are empty dictionaries
a is b # False, both are separately initialized dictionary.
c is a # True, c refers to the same dictionary as a
进入全屏模式 退出全屏模式
它有细微差别,但这应该说明这一点。
M的is算子就完全不一样了。在 M 中,is用于检查类型一致性。
示例 M 代码:
42 is number //TRUE
进入全屏模式 退出全屏模式
备忘单:记录和表格
Python 没有 Record 或 Table 的本机实现。
Record很可能受到数据库术语的启发。它采用[Name="Seinfeld", Age=33]的形式。
乍一看,Record看起来像 Pythondict(因为它具有键值对),但 Python dict 中的键必须是已经定义的。它看起来也类似于namedtuple,但必须首先指定命名元组的模式(请注意,尽管从 Python 3.7 开始添加了默认值);Record没有这样的限制。
用 Python 实现的 Record 肯定是这样的:
class Record:
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
jerry = Record(Name='Seinfeld', Age='33')
print(jerry.Name) # Seinfeld
print(jerry.Age) # 33
进入全屏模式 退出全屏模式
感谢pandas之类的库,Python 用户确实可以选择处理二维数据。
表绝对是 Power Query 中最突出的数据类型。
- 文档:M中的表函数
我们不会介绍所有可用的方法,但需要注意的一个好特性是它有相当多的类方法可用于实例化表。这是一个例子。
let
output = Table.FromRecords({
[Name="Jeff Winger", Age=27],
[Name="Britta Perry", Age=28]
})
in
output
进入全屏模式 退出全屏模式
备忘单:函数
Python 中的函数可以(通常)使用def关键字创建,也可以使用lambda匿名创建。
例如:
def add(addend1, addend2):
return addend1 + addend2
print(add(4,2)) # 6
add_lambda = lambda addend1, addend2: addend1 + addend2
print(add_lambda(4,2)) # 6
进入全屏模式 退出全屏模式
在M中定义函数类似于 JS (welp,有一个箭头)。M中的函数可以在单独的查询中分配,也可以在变量中分配。
(addend1, addend2) => addend1 + addend2
进入全屏模式 退出全屏模式
据我所知,M没有列表理解或map,但本机类型应该有足够的转换方法。
示例:返回一个包含 0 到 9 数字平方的列表。
Python:
numbers = list(range(10))
def square(n):
return n ** 2
# via comprehension
squares_comprehension = [ square(i) for i in numbers ]
# via map
squares_map = list(map(square, numbers))
进入全屏模式 退出全屏模式
在M中,翻译为:
let
numbers = { 0 .. 9 },
square = (n) => Number.Power(n,2),
squares_list = List.Transform(numbers, square)
in
squares_list
进入全屏模式 退出全屏模式
备忘单:下划线 (_) 和每个
下划线 (_) 和each都是一元函数(只有一个参数的函数)的语法糖。以上面的代码示例为例。
square = (n) => Number.Power(n,2)
进入全屏模式 退出全屏模式
square是一个函数,它接受参数n并在n时返回平方。可以用下划线代替n。这通常在匿名传递函数时很常见。
例如,上面的代码可以重写为:
List.Transform(
{ 0 .. 9},
(_) => Number.Power(_,2)
)
进入全屏模式 退出全屏模式
还可以进一步简化使用each关键字
List.Transform(
{ 0 .. 9},
each Number.Power(_,2)
)
进入全屏模式 退出全屏模式
请注意,下划线可以代表任何数据类型。
let
src = Table.FromRecords({
[Name="Foo"],
[Name="Bar"],
[Name="Baz"],
[Name="Spam"],
[Name="Ham"]
}),
out = Table.SelectRows(
src,
each Text.StartsWith([Name], "B") // (_) => Text.StartsWith(_[Name], "B")
)
in
out
进入全屏模式 退出全屏模式
备忘单:输入 M
M可以强类型。以下面的代码为例。
let
add = (addend1, addend2) => try addend1 + addend2 otherwise addend1 & addend2,
output = add("1", "2")
in
output
进入全屏模式 退出全屏模式
在这个例子中,我们将文本类型"1"和"2"传递给我们的自定义函数add。如果可能,函数add将尝试添加两个参数,否则,它将尝试连接..M不会将大小写"1"和"2"输入数字类型。因此,结果将是 be"12"(文本)。
可以通过指定函数预期获得的类型来修改函数。
let
add = (addend1 as number, addend2 as number) => try addend1 + addend2 otherwise addend1 & addend2,
output = add("1", "2")
in
output
进入全屏模式 退出全屏模式
上面的代码会抛出一个错误。
在创建自定义表时也可以定义某种模式。
let
schema = type [Name=text, Age=number],
my_table = type table schema,
output = #table(
my_table,
{
{"Jeff Winger", 27},
{"Britta Perry", 28}
}
)
in
output
进入全屏模式 退出全屏模式
与前面使用Table.FromRecords实例化表的示例不同,此方法不需要用户键入每个项目的属性。
结论
Power BI 是一个很棒的软件,Python 程序员可以将它添加到他们的工具库中。它的其中一个工具M是一种成熟的查询语言,可以与pandas等 Python 包完全匹配。
编辑
社区贡献:
感谢 u/MonkeyNin 在 r/PowerBI](https://www.reddit.com/r/PowerBI/comments/r8qyuz/power_bis_power_query_m_for_python_programmers/)上贡献了一些主题[。您可以参考他们的gist,其中涵盖了其他主题,例如选择和投影运算符等等!
更多推荐

所有评论(0)