Разница между наборами данных - PullRequest
0 голосов
/ 01 февраля 2011


У меня есть два набора данных в виде списков, например:

xa = [1, 2, 3, 10, 1383, 0, 12, 9229, 2, 494, 10, 49]    
xb = [1, 1, 4, 12, 1100, 43, 9, 4848, 2, 454, 6, 9]

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

Мне нужно найти «разницу» в процентах, которая показывает «насколько сходство / различие между рядами в процентах».
В настоящее время у меня есть идея построить диаграммы для каждого списка (xa, xb как Y ax, а диапазон (1, len (xa)) как X ax).интерполируйте функции для xa, xb, затем вычислите площадь xa, xb (с интегрированием) и площадь разницы между xa и xb.После этого различие составляет (разность площадей) * 100% / (xa площадь + xb область).

Интересно, есть ли у этого вопроса более простое решение?Если нет - как я могу вычислить разницу разности xa, xb?Графики построены с scipy, numpy, matplotlib.

обновление : я ищу ОДИН номер, который представляет разницу между наборами.Проценты являются предпочтительными.

Ответы [ 5 ]

5 голосов
/ 01 февраля 2011

Хорошо, если вы хотите получить метрику сходства для сравнения двух 1D-векторов, которая предпочтительно возвращает значение от 0 до 1 (или от 0 до 100%), косинусное сходство удовлетворяет этим критериям(с оговоркой в ​​конце).(Является ли это уместным с учетом контекста вашей проблемы, я не знаю, но вы знаете контекст, так что вы, безусловно, можете сделать это определение.)

import numpy as NP
import numpy.linalg as LA

# generate some data
fnx = lambda : NP.random.randint(0, 10, 10)
s1, s2 = fnx(), fnx()

# a function to calculate cosine similarity
cx = lambda a, b : round(NP.inner(a, b)/(LA.norm(a)*LA.norm(b)), 2)

cx(s1, s2)
# returns 0.85

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

В общем случае косинусное сходство возвращает значения от -1 до 1, хотя во многих (большинстве?) практических ситуациях, в которыхэто используется, возможные значения ограничены между 0 и 1.

Во-вторых, формула для косинусного подобия является точкой (a, b) / (norm (a) x norm (b));NumPy имеет функцию точки, однако внутренняя - это функция NumPy, которая реализует произведение точек.

3 голосов
/ 01 февраля 2011

Это очень сильно зависит от характера «сходства», которое вы ищете.

Мне вспоминаются два такта.

  • Рассчитать сумму sqrt((X[i]-Y[i])^2) или abs(X[i]-Y[i]), нормализовать до диапазона X и Y, то есть от min (X, Y) до max (X, Y). Чем ближе к 0, тем больше похожи наборы данных. Версия sqrt более чувствительна к небольшим различиям.
  • Рассчитайте корреляцию , это даст вам меру от +1 как «полностью похожую» на -1 до «полностью отличную». Обратите внимание, что это «сходство» не обязательно означает, что ваши серии четко следуют друг за другом. Взгляните на картинку в статье в википедии.
2 голосов
/ 01 февраля 2011

Это зависит от того, что вы пытаетесь сделать.Например, чтобы привести еще один данный пример, вы можете представить подсчет элементов в одном, а не в обоих наборах (длина симметричной разности двух наборов) - если числа соответствуют измерениям, это, очевидно, будет очень плохо.

Вы говорите, что временные ряды, так что мы можем предположить, что порядок имеет значение?

Для временных рядов часто выгодно вычислять вещи в спектральной области, что еще нужно учитывать.Что-то с одним номером вряд ли даст вам много информации

1 голос
/ 01 февраля 2011

это то, что вы ищете?

xa = [1, 2, 3, 10, 1383, 0, 12, 9229, 2, 494, 10, 49]    
xb = [1, 1, 4, 12, 1100, 43, 9, 4848, 2, 454, 6, 9]
xc = []

for i in range(0, len(xa)-1):
    xc.append(xa[i] - xb[i])

print xc

выход:

[0, 1, -1, -2, 283, -43, 3, 4381, 0, 40, 4]

РЕДАКТИРОВАТЬ:

почему бы не взять процентную разницу для каждого значения, а затем усреднить их все:

from statlib import stats

xa = [1, 2, 3, 10, 1383, 0, 12, 9229, 2, 494, 10, 49]    
xb = [1, 1, 4, 12, 1100, 43, 9, 4848, 2, 454, 6, 9]
xc = []


for i in range(0, len(xa)-1):
    xc.append(abs(float(xa[i] - xb[i])/(xa[i] + xb[i])/2))

print stats.mean(xc)*100

если у вас нет statlib, вы можете получить его здесь

0 голосов
/ 01 февраля 2011
from __future__ import division
from itertools import izip, repeat
import math

def weighted_mean(values, weights=None):
    total = 0
    number = 0
    if weights is None:
        weights = repeat(1)
    for weight, value in izip(weights, values):
        total += weight * value
        number += weight
    return number and total / number

xa = [1, 2, 3, 10, 1383, 0, 12, 9229, 2, 494, 10, 49]    
xb = [1, 1, 4, 12, 1100, 43, 9, 4848, 2, 454, 6, 9]


print "Option 1, if you want bigger numbers to have a bigger effect on the score"

weights = (math.sqrt(abs(a) * abs(b)) for a, b in izip(xa, xb))
scores = (abs(a) + abs(b) and abs(a - b) / (abs(a) + abs(b)) for a, b in izip(xa, xb))

final_score = weighted_mean(scores, weights)
print "%.02f%%" % (final_score * 100)


print "Option 2, if you want to have all numbers have the same effect on the score"

scores = (abs(a) + abs(b) and abs(a - b) / (abs(a) + abs(b)) for a, b in izip(xa, xb))

final_score = weighted_mean(scores)
print "%.02f%%" % (final_score * 100)

Конечно, вы также можете использовать другие виды весов, такие как (abs(a) + abs(b)) / 2, в зависимости от того, как вы хотите интерпретировать данную разницу.

Бездонная версия второго:

xan = numpy.array(xa)
xbn = numpy.array(xb)
error_threshold = 0.000001
final_score = numpy.mean((abs(xan - xbn) + error_threshold) / (abs(xan) + abs(xbn) + error_threshold))

Или первый:

scores = (abs(xan - xbn) + error_threshold) / (abs(xan) + abs(xbn) + error_threshold)
weights = numpy.sqrt(abs(xan) * abs(xbn))
final_score = numpy.sum(scores * weights) / numpy.sum(weights)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...