Подгонка прямой к кривой log-log в matplotlib

У меня есть сюжет со мной, который является логарифмическим по обеим осям. У меня есть пиплот loglog Функция для этого. Это также дает мне логарифмическую шкалу по обеим осям.

Теперь, используя numpy, я подгоняю прямую линию к набору точек, которые у меня есть. Однако, когда я строю эту линию на графике, я не могу получить прямую линию. Я получаю изогнутую линию. Синяя линия - предположительно

Синяя линия - предположительно "прямая линия". Это не получается прямо. Я хочу подогнать эту прямую линию к кривой, нанесенной красными точками

Вот код, который я использую для построения точек:

import numpy
from matplotlib import pyplot as plt
import math
fp=open("word-rank.txt","r")
a=[]
b=[]

for line in fp:
    string=line.strip().split()
    a.append(float(string[0]))
    b.append(float(string[1]))

coefficients=numpy.polyfit(b,a,1)
polynomial=numpy.poly1d(coefficients)
ys=polynomial(b)
print polynomial
plt.loglog(b,a,'ro')
plt.plot(b,ys)
plt.xlabel("Log (Rank of frequency)")
plt.ylabel("Log (Frequency)")
plt.title("Frequency vs frequency rank for words")
plt.show()

3 ответа

Решение

Ваша линейная подгонка не выполняется на тех же данных, как показано на графике журнала.

Сделайте такие массивы как a и b

a = numpy.asarray(a, dtype=float)
b = numpy.asarray(b, dtype=float)

Теперь вы можете выполнять операции над ними. Что делает loglog-сюжет, так это переводит логарифм в основание 10 как a, так и b. Вы можете сделать то же самое,

logA = numpy.log10(a)
logB = numpy.log10(b)

Вот что визуализирует сюжет журнала. Проверьте это, построив logA и logB как обычный график. Повторите линейное соответствие данных журнала и нанесите линию на тот же график, что и данные logA, logB.

coefficients = numpy.polyfit(logB, logA, 1)
polynomial = numpy.poly1d(coefficients)
ys = polynomial(b)
plt.plot(logB, logA)
plt.plot(b, ys)

Чтобы лучше понять эту проблему, давайте сначала поговорим о простой линейной регрессии (polyfit функция, в данном случае, ваш алгоритм линейной регрессии).


Предположим, у вас есть набор точек данных (x,y), показанный ниже:

Линейная регрессионная диаграмма

Вы хотите создать модель, которая предсказывает y как функция x, так что вы используете линейную регрессию. Это использует модель:

y = mx + b

и вычисляет значения m а также b которые лучше всего предсказывают ваши данные, используя некоторую линейную алгебру.

Затем вы используете вашу модель для прогнозирования значений y как функции от x. Вы делаете это, выбирая набор значений для x (думаю, linspace) и вычисляя соответствующие значения y. Построение этих (x, y) пар дает вам линию регрессии.


Теперь поговорим о логарифмической регрессии. В этом случае у нас все еще есть две переменные, у против х, и мы по-прежнему заинтересованы в их взаимосвязи, т. Е. Возможность предсказать y дано x, Единственная разница в том, сейчас y а также x случается, логарифмы двух других переменных, которые я назову log(F) а также log(R), Пока что это не более чем простая смена имени.

Лог регрессионная диаграмма

Линейная регрессия также работает аналогичным образом. Вы все еще регрессируете у против х. Алгоритм линейной регрессии не волнует, что y а также x на самом деле log(F) а также log(R) - это не имеет никакого значения для алгоритма.

Последний шаг немного отличается - и именно здесь вы попадаете в заговор выше. То, что вы делаете, это вычисления

F = m R + b

но это неверно, потому что отношения между F а также R не является линейным. (Вот почему вы используете график журнала.)

Вместо этого вы должны вычислить

log(F) = m log(R) + b

Если вы преобразуете это (поднимите 10 к степени обеих сторон и переставите), вы получите

F = c R^m

где c = 10^b, Это отношения между F а также R: это отношения степенного права. (Взаимосвязь степенного закона - это то, что лучше всего подходит для логов.)

В вашем коде вы используете A и B при вызове polyfit, но вы должны использовать log(A) а также log(B),

Другие ответы предлагают отличные объяснения и решения. Однако я хотел бы предложить решение, которое мне очень помогло и, возможно, поможет вам.

Еще один простой способ написания строки, подходящей для масштаба log-log, - это функция powerfit в коде ниже. Требуется в оригинале x а также y данные и с помощью ряда новых х-точек вы можете получить прямую линию в масштабе журнала регистрации. В текущем случае значения xnew такие же как x (которые оба b).

Преимущество определения новых x-координат состоит в том, что вы можете получить как можно меньше или столько точек линии питания, сколько вам нужно.

import numpy as np
from matplotlib import pyplot as plt
import math


def powerfit(x, y, xnew):
    """line fitting on log-log scale"""
    k, m = np.polyfit(np.log(x), np.log(y), 1)
    return np.exp(m) * xnew**(k)


fp=open("word-rank.txt","r")
a=[]
b=[]

for line in fp:
    string=line.strip().split()
    a.append(float(string[0]))
    b.append(float(string[1]))

ys = powerfit(b, a, b)

plt.loglog(b,a,'ro')
plt.plot(b,ys)
plt.xlabel("Log (Rank of frequency)")
plt.ylabel("Log (Frequency)")
plt.title("Frequency vs frequency rank for words")
plt.show()
Другие вопросы по тегам