如何确定黑盒子是多项式还是指数型

时间:2014-04-12 04:58:30

标签: python numpy matplotlib statistics time-complexity

我有一个基本上减少的问题:

  1. 您有一个黑盒功能,可接受长度为n的输入。
  2. 您可以衡量该函数返回答案所需的时间,但您无法确切知道它是如何计算的。
  3. 您必须确定此函数的时间复杂度是多项还是指数。
  4. 我这样做的方法是通过函数运行数千个不同长度的随机样本输入,然后在散点图上绘制它们,在y轴上有时间,在x轴上有输入长度。

    我使用numpy绘制了散点图,但现在我如何绘制多项式和指数最佳拟合线?我可以计算哪些指标来确定哪条最佳拟合线最合适?

    (问一个类似的问题,但理论上并没有强调计算机科学上的特定语言:https://cs.stackexchange.com/questions/23686/how-to-determine-if-a-black-box-is-polynomial-or-exponential

2 个答案:

答案 0 :(得分:6)

取所有Y值的对数。多项式结果仍将显示对数增长(自log x^n = n * log x),但指数曲线将转换为适当的直线(log exp(x) = x)。

如果你现在用线性LSQ估计足够的结果点,那么你可以非常肯定算法是指数的,如果它很好地适合(允许存在一些差异 - 我建议通过经验推导出一些合理的epsilon)检查一个你知道复杂性的算法!),否则就是多项式。

您还可以通过检查与回归线的偏差来提高置信水平:如果大多数值低于回归线,那么数据很可能是对数的(即程序以多项式时间运行)。

答案 1 :(得分:2)

如果算法的时间成本 t n 大小多项式,即近似t = k * n m ,然后log-log plot log t 对log n 的图应该是带梯度的直线 m (并拦截lo​​g k )。

如果算法的时间成本 t n 大小方面指数,即近似t = k e < sup> m n,然后a log-linear plot,一个 log t n 的图应该是渐变 m 的直线(和拦截日志 k )。

因为这些图是直线,所以您可以使用简单的线性回归来估计参数。

  

如何绘制多项式和指数最佳拟合线?

一旦你有了参数,直线 m 和截距 c 的直线适合日志日志或半日志空间,你可以转换 m c 返回原始坐标空间,以获得原始数据的最佳拟合曲线(详细信息显示在下面的示例程序中)。

  

我可以计算哪些指标来确定哪条最佳拟合线最合适?

回归的 R 2 给出了拟合优度的数值指示,更接近1是更好的拟合。然而,这可能有点误导,因为它反映了变换空间的拟合(log t vs log n或log t vs n),因此更容易看到结果方程并观察曲线。另一种定量测量方法是将原始数据与最佳拟合曲线上的相应点之间的误差相加。

该技术通过以下数据系列进行演示(每个系列都包含噪声)

  • 系列0: t = 3n
  • 系列1: t = 5n 2
  • 系列2: t = 7e n
  • 系列3: t = 9e 2n

在下图中,您可以看到多项式形式已经恢复为0和1系列(绿色虚线),并且指数形式已恢复为系列2和3(红色虚线)。在每种情况下,较高的 R 2 对应于最佳拟合,并且参数 m 已经非常准确地恢复。

enter image description here

代码在

之下
import math, numpy as np, matplotlib.pyplot as plt
from sklearn import linear_model

N = 100
lo = 2
hi = 25
n = np.linspace(lo,hi,num=N)
D = 4
T = np.maximum(np.random.normal(scale=hi / 25.0, size=(N,D)),0.01)
T[:,0] = 3*(T[:,0] + n)
T[:,1] = 5*(T[:,1] + n)**2
T[:,2] = 7*np.exp(T[:,2]/5.0 + n)
T[:,3] = 9*np.exp(2*(T[:,3]/5.0 + n))

logn = np.log(n)
logT = np.log(T)

for i in range(D):
    # fit log-log model
    loglogmod = linear_model.LinearRegression()
    x=np.reshape(logn,(N,1))
    y=logT[:,i]
    loglogmod.fit(x, y)
    loglogmod_rsquared = loglogmod.score(x, y)
    # fit log model
    logmod = linear_model.LinearRegression()
    x=np.reshape(n,(N,1))
    logmod.fit(x, y)
    logmod_rsquared = logmod.score(x, y)
    # plot results
    plt.subplot(2,2,i+1)
    plt.plot(n, T[:,i], label='series {}'.format(i),lw=2)
    m = loglogmod.coef_[0]
    c = loglogmod.intercept_
    polynomial = math.exp(c)*np.power(n,m)
    plt.plot(n, polynomial,
                label='$t={0:.1f}n^{{{1:.1f}}}$ ($r^2={2:.2f}$)'.format(math.exp(c),m,loglogmod_rsquared),
                ls='dashed',lw=3)
    m = logmod.coef_[0]
    c = logmod.intercept_
    exponential = np.exp(n * m) * math.exp(c)
    plt.plot(n, exponential,
                label='$t={0:.1f}e^{{{1:.1f}n}}$ ($r^2={2:.2f}$)'.format(math.exp(c),m,logmod_rsquared),
                ls='dashed',lw=3)
    plt.legend(loc='upper left', prop={'size':16})

plt.show()

(我使用的文档:sklearn.linear_model.LinearRegression referencematplotlib tutorial