Питання Python: Пошук тенденції в наборі чисел


У мене є список чисел у Python, як це:

x = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81]

Який найкращий спосіб знайти тенденцію в цих числах? Я не зацікавлений у прогнозуванні того, що буде наступним номером, я просто хочу вивести тенденцію для багатьох наборів чисел, щоб порівняти тенденції.

Редагувати: За тенденцією, я маю на увазі, що я хотів би чисельне уявлення про те, чи збільшуються чи зменшуються числа, і з якою швидкістю. Я не масово математичний, тому, мабуть, для цього є власне ім'я!

Редагувати 2: Схоже, що я дійсно хочу, щоб коефіцієнт лінійного оптимально відповідав. Який найкращий спосіб отримати це в Python?


20
2018-04-06 19:56


походження


Що ви маєте на увазі за допомогою "тренду"? - David Z
Прошу Давай - я оновлюю своє запитання більш докладно. - Sam Starling
Мені подобається питання. Відповідь повинна бути функцією, яка входить до списку і кашляє один номер, ні? - gseattle


Відповіді:


Можливо, ви маєте на увазі, що ви хочете розмістити ці цифри на графіку та знайти пряму лінію через них, де загальна відстань між лінією та цифрами мінімізована? Це називається лінійною регресією

def linreg(X, Y):
    """
    return a,b in solution to y = ax + b such that root mean square distance between trend line and original points is minimized
    """
    N = len(X)
    Sx = Sy = Sxx = Syy = Sxy = 0.0
    for x, y in zip(X, Y):
        Sx = Sx + x
        Sy = Sy + y
        Sxx = Sxx + x*x
        Syy = Syy + y*y
        Sxy = Sxy + x*y
    det = Sxx * N - Sx * Sx
    return (Sxy * N - Sy * Sx)/det, (Sxx * Sy - Sx * Sxy)/det


x = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81]
a,b = linreg(range(len(x)),x)  //your x,y are switched from standard notation

Тенденційна лінія навряд чи пройде через ваші оригінальні точки, але вона буде максимально наближена до початкових точок, які може отримати пряма лінія. Використовуючи значення градієнта та перехоплення цієї лінії тренду (a, b), ви зможете екстраполювати рядок, що лежить наприкінці масиву:

extrapolatedtrendline=[a*index + b for index in range(20)] //replace 20 with desired trend length

20
2018-04-06 20:23



Можливо, це має бути zip(X,Y) замість map(None,X,Y) - David Z
ти правий, блискавка краще - Riaz Rizvi
Тепер я багато не знаю про математику тут, але я тестував це широко і це було ні правильно, він не знайшов правильного b компенсувати і не було його a схил навіть дистанційно правильний. Це посилання дав мені розумний результат. - 2rs2ts
Чому б не нагодувати його лише за перелік і робити діапазон всередині функції? Простота ... це добре. Також він запитував число (коефіцієнт), а не два числа, не включаючи перехоплення, що б то не було. Яка планета - це статистики? :) - gseattle


Посилання, надане Кейтом або, мабуть, відповідь від Riaz може допомогти вам отримати поліс, але завжди рекомендується використовувати библиотеки, якщо такі є, і для проблеми у вашій руці, номер забезпечує чудову функцію поліноми, яка називається поліфіт . Ви можете використовувати Polyfit, щоб відповідати даним за будь-якою мірою рівняння.

Ось приклад, що використовує numpy, щоб відповідати даним у лінійному рівнянні форми y = ax + b

>>> data = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81]
>>> x = np.arange(0,len(data))
>>> y=np.array(data)
>>> z = np.polyfit(x,y,1)
>>> print "{0}x + {1}".format(*z)
4.32527472527x + 17.6
>>> 

так само квадратна придатність буде

>>> print "{0}x^2 + {1}x + {2}".format(*z)
0.311126373626x^2 + 0.280631868132x + 25.6892857143
>>> 

12
2018-04-06 20:33





Ви могли б зробити це Найменші квадрати підходять даних.

Використання формули з ця сторінка:

y = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81]
N = len(y)
x = range(N)
B = (sum(x[i] * y[i] for i in xrange(N)) - 1./N*sum(x)*sum(y)) / (sum(x[i]**2 for i in xrange(N)) - 1./N*sum(x)**2)
A = 1.*sum(y)/N - B * 1.*sum(x)/N
print "%f + %f * x" % (A, B)

Яка відбиває початкове значення та дельту найкращої лінії.


6
2018-04-06 19:59



Використовуючи придатність, потрібно заздалегідь знати функціональну форму ("тренд"). Якщо ви не хочете вгадати і перевірити випадкові функції, але простір усіх можливих функцій нескінченний, тож ви ніколи не знатимете, що у вас це правильно. - David Z
@David: звичайно, але ви просто визначили проблему так, що її неможливо вирішити. "тренд" означає щось для плаката. Напевно, просто лінійна придатність. - Keith Randall
Негативний. Як ви могли це зробити за допомогою однієї змінної? - luke14free
@ luke14free: індекс - це незалежна змінна, а значення - залежна змінна. Як (0,12), (1,34), (2, 29), ... - Keith Randall
@KeithRandall це тверде припущення, яке не повинно бути правдою. - luke14free


Ось один із способів отримати тенденцію до збільшення / зменшення:

>>> x = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81]
>>> trend = [b - a for a, b in zip(x[::1], x[1::1])]
>>> trend
[22, -5, 9, -4, 17, -22, 5, 13, -13, 21, 39, -26, 13]

У наведеному списку trend, trend[0] можна тлумачити як збільшення від x[0] до x[1], trend[1] буде збільшення від x[1] до x[2] д. Негативні значення в trend означає це значення в x знизився від одного індексу до іншого.


3
2018-04-06 20:04





Я згоден з Кейтом, я думаю, що ви, напевно, шукаєте лінійні найменші квадрати, придатні (якщо все, що ви хочете знати, це чи цифри, як правило, збільшуються або зменшуються, і за якою швидкістю). Схил придатності покаже вам, якою швидкістю вони зростають. Якщо ви хочете, щоб візуальне представлення лінійних найменших квадратів відповідає, спробуйте Wolfram Alpha:

http://www.wolframalpha.com/input/?i=linear+fit+%5B12%2C+34%2C+29%2C+38%2C+34%2C+51%2C+29%2C+34%2C + 47% 2С + 34% 2С + 55% 2С + 94% 2С + 68% 2С + 81% 5D

Оновлення:  Якщо ви хочете здійснити лінійну регресію в Python, я рекомендую почати з пояснення в Mathworld:

http://mathworld.wolfram.com/LeastSquaresFitting.html

Це дуже просте пояснення алгоритму, і він практично сам пише. Зокрема, ви хочете звернути пильну увагу на рівняння 16-21, 27 і 28.

Спробуйте самостійно написати алгоритм, і якщо у вас є проблеми, ви повинні відкрити ще одне питання.


3
2018-04-06 20:06



Прекрасна посилання. Я думаю, що я хочу, це коефіцієнт лінійної найменшої квадратики найкраще підходить. Мені не надто турбувало зміщення. Чи є простий спосіб зробити це в Python? - Sam Starling


Ви можете знайти коефіцієнт OLS за допомогою numpy:

import numpy as np

y = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81]

x = []
x.append(range(len(y)))                 #Time variable
x.append([1 for ele in xrange(len(y))]) #This adds the intercept

y = np.matrix(y).T
x = np.matrix(x).T

betas = (x.T*x).I*x.T*y)

Результати:

>>> betas
matrix([[  4.32527473],  #coefficient on the time variable
        [ 17.6       ]]) #coefficient on the intercept

Оскільки коефіцієнт змінної тренду є позитивним, спостереження у вашій змінній з часом зростають.


1
2018-04-06 22:27





Обчислити коефіцієнт бета.

y = [12, 34, 29, 38, 34, 51, 29, 34, 47, 34, 55, 94, 68, 81]
x = range(1,len(y)+1)

def var(X):
    S = 0.0
    SS = 0.0
    for x in X:
        S += x
        SS += x*x
    xbar = S/float(len(X))
    return (SS - len(X) * xbar * xbar) / (len(X) -1.0)

def cov(X,Y):
    n = len(X)
    xbar = sum(X) / n
    ybar = sum(Y) / n
    return sum([(x-xbar)*(y-ybar) for x,y in zip(X,Y)])/(n-1)


def beta(x,y):
    return cov(x,y)/var(x)

print beta(x,y) #4.34285714286

-1
2018-04-06 20:50