这是对数刻度的网络IP频率等级图。完成这一部分后,我尝试使用 Python 2.7 在对数对数刻度上绘制最佳拟合线。我必须使用matplotlib的“符号”轴比例,否则某些值将无法正确显示,而某些值将被隐藏。

我正在绘制的数据的X值是URL,Y值是URL的相应​​频率。

我的数据如下所示:

'http://www.bing.com/search?q=d2l&src=IE-TopResult&FORM=IETR02&conversationid=  123 0.00052210688591'
`http://library.uc.ca/  118 4.57782298326e-05`
`http://www.bing.com/search?q=d2l+uofc&src=IE-TopResult&FORM=IETR02&conversationid= 114 4.30271029472e-06`
`http://www.nature.com/scitable/topicpage/genetics-and-statistical-analysis-34592   109 1.9483268261e-06`

数据在第一列中包含URL,在第二列中包含相应的频率(存在相同URL的次数),最后在第三列中包含传输的字节。首先,我仅使用第一列和第二列进行此分析。共有2465个x值或唯一的URL。

以下是我的代码
import os
import matplotlib.pyplot as plt
import numpy as np
import math
from numpy import *
import scipy
from scipy.interpolate import *
from scipy.stats import linregress
from scipy.optimize import curve_fit

file = open(filename1, 'r')
lines = file.readlines()

result = {}
x=[]
y=[]
for line in lines:
  course,count,size = line.lstrip().rstrip('\n').split('\t')
  if course not in result:
      result[course] = int(count)
  else:
      result[course] += int(count)
file.close()

frequency = sorted(result.items(), key = lambda i: i[1], reverse= True)
x=[]
y=[]
i=0
for element in frequency:
  x.append(element[0])
  y.append(element[1])


z=[]
fig=plt.figure()
ax = fig.add_subplot(111)
z=np.arange(len(x))
print z
logA = [x*np.log(x) if x>=1 else 1 for x in z]
logB = np.log(y)
plt.plot(z, y, color = 'r')
plt.plot(z, np.poly1d(np.polyfit(logA, logB, 1))(z))
ax.set_yscale('symlog')
ax.set_xscale('symlog')
slope, intercept = np.polyfit(logA, logB, 1)
plt.xlabel("Pre_referer")
plt.ylabel("Popularity")
ax.set_title('Pre Referral URL Popularity distribution')
plt.show()

您会看到很多导入的库,因为我一直在使用它们,但是我的实验都没有产生预期的结果。因此,上面的代码正确生成了等级图。可以看到,曲线中的红线是红线,而曲线中的蓝线被认为是最佳拟合线,这在视觉上是不正确的。这是生成的图。

这是我期望的图表。我以某种方式不正确地绘制了第二张图中的虚线。



关于如何解决此问题的任何想法?

最佳答案

沿对数对数刻度沿直线下降的数据遵循y = c*x^(m)形式的幂关系。通过取两边的对数,可以得到您要拟合的线性方程:

log(y) = m*log(x) + c

调用np.polyfit(log(x), log(y), 1)可提供mc的值。然后,您可以使用这些值来计算log_y_fit的拟合值,如下所示:
log_y_fit = m*log(x) + c

您要针对原始数据绘制的拟合值是:
y_fit = exp(log_y_fit) = exp(m*log(x) + c)

因此,您遇到的两个问题是:
  • 您正在使用原始x坐标而不是log(x)坐标
  • 计算拟合值
  • 您正在绘制拟合的y值的对数,而没有将它们转换回原始比例

  • 我已经在下面的代码中解决了这两个问题,方法是将plt.plot(z, np.poly1d(np.polyfit(logA, logB, 1))(z))替换为:
    m, c = np.polyfit(logA, logB, 1) # fit log(y) = m*log(x) + c
    y_fit = np.exp(m*logA + c) # calculate the fitted values of y
    plt.plot(z, y_fit, ':')
    

    可以将其放置为一行:plt.plot(z, np.exp(np.poly1d(np.polyfit(logA, logB, 1))(logA))),但是我发现这使得调试更加困难。

    以下代码中的其他一些不同之处:
  • 当您从logA计算z来过滤掉所有z是一个线性范围,并且只有第一个值z,这就是方法我已经编码了。
  • 我不确定您为什么对x*log(x)的列表理解中有术语logA。对我来说,这似乎是一个错误,因此我没有将其包括在答案中。

  • 此代码应为您正确运行:
    fig=plt.figure()
    ax = fig.add_subplot(111)
    
    z=np.arange(1, len(x)+1) #start at 1, to avoid error from log(0)
    
    logA = np.log(z) #no need for list comprehension since all z values >= 1
    logB = np.log(y)
    
    m, c = np.polyfit(logA, logB, 1) # fit log(y) = m*log(x) + c
    y_fit = np.exp(m*logA + c) # calculate the fitted values of y
    
    plt.plot(z, y, color = 'r')
    plt.plot(z, y_fit, ':')
    
    ax.set_yscale('symlog')
    ax.set_xscale('symlog')
    #slope, intercept = np.polyfit(logA, logB, 1)
    plt.xlabel("Pre_referer")
    plt.ylabel("Popularity")
    ax.set_title('Pre Referral URL Popularity distribution')
    plt.show()
    

    当我在模拟数据上运行它时,将得到以下图形:

    python - python 2.7中的对数刻度上的最佳拟合线-LMLPHP

    注意:
  • 该行左右两端的“扭结”是使用“symlog”的结果,该符号将非常小的值线性化,如What is the difference between 'log' and 'symlog'?的答案所述。如果将此数据绘制在“对数-对数”轴上,则拟合的数据将是一条直线。
  • 您可能还想阅读以下答案:https://stackoverflow.com/a/3433503/7517724,它说明了如何使用加权来实现对日志转换后的数据的“更好”拟合。
  • 关于python - python 2.7中的对数刻度上的最佳拟合线,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43837179/

    10-11 04:12
    查看更多