Способы расчета сходства - PullRequest
17 голосов
/ 05 июня 2010

Я делаю сайт сообщества, который требует, чтобы я вычислил сходство между любыми двумя пользователями. Каждый пользователь описывается следующими атрибутами:

возраст, тип кожи (жирная, сухая), тип волос (длинные, короткие, средние), стиль жизни (активный любитель активного отдыха, TV junky) и др.

Может кто-нибудь сказать мне, как решить эту проблему или указать мне некоторые ресурсы?

Ответы [ 6 ]

14 голосов
/ 06 июня 2010

Другой способ вычисления (в R ) всех парных различий (расстояний) между наблюдениями в наборе данных. Исходные переменные могут быть смешанного типа. Обработка номинальных, порядковых и (а) симметричных двоичных данных достигается с помощью общего коэффициента разности Гауэра (Gower, J. C. (1971) Общий коэффициент подобия и некоторые его свойства, Biometrics 27, 857–874). Для получения дополнительной информации это на странице 47 . Если x содержит какие-либо столбцы этих типов данных, в качестве метрики будет использоваться коэффициент Гауэра.

Например

x1 <- factor(c(10, 12, 25, 14, 29))
x2 <- factor(c("oily", "dry", "dry", "dry", "oily"))
x3 <- factor(c("medium", "short", "medium", "medium", "long"))
x4 <- factor(c("active outdoor lover", "TV junky", "TV junky", "active outdoor lover", "TV junky"))
x <- cbind(x1,x2,x3,x4)

library(cluster)
daisy(x, metric = "euclidean")

вы получите:

Dissimilarities :
         1        2        3        4
2 2.000000                           
3 3.316625 2.236068                  
4 2.236068 1.732051 1.414214         
5 4.242641 3.741657 1.732051 2.645751

Если вас интересует метод уменьшения размерности для категориальных данных (также способ организации переменных в однородные кластеры), отметьте this

3 голосов
/ 05 июня 2010

Присвойте каждому атрибуту соответствующий вес и добавьте различия между значениями.

enum SkinType
    Dry, Medium, Oily

enum HairLength
    Bald, Short, Medium, Long

UserDifference(user1, user2)
    total := 0
    total += abs(user1.Age - user2.Age) * 0.1
    total += abs((int)user1.Skin - (int)user2.Skin) * 0.5
    total += abs((int)user1.Hair - (int)user2.Hair) * 0.8
    # etc...
    return total

Если вам действительно нужно сходство вместо разницы, используйте 1 / UserDifference(a, b)

2 голосов
/ 05 июня 2010

Вам, наверное, стоит взглянуть на

Эти темы позволят вашей программе распознать сходства и кластеров в вашей коллекции пользователей и попытаться адаптироваться к ним ...

Затем вы можете узнать различные скрытые общие группы связанных пользователей ... (т.е. пользователи с зелеными волосами обычно не любят смотреть телевизор ..)

В качестве совета попробуйте использовать готовые инструменты для этой функции вместо того, чтобы реализовывать ее самостоятельно ...
Взгляните на Open Directory Data Mining Projects

1 голос
/ 10 июня 2010

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

  1. Запишите все ваши переменные в типичную числовую переменную, например: тип кожи (жирный = -1, сухой = 1), тип волос (длинный = 2, короткие = 0, средний = 1), образ жизни (активный любитель активного отдыха = 1, TV junky = -1), возраст - это число.
  2. Масштабируйте все числовые диапазоны так, чтобы они соответствовали относительной важности, которую вы им придаете для указания разницы. Например: разница в возрасте 10 лет примерно такая же, как разница между длинными и средними волосами, а также разница между жирной и сухой кожей. Таким образом, 10 на возрастной шкале так же различны, как 1 на шкале для волос, так же, как 2 на шкале для кожи, поэтому масштабируйте разницу в возрасте на 0,1, в волосах на 1 и в коже на 0,5
  3. Используйте соответствующую метрику расстояния , чтобы объединить различия между двумя людьми на разных шкалах в одну общую разницу. Чем меньше это число, тем больше они похожи. Я бы предложил простую квадратичную разницу в качестве первой попытки для вашей функции расстояния.

Тогда можно рассчитать разницу между двумя людьми (я полагаю, что Person.age, .skin, .hair и т. Д. Уже прошли шаг 1 и являются числовыми):

double Difference(Person p1, Person p2) {

    double agescale=0.1;
    double skinscale=0.5;
    double hairscale=1;
    double lifestylescale=1;

    double agediff = (p1.age-p2.age)*agescale;
    double skindiff = (p1.skin-p2.skin)*skinscale;
    double hairdiff = (p1.hair-p2.hair)*hairscale;
    double lifestylediff = (p1.lifestyle-p2.lifestyle)*lifestylescale;

    double diff = sqrt(agediff^2 + skindiff^2 + hairdiff^2 + lifestylediff^2);
    return diff;
}

Обратите внимание, что diff в этом примере не в хорошем масштабе, как (0..1). Его значение может варьироваться от 0 (без разницы) до чего-то большого (большая разница). Кроме того, этот метод почти полностью ненаучен, он просто разработан, чтобы быстро дать вам метрику рабочей разницы.

0 голосов
/ 28 июня 2010
0 голосов
/ 05 июня 2010

Посмотрите на алгоритмы вычисления разницы в srting.Это очень похоже на то, что вам нужно.Сохраните ваши атрибуты как битовую строку и вычислите расстояние между строками

...