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

标签 python matplotlib ip linear-regression curve-fitting

这是对数刻度的网络 IP 频率排名图。完成这部分后,我尝试使用 Python 2.7 在对数对数尺度上绘制最佳拟合线。我必须使用 matplotlib 的“symlog”轴刻度,否则某些值无法正确显示并且某些值会被隐藏。

我正在绘制的数据的 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 出现的次数),最后是第三列中传输的字节数。首先,我仅使用第一列和第二列进行此分析。总共有 2,465 个 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()

你会看到很多导入的库,因为我一直在玩很多库,但我的实验都没有产生预期的结果。所以上面的代码正确地生成了排名图。可以看出,这是红线,但曲线中的蓝线本应是最佳拟合线,但在视觉上是不正确的。这是生成的图表。

Correct Rank plot but incorrect curve fit

这是我期待的图表。第二张图中的虚线是我以某种方式错误绘制的。

Expected graph

关于如何解决这个问题有什么想法吗?

最佳答案

在双对数刻度上沿直线落下的数据遵循 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)

那么,您遇到的两个问题是:

  1. 您正在使用原始 x 坐标而不是 log(x) 坐标计算拟合值

  2. 您正在绘制拟合 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))),但我发现这使得调试变得更加困难。

以下代码中的其他一些不同之处:

  • 当您从 z 计算 logA 以过滤掉所有 <1 的值时,您正在使用列表推导式,但 z 是一个线性范围,只有第一个值 < 1。从 1 开始创建 z 似乎更容易,这就是我的编码方式。

  • 我不确定为什么您在对 logA 的列表理解中使用术语 x*log(x)。这对我来说像是一个错误,所以我没有将其包含在答案中。

此代码应该可以为您正常工作:

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()

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

Log-log graph with fitted line

注意事项:

关于python - python 2.7 中对数对数刻度的最佳拟合线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43837179/

相关文章:

python - py.test -- 模拟常量并在测试函数中引发异常

python - 在烛台图上绘制移动平均线

matplotlib - 如何使用 pandas.DataFrame.boxplot 的返回值?

java - 从 csv 中删除重复项并在 Java 中对它们进行计数

c# - Tcp/Ip C# 错误请求/丢失数据包

python - 如何通过 pyglet 使用鼠标运动来移动标签?

python - 如何从 PythonGDB (GDB 7.1) 中的 gdb.execute 获取输出?

python-3.x - 分别设置两个直方图的颜色有问题

c - 尝试写入 struct ip 时出现错误 “dereferencing pointer to incomplete type”

python - 仅使用天数时, "datetime.timedelta"和 "dateutil.relativedelta.relativedelta"有什么区别?