Дані мають дві тенденції; як витягти незалежні трендові лінії?


34

У мене є набір даних, який не впорядкований якимось особливим чином, але при графіку чітко визначено дві чіткі тенденції. Проста лінійна регресія тут насправді не була б адекватною через чітке розмежування двох серій. Чи є простий спосіб отримати дві незалежні лінійні лінії тренду?

Для запису я використовую Python, і мені досить комфортно програмування та аналіз даних, включаючи машинне навчання, але я готовий перейти на R, якщо це абсолютно необхідно.

введіть тут опис зображення


6
Найкраща відповідь, яку я маю поки що, - це роздрукувати це на графічному папері та використовувати олівець та лінійку та калькулятор ...
jbbiomed

Можливо, ви можете обчислити парні схили та згрупувати їх у два "кластери схилів". Однак це не вдасться, якщо у вас є дві паралельні тенденції.
Thomas Jungblut

1
Я не маю жодного особистого досвіду з цим, але думаю, що статистичні моделі варто перевірити. Статистично лінійна регресія з взаємодією для групи була б адекватною (якщо ви не кажете, що у вас є негруповані дані; в такому випадку це трохи невдало ...)
Метт Паркер

1
На жаль, це не дані про ефекти, а дані про використання, і, очевидно, використання з двох окремих систем, змішаних в один набір даних. Я хочу бути в змозі описати дві схеми використання, але я не можу повернутися назад і пригадати дані, оскільки це становить близько 6 років інформації, зібраної клієнтом.
jbbiomed

2
Просто для того, щоб переконатися: у вашого клієнта немає додаткових даних, які б вказували на те, які вимірювання відбуваються з якої сукупності? Це 100% даних, які ви або ваш клієнт мають або можете знайти. Також 2012 рік виглядає так, що ваш збір даних розпався, або одна або обидві ваші системи провалилися через підлогу. Змушує мене замислитись, чи сильно важливі лінії тренду до цього моменту.
Уейн

Відповіді:


30

Для вирішення вашої проблеми хорошим підходом є визначення ймовірнісної моделі, яка відповідає припущенням щодо вашого набору даних. У вашому випадку ви, мабуть, хочете суміш лінійних моделей регресії. Можна створити модель "суміш регресорів", подібну до моделі гауссової суміші, пов'язуючи різні точки даних з різними компонентами суміші.

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

import numpy as np
import matplotlib.pyplot as plt 
import scipy.linalg as lin

#generate some random data
N=100
x=np.random.rand(N,2)
x[:,1]=1

w=np.random.rand(2,2)
y=np.zeros(N)

n=int(np.random.rand()*N)
y[:n]=np.dot(x[:n,:],w[0,:])+np.random.normal(size=n)*.01
y[n:]=np.dot(x[n:,:],w[1,:])+np.random.normal(size=N-n)*.01


rx=np.ones( (100,2) )
r=np.arange(0,1,.01)
rx[:,0]=r

#plot the random dataset
plt.plot(x[:,0],y,'.b')
plt.plot(r,np.dot(rx,w[0,:]),':k',linewidth=2)
plt.plot(r,np.dot(rx,w[1,:]),':k',linewidth=2)

# regularization parameter for the regression weights
lam=.01

def em():
    # mixture weights
    rpi=np.zeros( (2) )+.5

    # expected mixture weights for each data point
    pi=np.zeros( (len(x),2) )+.5

    #the regression weights
    w1=np.random.rand(2)
    w2=np.random.rand(2)

    #precision term for the probability of the data under the regression function 
    eta=100

    for _ in xrange(100):
        if 0:
            plt.plot(r,np.dot(rx,w1),'-r',alpha=.5)
            plt.plot(r,np.dot(rx,w2),'-g',alpha=.5)

        #compute lhood for each data point
        err1=y-np.dot(x,w1)
        err2=y-np.dot(x,w2)
        prbs=np.zeros( (len(y),2) )
        prbs[:,0]=-.5*eta*err1**2
        prbs[:,1]=-.5*eta*err2**2

        #compute expected mixture weights
        pi=np.tile(rpi,(len(x),1))*np.exp(prbs)
        pi/=np.tile(np.sum(pi,1),(2,1)).T

        #max with respect to the mixture probabilities
        rpi=np.sum(pi,0)
        rpi/=np.sum(rpi)

        #max with respect to the regression weights
        pi1x=np.tile(pi[:,0],(2,1)).T*x
        xp1=np.dot(pi1x.T,x)+np.eye(2)*lam/eta
        yp1=np.dot(pi1x.T,y)
        w1=lin.solve(xp1,yp1)

        pi2x=np.tile(pi[:,1],(2,1)).T*x
        xp2=np.dot(pi2x.T,x)+np.eye(2)*lam/eta
        yp2=np.dot(pi[:,1]*y,x)
        w2=lin.solve(xp2,yp2)

        #max wrt the precision term
        eta=np.sum(pi)/np.sum(-prbs/eta*pi)

        #objective function - unstable as the pi's become concentrated on a single component
        obj=np.sum(prbs*pi)-np.sum(pi[pi>1e-50]*np.log(pi[pi>1e-50]))+np.sum(pi*np.log(np.tile(rpi,(len(x),1))))+np.log(eta)*np.sum(pi)
        print obj,eta,rpi,w1,w2

        try:
            if np.isnan(obj): break
            if np.abs(obj-oldobj)<1e-2: break
        except:
            pass

        oldobj=obj

    return w1,w2


#run the em algorithm and plot the solution
rw1,rw2=em()
plt.plot(r,np.dot(rx,rw1),'-r')
plt.plot(r,np.dot(rx,rw2),'-g')

plt.show()

25

В іншому місці користувач1149913 надає чудові поради (визначте ймовірнісну модель) та код для потужного підходу (оцінка ЕМ). Залишається вирішити два питання:

  1. Як впоратися з відхиленнями від імовірнісної моделі (які дуже очевидні в даних 2011-2012 рр. І дещо очевидні в коливаннях менш нахилених точок).

  2. Як визначити хороші вихідні значення для алгоритму ЕМ (або будь-якого іншого алгоритму).

Щоб вирішити номер 2, подумайте про перетворення Хаффа . Це алгоритм виявлення особливостей, який для знаходження лінійних розтяжок функцій може ефективно обчислюватися як перетворення Радона .

хух,ув перетворенні Хоф. Коли риси оригінальної ділянки падають на загальну лінію або достатньо близьку до одиниці, то колекції кривих, які вони виробляють у перетворенні Хоуфа, мають звичайний перетин, відповідний цій загальній лінії. Виявивши ці точки найбільшої інтенсивності в перетворенні Хоффа, ми можемо прочитати хороші рішення вихідної проблеми.

Для початку з цими даними я спершу обрізав допоміжний матеріал (оси, галочки та мітки) і для гарної міри обрізав очевидно зовнішні точки в правій нижній частині і посипав уздовж нижньої осі. (Коли цей матеріал не обрізаний, процедура все ще працює добре, але він також виявляє осі, рамки, лінійні послідовності кліщів, лінійні послідовності міток і навіть точки, що спорадично лежать на нижній осі!)

img = Import["http://i.stack.imgur.com/SkEm3.png"]
i = ColorNegate[Binarize[img]]
crop2 = ImageCrop[ImageCrop[i, {694, 531}, {Left, Bottom}], {565, 467}, {Right, Top}]

(Цей та решта коду є у Mathematica .)

Обрізане зображення

Кожній крапці на цьому зображенні відповідає вузький діапазон кривих у перетворенні Хоффа, видно тут. Вони є синусоїдами:

hough2 = Radon[crop2, Method -> "Hough"]  // ImageAdjust

Хоф трансформація

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

У цьому випадку кластеризація є настільки зрозумілою, що досить простої післяобробки перетворення Хоуфа. Щоб визначити місця найбільшої інтенсивності в перетворенні, я збільшив контраст і розмив перетворення в радіусі близько 1%: це порівнянно з діаметрами точок сюжету на вихідному зображенні.

blur = ImageAdjust[Blur[ImageAdjust[hough2, {1, 0}], 8]]

Розмита трансформація

Результат порогу звузив його до двох крихітних крапель, центроїди яких обґрунтовано ототожнюють точки найбільшої інтенсивності: вони оцінюють відповідні лінії.

comp = MorphologicalComponents[blur, 0.777]) // Colorize

0,777

Порогове бінаризоване перетворення

Ліва частина зображення відповідає напрямку 0 градусів (горизонтальному), і, коли ми дивимось зліва направо, цей кут лінійно збільшується до 180 градусів. Інтерполюючи, я обчислюю, що дві краплі зосереджені відповідно на 19 і 57,1 градуса. Ми також можемо зчитувати перехоплення з вертикальних позицій краплі. Ця інформація дає початкові результати:

width = ImageDimensions[blur][[1]];
slopes =  Module[{x, y, z}, ComponentMeasurements[comp, "Centroid"] /. 
          Rule[x_, {y_, z_}] :>  Round[((y - 1/2)/(width - 1))  180., 0.1]
  ]

{19., 57.1}

Аналогічним чином можна обчислити перехоплення, відповідні цим нахилам, надаючи ці підходи:

Пристосовані лінії

(Червона лінія відповідає крихітній рожевій крапці на попередньому малюнку, а синя лінія - більшій аква-крап.)

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

На цьому етапі можна надати ці оцінки як вихідні значення для алгоритму ЕМ або як мінімізатор ймовірності (який, даючи хороші оцінки, швидко сходиться). Краще, однак, було б використовувати надійний оцінювач регресії, такий як ітеративно переосмислені найменші квадрати . Він здатний надати вагу регресії до кожної точки. Невеликі ваги вказують, що точка не "належить" до лінії. Використовуйте ці ваги, за бажанням, щоб призначити кожну точку відповідної лінії. Потім, класифікувавши точки, ви можете використовувати звичайні найменші квадрати (або будь-яку іншу процедуру регресії) окремо на дві групи точок.


1
Картинки розповідають тисячу слів, а у вас є 5. Це неймовірний твір із швидкого графіка, який я зробив саме для цього питання! Кудо!
jbbiomed

2
Трансформація Хока широко використовується в полі "Комп'ютерне бачення" для виявлення прямих ліній на зображенні. Чому його не слід використовувати і в статистиці? ;)
Лукас Рейс

ху

Так. Уявіть, наприклад, кількість людей, що переживають люди, які беруть участь у порівнянні двох зображень, щоб виявити, чи є вони з одного предмета. І, головне, уявіть, що це потрібно робити в режимі реального часу. "Швидкість" є дуже важливим фактором у "Комп'ютерному баченні", і не настільки важливим для статистики.
Лукас Рейс

@RoyalTS Дякуємо, що вказали на необхідність виправлення одного з фрагментів коду. На той момент, коли я знайшов запропоновану вами зміну, її було відхилено (правильно, тому що це було не зовсім правильно, але не майте на увазі: я вдячний, що помітили, що сталася помилка). Я виправив це, видаливши посилання на rotation, яке було встановлено на нулі спочатку, і тому нічого не змінило.
whuber

15

Я знайшов це питання пов'язаним з іншим питанням . Я насправді робив наукові дослідження з цієї проблеми. Перевірте відповідь моєї відповіді "Найменший квадратний корінь"? Метод підгонки з декількома мінімумами для отримання детальної інформації.

Підхід на основі перетворення Хаубера на основі Хаубера є дуже хорошим рішенням для простих сценаріїв, як той, який ви дали. Я працював над сценаріями зі складнішими даними, такими як:

проблема асоціації даних - набір цукеркових даних

Ми з моїми співавторами позначали цю проблему "асоціації даних". Коли ви намагаєтеся вирішити її, головна проблема, як правило, є комбінаторною через експоненціальну кількість можливих комбінацій даних.

У нас є публікація « Перекриття сумішей Гауссових процесів для проблеми асоціації даних », де ми підходили до загальної проблеми N кривих ітераційною технікою, даючи дуже хороші результати. Ви можете знайти код Matlab, пов'язаний у статті.

[Оновлення] В бібліотеці GPClust можна знайти реалізацію методики OMGP Python .

У мене є ще один документ, де ми усунули проблему, щоб отримати проблему оптимізації опуклої, але вона ще не була прийнята до публікації. Він специфічний для 2 кривих, тому він би чудово працював на ваших даних. Повідомте мене, якщо ви зацікавлені.


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

1
Папір справді була прийнята, всього кілька місяців тому. Завантажити його можна тут gtas.unican.es/pub/378 . Це насправді досить рідкісна проблема (що може пояснити її недостатню популярність), але нам все ж вдалося знайти кілька цікавих застосувань. Подивіться експерименти в кінці статті, якщо вам подобається.
Стівен

2

користувач1149913 має чудову відповідь (+1), але мені здається, що ваш збір даних розпався наприкінці 2011 року, тому вам доведеться відрізати цю частину своїх даних, а потім все одно запускати речі різними випадковими вихідні коефіцієнти, щоб побачити, що ви отримуєте.

Один з простих способів зробити це - розділити свої дані на два набори на очі, а потім використовувати будь-яку техніку лінійної моделі, до якої ви звикли. У R це була б lmфункція.

Або помістити дві лінії очей. У R ви б скористалися ablineдля цього.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.