SQL 服务器等效于 Excel 的 TINV 函数
SQL Server equivalent of Excel's TINV function
我正在尝试寻找 X 的 t 分布的双尾逆。可以在 Excel 中使用 TINV 函数找到它,但我需要在 SQL 服务器中实现它。请给我建议。
TINV 函数语法具有以下参数:
概率:与双尾学生 t 分布相关的概率。
Deg_freedom :表征分布的自由度数。
例如:
select tinv( 0.054645, 60);
-- -----------------
-- 1.9599994129833
-- (1 row returned)
您可以将自己的实现编写为 SQL 函数,或者使用 CLR 并用 C# 编写。
我的建议是使用 CLR 并包含 Accord 库(我推荐这个库,因为它们仍然有 .NET 3.5 版本,SQL 服务器 CLR 需要这些版本)实现统计功能。我在过去的其他统计计算中也这样做过,效果非常好。
SQL-服务器没有加入很多统计功能。
tinv
不存在于 SQL-服务器中。
添加 tinv 函数的唯一方法是使用 CLR 函数。
因此,问题本身减少为 "How do I calculate tinv with the subset of C# allowed in SQL-Server ?"。
如果您使用的是 .NET 4.0,则可以使用 System.Web.DataVisualization.dll
中的图表-class
例如
var someChart = new System.Web.UI.DataVisualization.Charting.Chart();
double res = someChart.DataManipulator.Statistics.InverseTDistribution(.05, 15);
//2.131449546
但是,您可能不希望这种开销。
因此,您必须将其从 Math.NET 的源代码(MIT/X11 许可证)中删除。
StudentT dist = new StudentT(0.0,1.0,7.0);
double prob = dist.CumulativeDistribution(1.8946);
结果应该是 0.95
既然你需要逆,你就需要
StudentT.InvCDF(double location, double scale, double freedom, double p)
location:分布的位置(μ)。
尺度:分布的尺度 (σ)。范围:σ > 0。
自由度:分布的自由度 (ν)。范围:ν > 0.
p:计算逆累积密度的位置。
[Microsoft.SqlServer.Server.SqlFunction]
public static System.Data.SqlTypes.SqlDouble TInv(double probability, int degFreedom)
{
double result = 0.00;
try
{
result = fnInverseTDistribution(degFreedom, probability);
}
catch
{
// throw; // Optionally throw/log/ignore/whatever
}
return result;
}
使用 DataVisualization,它是这样的:
[Microsoft.SqlServer.Server.SqlFunction]
public static System.Data.SqlTypes.SqlDouble TInv(double probability, int degFreedom)
{
double result = 0.00;
try
{
var someChart = new System.Web.UI.DataVisualization.Charting.Chart();
result = someChart.DataManipulator.Statistics.InverseTDistribution( probability, degFreedom);
}
catch
{
// throw; // Optionally throw/log/ignore/whatever
}
return result;
}
然而,DataVisualization 技巧在 SQL-Server 上不起作用,因为您需要添加对 System.Web 的引用,而这在 SQL 中是做不到的-服务器。
另外,excel还有很多类似的函数,tinv,t.inv,T.INV.2S等等,一定要选对哦
编辑:
找到更多信息:
http://numerics.mathdotnet.com/api/MathNet.Numerics/ExcelFunctions.htm#TIn
在 Math.NET 中有一个名为 ExcelFunctions 的特殊 class 您可以实际使用:
MathNet.Numerics.ExcelFunctions.TInv (1.1, 55);
您在 TINV and TDIST on OpenOffice.org along with a list of functions by by category
上找到了更多信息
所以你的问题的解决方案是
[Microsoft.SqlServer.Server.SqlFunction]
public static System.Data.SqlTypes.SqlDouble TInv(double probability, int degFreedom)
{
double result = 0.00;
try
{
result = MathNet.Numerics.ExcelFunctions.TInv (probability, degFreedom);
}
catch
{
// throw; // Optionally throw/log/ignore/whatever
}
return result;
}
其实和
是一样的
[Microsoft.SqlServer.Server.SqlFunction]
public static System.Data.SqlTypes.SqlDouble TInv(double probability, int degFreedom)
{
double result = 0.00;
try
{
result = -StudentT.InvCDF(0d, 1d, degFreedom, probability/2);
}
catch
{
// throw; // Optionally throw/log/ignore/whatever
}
return result;
}
所以现在你从中获取 Math.Net 的源代码
https://github.com/mathnet/mathnet-numerics
并使用 CRL-Function 将 mathnet-numerics/src/Numerics/ 的内容(或您需要的部分)拖放到您的项目中,然后完成。
当你有 CLR dll 时,你进入 SSMS 并执行:
EXEC dbo.sp_configure 'clr enabled',1 RECONFIGURE WITH
CREATE ASSEMBLY SQLServerStatistics from 'C:\SQLServerStatistics.dll' WITH PERMISSION_SET = SAFE
成功后,还需要在SQL-Server上注册该函数。
CREATE FUNCTION [dbo].[tinv](@prob float, @degFreedom int)
RETURNS float WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [SQLServerStatistics].[Functions].[TInv]
有关详细信息,请参阅 this 文章。
如果您想将 Dll 带到生产服务器上,您需要从字节数组字符串创建程序集,如下所示:
CREATE ASSEMBLY [MyFunctions]
AUTHORIZATION [dbo]
FROM 0x4D5A90000[very long string here...];
您可以像这样从字节数组创建十六进制字符串:
byte[] bytes = System.IO.File.ReadAllBytes(@"C:\SQLServerStatistics.dll");
"0x" + BitConverter.ToString(bytes).Replace("-", "")
我已将整个解决方案 here 上传到 github。
然后你可以运行这样的函数:
SELECT dbo.tinv(0.54645, 60)
==> 0.606531559343638
脚本生成器工具会自动为您构建安装脚本。
看起来像这样:
> sp_configure 'show advanced options', 1; GO RECONFIGURE; GO
> sp_configure 'clr enabled', 1; GO RECONFIGURE; GO
>
>
> DECLARE @sql nvarchar(MAX) SET @sql = 'ALTER DATABASE ' +
> QUOTENAME(DB_NAME()) + ' SET TRUSTWORTHY ON;'
> -- PRINT @sql; EXECUTE(@sql); GO
>
>
> -- Restore sid when db restored from backup... DECLARE @Command NVARCHAR(MAX) = N'ALTER AUTHORIZATION ON DATABASE::<<DatabaseName>> TO
> [<<LoginName>>]' SELECT @Command = REPLACE ( REPLACE(@Command,
> N'<<DatabaseName>>', SD.Name) , N'<<LoginName>>' , SL.Name ) FROM
> master..sysdatabases AS SD JOIN master..syslogins AS SL ON SD.SID
> = SL.SID
>
> WHERE SD.Name = DB_NAME()
>
> -- PRINT @command EXECUTE(@command) GO
>
> IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TDist]') AND type in (N'FN', N'IF', N'TF', N'FS',
> N'FT')) DROP FUNCTION [dbo].[TDist] GO
>
> IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TInv]') AND type in (N'FN', N'IF', N'TF', N'FS',
> N'FT')) DROP FUNCTION [dbo].[TInv] GO
>
>
>
> IF EXISTS (SELECT * FROM sys.assemblies asms WHERE asms.name =
> N'SQLServerStatistics' and is_user_defined = 1) DROP ASSEMBLY
> [SQLServerStatistics] GO
>
>
> CREATE ASSEMBLY SQLServerStatistics AUTHORIZATION [dbo]
> FROM 'c:\users\administrator\documents\visual studio 2013\Projects\SqlServerStatistics\ClrCreationScriptGenerator\bin\Debug\SqlServerStatistics.dll'
> WITH PERMISSION_SET = UNSAFE GO
>
>
> CREATE FUNCTION [dbo].[TDist](@x AS float, @degFreedom AS int, @tails
> AS int)
> RETURNS float WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLServerStatistics].[SqlServerStatistics.ExcelFunctions].[TDist] GO
>
>
>
> CREATE FUNCTION [dbo].[TInv](@probability AS float, @degFreedom AS
> int)
> RETURNS float WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLServerStatistics].[SqlServerStatistics.ExcelFunctions].[TInv] GO
您可以在R中使用qt函数。这是一个代码片段:
DECLARE @confinPerc float, @setCount integer
SET @confinPerc = .95
SET @setCount = 5
DROP TABLE IF EXISTS #R_RES;
CREATE TABLE #R_RES(res float);
DECLARE @sql nvarchar(100)
SET @sql =N'SELECT ' + CAST(1-@confinPerc AS NVARCHAR) + ' AS prob, ' + CAST(@setCount - 2 AS NVARCHAR) + ' AS dF;'
INSERT INTO #R_RES
EXECUTE sp_execute_external_script
@language = N'R'
,@script = N' res <- qt(1-InputDataSet$prob/2,InputDataSet$dF);
df <- data.frame(res);'
,@input_data_1 = @sql
,@output_data_1_name = N'df';
SELECT * FROM #R_RES;
我正在尝试寻找 X 的 t 分布的双尾逆。可以在 Excel 中使用 TINV 函数找到它,但我需要在 SQL 服务器中实现它。请给我建议。
TINV 函数语法具有以下参数:
概率:与双尾学生 t 分布相关的概率。
Deg_freedom :表征分布的自由度数。
例如:
select tinv( 0.054645, 60);
-- -----------------
-- 1.9599994129833
-- (1 row returned)
您可以将自己的实现编写为 SQL 函数,或者使用 CLR 并用 C# 编写。
我的建议是使用 CLR 并包含 Accord 库(我推荐这个库,因为它们仍然有 .NET 3.5 版本,SQL 服务器 CLR 需要这些版本)实现统计功能。我在过去的其他统计计算中也这样做过,效果非常好。
SQL-服务器没有加入很多统计功能。
tinv
不存在于 SQL-服务器中。
添加 tinv 函数的唯一方法是使用 CLR 函数。
因此,问题本身减少为 "How do I calculate tinv with the subset of C# allowed in SQL-Server ?"。
如果您使用的是 .NET 4.0,则可以使用 System.Web.DataVisualization.dll
例如
var someChart = new System.Web.UI.DataVisualization.Charting.Chart();
double res = someChart.DataManipulator.Statistics.InverseTDistribution(.05, 15);
//2.131449546
但是,您可能不希望这种开销。 因此,您必须将其从 Math.NET 的源代码(MIT/X11 许可证)中删除。
StudentT dist = new StudentT(0.0,1.0,7.0);
double prob = dist.CumulativeDistribution(1.8946);
结果应该是 0.95
既然你需要逆,你就需要
StudentT.InvCDF(double location, double scale, double freedom, double p)
location:分布的位置(μ)。
尺度:分布的尺度 (σ)。范围:σ > 0。
自由度:分布的自由度 (ν)。范围:ν > 0.
p:计算逆累积密度的位置。
[Microsoft.SqlServer.Server.SqlFunction]
public static System.Data.SqlTypes.SqlDouble TInv(double probability, int degFreedom)
{
double result = 0.00;
try
{
result = fnInverseTDistribution(degFreedom, probability);
}
catch
{
// throw; // Optionally throw/log/ignore/whatever
}
return result;
}
使用 DataVisualization,它是这样的:
[Microsoft.SqlServer.Server.SqlFunction]
public static System.Data.SqlTypes.SqlDouble TInv(double probability, int degFreedom)
{
double result = 0.00;
try
{
var someChart = new System.Web.UI.DataVisualization.Charting.Chart();
result = someChart.DataManipulator.Statistics.InverseTDistribution( probability, degFreedom);
}
catch
{
// throw; // Optionally throw/log/ignore/whatever
}
return result;
}
然而,DataVisualization 技巧在 SQL-Server 上不起作用,因为您需要添加对 System.Web 的引用,而这在 SQL 中是做不到的-服务器。
另外,excel还有很多类似的函数,tinv,t.inv,T.INV.2S等等,一定要选对哦
编辑:
找到更多信息: http://numerics.mathdotnet.com/api/MathNet.Numerics/ExcelFunctions.htm#TIn
在 Math.NET 中有一个名为 ExcelFunctions 的特殊 class 您可以实际使用:
MathNet.Numerics.ExcelFunctions.TInv (1.1, 55);
您在 TINV and TDIST on OpenOffice.org along with a list of functions by by category
上找到了更多信息所以你的问题的解决方案是
[Microsoft.SqlServer.Server.SqlFunction]
public static System.Data.SqlTypes.SqlDouble TInv(double probability, int degFreedom)
{
double result = 0.00;
try
{
result = MathNet.Numerics.ExcelFunctions.TInv (probability, degFreedom);
}
catch
{
// throw; // Optionally throw/log/ignore/whatever
}
return result;
}
其实和
是一样的[Microsoft.SqlServer.Server.SqlFunction]
public static System.Data.SqlTypes.SqlDouble TInv(double probability, int degFreedom)
{
double result = 0.00;
try
{
result = -StudentT.InvCDF(0d, 1d, degFreedom, probability/2);
}
catch
{
// throw; // Optionally throw/log/ignore/whatever
}
return result;
}
所以现在你从中获取 Math.Net 的源代码 https://github.com/mathnet/mathnet-numerics 并使用 CRL-Function 将 mathnet-numerics/src/Numerics/ 的内容(或您需要的部分)拖放到您的项目中,然后完成。
当你有 CLR dll 时,你进入 SSMS 并执行:
EXEC dbo.sp_configure 'clr enabled',1 RECONFIGURE WITH
CREATE ASSEMBLY SQLServerStatistics from 'C:\SQLServerStatistics.dll' WITH PERMISSION_SET = SAFE
成功后,还需要在SQL-Server上注册该函数。
CREATE FUNCTION [dbo].[tinv](@prob float, @degFreedom int)
RETURNS float WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [SQLServerStatistics].[Functions].[TInv]
有关详细信息,请参阅 this 文章。
如果您想将 Dll 带到生产服务器上,您需要从字节数组字符串创建程序集,如下所示:
CREATE ASSEMBLY [MyFunctions]
AUTHORIZATION [dbo]
FROM 0x4D5A90000[very long string here...];
您可以像这样从字节数组创建十六进制字符串:
byte[] bytes = System.IO.File.ReadAllBytes(@"C:\SQLServerStatistics.dll");
"0x" + BitConverter.ToString(bytes).Replace("-", "")
我已将整个解决方案 here 上传到 github。
然后你可以运行这样的函数:
SELECT dbo.tinv(0.54645, 60)
==> 0.606531559343638
脚本生成器工具会自动为您构建安装脚本。 看起来像这样:
> sp_configure 'show advanced options', 1; GO RECONFIGURE; GO
> sp_configure 'clr enabled', 1; GO RECONFIGURE; GO
>
>
> DECLARE @sql nvarchar(MAX) SET @sql = 'ALTER DATABASE ' +
> QUOTENAME(DB_NAME()) + ' SET TRUSTWORTHY ON;'
> -- PRINT @sql; EXECUTE(@sql); GO
>
>
> -- Restore sid when db restored from backup... DECLARE @Command NVARCHAR(MAX) = N'ALTER AUTHORIZATION ON DATABASE::<<DatabaseName>> TO
> [<<LoginName>>]' SELECT @Command = REPLACE ( REPLACE(@Command,
> N'<<DatabaseName>>', SD.Name) , N'<<LoginName>>' , SL.Name ) FROM
> master..sysdatabases AS SD JOIN master..syslogins AS SL ON SD.SID
> = SL.SID
>
> WHERE SD.Name = DB_NAME()
>
> -- PRINT @command EXECUTE(@command) GO
>
> IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TDist]') AND type in (N'FN', N'IF', N'TF', N'FS',
> N'FT')) DROP FUNCTION [dbo].[TDist] GO
>
> IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TInv]') AND type in (N'FN', N'IF', N'TF', N'FS',
> N'FT')) DROP FUNCTION [dbo].[TInv] GO
>
>
>
> IF EXISTS (SELECT * FROM sys.assemblies asms WHERE asms.name =
> N'SQLServerStatistics' and is_user_defined = 1) DROP ASSEMBLY
> [SQLServerStatistics] GO
>
>
> CREATE ASSEMBLY SQLServerStatistics AUTHORIZATION [dbo]
> FROM 'c:\users\administrator\documents\visual studio 2013\Projects\SqlServerStatistics\ClrCreationScriptGenerator\bin\Debug\SqlServerStatistics.dll'
> WITH PERMISSION_SET = UNSAFE GO
>
>
> CREATE FUNCTION [dbo].[TDist](@x AS float, @degFreedom AS int, @tails
> AS int)
> RETURNS float WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLServerStatistics].[SqlServerStatistics.ExcelFunctions].[TDist] GO
>
>
>
> CREATE FUNCTION [dbo].[TInv](@probability AS float, @degFreedom AS
> int)
> RETURNS float WITH EXECUTE AS CALLER AS EXTERNAL NAME [SQLServerStatistics].[SqlServerStatistics.ExcelFunctions].[TInv] GO
您可以在R中使用qt函数。这是一个代码片段:
DECLARE @confinPerc float, @setCount integer
SET @confinPerc = .95
SET @setCount = 5
DROP TABLE IF EXISTS #R_RES;
CREATE TABLE #R_RES(res float);
DECLARE @sql nvarchar(100)
SET @sql =N'SELECT ' + CAST(1-@confinPerc AS NVARCHAR) + ' AS prob, ' + CAST(@setCount - 2 AS NVARCHAR) + ' AS dF;'
INSERT INTO #R_RES
EXECUTE sp_execute_external_script
@language = N'R'
,@script = N' res <- qt(1-InputDataSet$prob/2,InputDataSet$dF);
df <- data.frame(res);'
,@input_data_1 = @sql
,@output_data_1_name = N'df';
SELECT * FROM #R_RES;