Power BI 中的多元线性回归
Multiple Linear Regression in Power BI
假设我有一组 returns,我想计算其相对于不同市场指数的 beta 值。为了有一个具体的例子,让我们在名为 Returns
的 table 中使用以下数据集:
Date Equity Duration Credit Manager
-----------------------------------------------
01/31/2017 2.907% 0.226% 1.240% 1.78%
02/28/2017 2.513% 0.493% 1.120% 3.88%
03/31/2017 1.346% -0.046% -0.250% 0.13%
04/30/2017 1.612% 0.695% 0.620% 1.04%
05/31/2017 2.209% 0.653% 0.480% 1.40%
06/30/2017 0.796% -0.162% 0.350% 0.63%
07/31/2017 2.733% 0.167% 0.830% 2.06%
08/31/2017 0.401% 1.083% -0.670% 0.29%
09/30/2017 1.880% -0.857% 1.430% 2.04%
10/31/2017 2.151% -0.121% 0.510% 2.33%
11/30/2017 2.020% -0.137% -0.020% 3.06%
12/31/2017 1.454% 0.309% 0.230% 1.28%
现在 Excel,我可以只使用 LINEST
函数来获取 beta 值:
= LINEST(Returns[Manager], Returns[[Equity]:[Credit]], TRUE, TRUE)
它吐出一个如下所示的数组:
0.077250253 -0.184974002 0.961578127 -0.001063971
0.707796954 0.60202895 0.540811546 0.008257129
0.50202386 0.009166729 #N/A #N/A
2.688342242 8 #N/A #N/A
0.000677695 0.000672231 #N/A #N/A
Beta 位于顶行,使用它们可以得到以下线性估计:
Manager = 0.962 * Equity - 0.185 * Duration + 0.077 * Credit - 0.001
问题是如何使用 DAX 在 Power BI 中获取这些值(最好不必编写自定义 R 脚本)?
对于simple linear regression against one column, I can go back to the mathematical definition and write a least squares implementation similar to the one given in this post。
然而,当涉及到更多的列时(我需要能够处理多达 12 列,但并不总是相同的数字),这很快就会变得混乱,我希望有更好的方法。
由于 Power BI 中 LINEST
函数没有等效或方便的替代品(我相信您在发布问题之前已经做了足够的研究),任何尝试都意味着在 Power 中重写整个函数Query/M,对于简单线性回归的情况已经不是"simple",更不用说多变量了
与其(重新)发明轮子,不如在 Power BI 中使用 R 脚本更容易(one-liner 代码..)。
考虑到我之前没有 R 经验,这不是一个糟糕的选择。经过几次搜索 trial-and-error,我得出以下结论:
# 'dataset' holds the input data for this script
# install.packages("broom") # uncomment to install if package does not exist
library(broom)
model <- lm(Manager ~ Equity + Duration + Credit, dataset)
model <- tidy(model)
lm
是 Power BI 的 built-in linear model function from R, and the tidy
function comes with the broom
package, which 。
对于 term
和 estimate
列,这应该足以计算出您想要的估计值。
M查询供您参考:
let
Source = Csv.Document(File.Contents("returns.csv"),[Delimiter=",", Columns=5, Encoding=1252, QuoteStyle=QuoteStyle.None]),
#"Promoted Headers" = Table.PromoteHeaders(Source, [PromoteAllScalars=true]),
#"Changed Type" = Table.TransformColumnTypes(#"Promoted Headers",{{"Date", type text}, {"Equity", Percentage.Type}, {"Duration", Percentage.Type}, {"Credit", Percentage.Type}, {"Manager", Percentage.Type}}),
#"Run R Script" = R.Execute("# 'dataset' holds the input data for this script#(lf)# install.packages(""broom"")#(lf)library(broom)#(lf)#(lf)model <- lm(Manager ~ Equity + Duration + Credit, dataset)#(lf)model <- tidy(model)",[dataset=#"Changed Type"]),
#"""model""" = #"Run R Script"{[Name="model"]}[Value]
in
#"""model"""
精华:
DAX 不是正确的选择。使用 Home > Edit Queries
,然后使用 Transform > Run R Script
。使用 table 中的所有可用变量将以下 R 片段插入 运行 回归分析:
model <- lm(Manager ~ . , dataset)
df<- data.frame(coef(model))
names(df)[names(df)=="coef.model."] <- "coefficients"
df['variables'] <- row.names(df)
将 Manager
编辑为任何其他可用变量名称以更改因变量。
详情:
好问题!为什么微软没有推出更灵活的解决方案是我无法理解的。但目前,如果不在 Power BI 中使用 R,您将无法找到非常好的方法。
因此,我建议的方法将忽略您关于以下方面的请求:
The question is how can I get these values in Power BI using DAX
(preferably without having to write a custom R script)?
但是我的回答将满足您关于以下方面的要求:
A good answer should generalize to more than 3 columns (probably by
working on an unpivoted data table with the indices as values rather
than column headers).
我们开始:
我在一个使用逗号作为小数分隔符的系统上,所以我将使用以下作为数据源(如果您将数字直接复制到 Power BI 中,将不会保持列分隔. 如果您先将其粘贴到 Excel,再复制一次,然后将其粘贴到 Power BI,列就可以了):
Date Equity Duration Credit Manager
31.01.2017 2,907 0,226 1,24 1,78
28.02.2017 2,513 0,493 1,12 3,88
31.03.2017 1,346 -0,046 -0,25 0,13
30.04.2017 1,612 0,695 0,62 1,04
31.05.2017 2,209 0,653 0,48 1,4
30.06.2017 0,796 -0,162 0,35 0,63
31.07.2017 2,733 0,167 0,83 2,06
31.08.2017 0,401 1,083 -0,67 0,29
30.09.2017 1,88 -0,857 1,43 2,04
31.10.2017 2,151 -0,121 0,51 2,33
30.11.2017 2,02 -0,137 -0,02 3,06
31.12.2017 1,454 0,309 0,23 1,28
在 Power BI 中从头开始(为了重现性目的)我使用 Enter Data
插入数据:
现在,转到 Edit Queries > Edit Queries
并检查您是否有:
为了在分析中包含的列数方面保持灵活性,我发现最好删除 Date 列。这不会对您的回归结果产生影响。只需 right-click 日期列和 select Remove
:
请注意,这将在 Query Settings > Applied Steps
>:
下添加一个新步骤
在这里您可以编辑我们将要使用的几行 R 代码。现在,转到 Transform > Run R Script
打开这个 window:
注意行 # 'dataset' holds the input data for this script
。值得庆幸的是,您的问题只是关于一个输入 table,所以事情不会变得太复杂(对于多个输入 table 请查看 )。 数据集变量是R中data.frame形式的变量,是进一步分析的一个很好的(唯一的..)起点。
插入以下脚本:
model <- lm(Manager ~ . , dataset)
df<- data.frame(coef(model))
names(df)[names(df)=="coef.model."] <- "coefficients"
df['variables'] <- row.names(df)
单击 OK
,如果一切顺利,您应该得到以下结果:
点击Table
,你会得到这个:
在 Applied Steps
下,您会看到已插入 Run R Script
步骤。点击右边的星号(齿轮?)进行编辑,或者点击df
格式化输出table.
就是这样! 至少对于 编辑查询 部分。
单击 Home > Close & Apply
返回 Power BI 报告部分并确认您在 Visualizations > Fields
下有一个新的 table:
插入一个 Table 或矩阵并激活系数和变量得到这个:
希望这就是您要找的!
现在了解有关 R 脚本的一些详细信息:
只要可能,我就会避免使用大量不同的 R 库。这样您就可以降低依赖性问题的风险。
函数 lm()
处理回归分析。在解释变量的数量方面获得所需灵活性的关键在于 Manager ~ . , dataset
部分。这只是对 运行 数据框 dataset
中的 Manager
变量进行回归分析,并使用所有剩余列 ~ .
作为解释变量。 coef(model)
部分从估计模型中提取系数值。结果是一个数据框,其中变量名称作为行名称。最后一行只是将这些名称添加到数据框本身。
我已经弄清楚如何专门针对三个变量执行此操作,但这种方法根本不会放大或缩小到更多或更少的变量。
Regression =
VAR ShortNames =
SELECTCOLUMNS (
Returns,
"A", [Equity],
"D", [Duration],
"C", [Credit],
"Y", [Manager]
)
VAR n = COUNTROWS ( ShortNames )
VAR A = SUMX ( ShortNames, [A] )
VAR D = SUMX ( ShortNames, [D] )
VAR C = SUMX ( ShortNames, [C] )
VAR Y = SUMX ( ShortNames, [Y] )
VAR AA = SUMX ( ShortNames, [A] * [A] ) - A * A / n
VAR DD = SUMX ( ShortNames, [D] * [D] ) - D * D / n
VAR CC = SUMX ( ShortNames, [C] * [C] ) - C * C / n
VAR AD = SUMX ( ShortNames, [A] * [D] ) - A * D / n
VAR AC = SUMX ( ShortNames, [A] * [C] ) - A * C / n
VAR DC = SUMX ( ShortNames, [D] * [C] ) - D * C / n
VAR AY = SUMX ( ShortNames, [A] * [Y] ) - A * Y / n
VAR DY = SUMX ( ShortNames, [D] * [Y] ) - D * Y / n
VAR CY = SUMX ( ShortNames, [C] * [Y] ) - C * Y / n
VAR BetaA =
DIVIDE (
AY*DC*DC - AD*CY*DC - AY*CC*DD + AC*CY*DD + AD*CC*DY - AC*DC*DY,
AD*CC*AD - AC*DC*AD - AD*AC*DC + AA*DC*DC + AC*AC*DD - AA*CC*DD
)
VAR BetaD =
DIVIDE (
AY*CC*AD - AC*CY*AD - AY*AC*DC + AA*CY*DC + AC*AC*DY - AA*CC*DY,
AD*CC*AD - AC*DC*AD - AD*AC*DC + AA*DC*DC + AC*AC*DD - AA*CC*DD
)
VAR BetaC =
DIVIDE (
- AY*DC*AD + AD*CY*AD + AY*AC*DD - AA*CY*DD - AD*AC*DY + AA*DC*DY,
AD*CC*AD - AC*DC*AD - AD*AC*DC + AA*DC*DC + AC*AC*DD - AA*CC*DD
)
VAR Intercept =
AVERAGEX ( ShortNames, [Y] )
- AVERAGEX ( ShortNames, [A] ) * BetaA
- AVERAGEX ( ShortNames, [D] ) * BetaD
- AVERAGEX ( ShortNames, [C] ) * BetaC
RETURN
{ BetaA, BetaD, BetaC, Intercept }
这是计算出来的 table returns 指定的回归系数:
这些数字与所提供数据的 LINEST 输出相匹配。
注意:我在问题中引用的 LINEST 值与这些值略有不同,因为它们是根据未四舍五入的 returns 而不是问题中提供的四舍五入的 returns 计算的。
我参考了 this document 的计算设置和 Mathematica 来求解系统:
假设我有一组 returns,我想计算其相对于不同市场指数的 beta 值。为了有一个具体的例子,让我们在名为 Returns
的 table 中使用以下数据集:
Date Equity Duration Credit Manager
-----------------------------------------------
01/31/2017 2.907% 0.226% 1.240% 1.78%
02/28/2017 2.513% 0.493% 1.120% 3.88%
03/31/2017 1.346% -0.046% -0.250% 0.13%
04/30/2017 1.612% 0.695% 0.620% 1.04%
05/31/2017 2.209% 0.653% 0.480% 1.40%
06/30/2017 0.796% -0.162% 0.350% 0.63%
07/31/2017 2.733% 0.167% 0.830% 2.06%
08/31/2017 0.401% 1.083% -0.670% 0.29%
09/30/2017 1.880% -0.857% 1.430% 2.04%
10/31/2017 2.151% -0.121% 0.510% 2.33%
11/30/2017 2.020% -0.137% -0.020% 3.06%
12/31/2017 1.454% 0.309% 0.230% 1.28%
现在 Excel,我可以只使用 LINEST
函数来获取 beta 值:
= LINEST(Returns[Manager], Returns[[Equity]:[Credit]], TRUE, TRUE)
它吐出一个如下所示的数组:
0.077250253 -0.184974002 0.961578127 -0.001063971
0.707796954 0.60202895 0.540811546 0.008257129
0.50202386 0.009166729 #N/A #N/A
2.688342242 8 #N/A #N/A
0.000677695 0.000672231 #N/A #N/A
Beta 位于顶行,使用它们可以得到以下线性估计:
Manager = 0.962 * Equity - 0.185 * Duration + 0.077 * Credit - 0.001
问题是如何使用 DAX 在 Power BI 中获取这些值(最好不必编写自定义 R 脚本)?
对于simple linear regression against one column, I can go back to the mathematical definition and write a least squares implementation similar to the one given in this post。
然而,当涉及到更多的列时(我需要能够处理多达 12 列,但并不总是相同的数字),这很快就会变得混乱,我希望有更好的方法。
由于 Power BI 中 LINEST
函数没有等效或方便的替代品(我相信您在发布问题之前已经做了足够的研究),任何尝试都意味着在 Power 中重写整个函数Query/M,对于简单线性回归的情况已经不是"simple",更不用说多变量了
与其(重新)发明轮子,不如在 Power BI 中使用 R 脚本更容易(one-liner 代码..)。
考虑到我之前没有 R 经验,这不是一个糟糕的选择。经过几次搜索 trial-and-error,我得出以下结论:
# 'dataset' holds the input data for this script
# install.packages("broom") # uncomment to install if package does not exist
library(broom)
model <- lm(Manager ~ Equity + Duration + Credit, dataset)
model <- tidy(model)
lm
是 Power BI 的 built-in linear model function from R, and the tidy
function comes with the broom
package, which
对于 term
和 estimate
列,这应该足以计算出您想要的估计值。
M查询供您参考:
let
Source = Csv.Document(File.Contents("returns.csv"),[Delimiter=",", Columns=5, Encoding=1252, QuoteStyle=QuoteStyle.None]),
#"Promoted Headers" = Table.PromoteHeaders(Source, [PromoteAllScalars=true]),
#"Changed Type" = Table.TransformColumnTypes(#"Promoted Headers",{{"Date", type text}, {"Equity", Percentage.Type}, {"Duration", Percentage.Type}, {"Credit", Percentage.Type}, {"Manager", Percentage.Type}}),
#"Run R Script" = R.Execute("# 'dataset' holds the input data for this script#(lf)# install.packages(""broom"")#(lf)library(broom)#(lf)#(lf)model <- lm(Manager ~ Equity + Duration + Credit, dataset)#(lf)model <- tidy(model)",[dataset=#"Changed Type"]),
#"""model""" = #"Run R Script"{[Name="model"]}[Value]
in
#"""model"""
精华:
DAX 不是正确的选择。使用 Home > Edit Queries
,然后使用 Transform > Run R Script
。使用 table 中的所有可用变量将以下 R 片段插入 运行 回归分析:
model <- lm(Manager ~ . , dataset)
df<- data.frame(coef(model))
names(df)[names(df)=="coef.model."] <- "coefficients"
df['variables'] <- row.names(df)
将 Manager
编辑为任何其他可用变量名称以更改因变量。
详情:
好问题!为什么微软没有推出更灵活的解决方案是我无法理解的。但目前,如果不在 Power BI 中使用 R,您将无法找到非常好的方法。
因此,我建议的方法将忽略您关于以下方面的请求:
The question is how can I get these values in Power BI using DAX (preferably without having to write a custom R script)?
但是我的回答将满足您关于以下方面的要求:
A good answer should generalize to more than 3 columns (probably by working on an unpivoted data table with the indices as values rather than column headers).
我们开始:
我在一个使用逗号作为小数分隔符的系统上,所以我将使用以下作为数据源(如果您将数字直接复制到 Power BI 中,将不会保持列分隔. 如果您先将其粘贴到 Excel,再复制一次,然后将其粘贴到 Power BI,列就可以了):
Date Equity Duration Credit Manager
31.01.2017 2,907 0,226 1,24 1,78
28.02.2017 2,513 0,493 1,12 3,88
31.03.2017 1,346 -0,046 -0,25 0,13
30.04.2017 1,612 0,695 0,62 1,04
31.05.2017 2,209 0,653 0,48 1,4
30.06.2017 0,796 -0,162 0,35 0,63
31.07.2017 2,733 0,167 0,83 2,06
31.08.2017 0,401 1,083 -0,67 0,29
30.09.2017 1,88 -0,857 1,43 2,04
31.10.2017 2,151 -0,121 0,51 2,33
30.11.2017 2,02 -0,137 -0,02 3,06
31.12.2017 1,454 0,309 0,23 1,28
在 Power BI 中从头开始(为了重现性目的)我使用 Enter Data
插入数据:
现在,转到 Edit Queries > Edit Queries
并检查您是否有:
为了在分析中包含的列数方面保持灵活性,我发现最好删除 Date 列。这不会对您的回归结果产生影响。只需 right-click 日期列和 select Remove
:
请注意,这将在 Query Settings > Applied Steps
>:
在这里您可以编辑我们将要使用的几行 R 代码。现在,转到 Transform > Run R Script
打开这个 window:
注意行 # 'dataset' holds the input data for this script
。值得庆幸的是,您的问题只是关于一个输入 table,所以事情不会变得太复杂(对于多个输入 table 请查看
插入以下脚本:
model <- lm(Manager ~ . , dataset)
df<- data.frame(coef(model))
names(df)[names(df)=="coef.model."] <- "coefficients"
df['variables'] <- row.names(df)
单击 OK
,如果一切顺利,您应该得到以下结果:
点击Table
,你会得到这个:
在 Applied Steps
下,您会看到已插入 Run R Script
步骤。点击右边的星号(齿轮?)进行编辑,或者点击df
格式化输出table.
就是这样! 至少对于 编辑查询 部分。
单击 Home > Close & Apply
返回 Power BI 报告部分并确认您在 Visualizations > Fields
下有一个新的 table:
插入一个 Table 或矩阵并激活系数和变量得到这个:
希望这就是您要找的!
现在了解有关 R 脚本的一些详细信息:
只要可能,我就会避免使用大量不同的 R 库。这样您就可以降低依赖性问题的风险。
函数 lm()
处理回归分析。在解释变量的数量方面获得所需灵活性的关键在于 Manager ~ . , dataset
部分。这只是对 运行 数据框 dataset
中的 Manager
变量进行回归分析,并使用所有剩余列 ~ .
作为解释变量。 coef(model)
部分从估计模型中提取系数值。结果是一个数据框,其中变量名称作为行名称。最后一行只是将这些名称添加到数据框本身。
我已经弄清楚如何专门针对三个变量执行此操作,但这种方法根本不会放大或缩小到更多或更少的变量。
Regression =
VAR ShortNames =
SELECTCOLUMNS (
Returns,
"A", [Equity],
"D", [Duration],
"C", [Credit],
"Y", [Manager]
)
VAR n = COUNTROWS ( ShortNames )
VAR A = SUMX ( ShortNames, [A] )
VAR D = SUMX ( ShortNames, [D] )
VAR C = SUMX ( ShortNames, [C] )
VAR Y = SUMX ( ShortNames, [Y] )
VAR AA = SUMX ( ShortNames, [A] * [A] ) - A * A / n
VAR DD = SUMX ( ShortNames, [D] * [D] ) - D * D / n
VAR CC = SUMX ( ShortNames, [C] * [C] ) - C * C / n
VAR AD = SUMX ( ShortNames, [A] * [D] ) - A * D / n
VAR AC = SUMX ( ShortNames, [A] * [C] ) - A * C / n
VAR DC = SUMX ( ShortNames, [D] * [C] ) - D * C / n
VAR AY = SUMX ( ShortNames, [A] * [Y] ) - A * Y / n
VAR DY = SUMX ( ShortNames, [D] * [Y] ) - D * Y / n
VAR CY = SUMX ( ShortNames, [C] * [Y] ) - C * Y / n
VAR BetaA =
DIVIDE (
AY*DC*DC - AD*CY*DC - AY*CC*DD + AC*CY*DD + AD*CC*DY - AC*DC*DY,
AD*CC*AD - AC*DC*AD - AD*AC*DC + AA*DC*DC + AC*AC*DD - AA*CC*DD
)
VAR BetaD =
DIVIDE (
AY*CC*AD - AC*CY*AD - AY*AC*DC + AA*CY*DC + AC*AC*DY - AA*CC*DY,
AD*CC*AD - AC*DC*AD - AD*AC*DC + AA*DC*DC + AC*AC*DD - AA*CC*DD
)
VAR BetaC =
DIVIDE (
- AY*DC*AD + AD*CY*AD + AY*AC*DD - AA*CY*DD - AD*AC*DY + AA*DC*DY,
AD*CC*AD - AC*DC*AD - AD*AC*DC + AA*DC*DC + AC*AC*DD - AA*CC*DD
)
VAR Intercept =
AVERAGEX ( ShortNames, [Y] )
- AVERAGEX ( ShortNames, [A] ) * BetaA
- AVERAGEX ( ShortNames, [D] ) * BetaD
- AVERAGEX ( ShortNames, [C] ) * BetaC
RETURN
{ BetaA, BetaD, BetaC, Intercept }
这是计算出来的 table returns 指定的回归系数:
这些数字与所提供数据的 LINEST 输出相匹配。
注意:我在问题中引用的 LINEST 值与这些值略有不同,因为它们是根据未四舍五入的 returns 而不是问题中提供的四舍五入的 returns 计算的。
我参考了 this document 的计算设置和 Mathematica 来求解系统: