К-означава ClusterПрограмиране в R с пример
⚡ Умно обобщение
К-средства ClusterВ R се групират наблюдения чрез минимизиране на разстоянието между всяка точка и нейния центроид на клъстера. Това ръководство стандартизира набора от данни за компютърни цени, анимира алгоритъма, намира оптималното k с метода на лакътя и отчита клъстерите чрез топлинна карта.

Какво е Cluster анализ?
Cluster анализът принадлежи на учене без надзор. Клъстерът е група от данни, които споделят подобни характеристики. Можем да кажем, че клъстерният анализ е повече за откритие, отколкото за прогноза. Машината търси сходство в данните. Например, можете да използвате клъстерен анализ за следното приложение:
- Сегментиране на клиенти: Търси прилики между групи клиенти
- Групиране на фондовия пазар: групови акции въз основа на представянето
- Намаляване на размерността на набор от данни чрез групаping наблюдения с подобни стойности
Clusterанализът не е твърде труден за прилагане и е смислен, както и приложим за бизнеса.
Най-забележителната разлика между контролираното и неконтролираното обучение се крие в резултатите. Неконтролираното обучение създава нова променлива, етикетът, докато контролираното обучение предвижда резултат. Машината помага на практикуващия в стремежа да етикетира данните въз основа на тясна връзка. От анализатора зависи да използва групите и да им даде имена.
Нека дадем пример, за да разберем концепцията за групиране. За по-лесно ние работим в две измерения. Имате данни за общите разходи на клиентите и тяхната възраст. За да подобри рекламирането, маркетинговият екип иска да изпраща по-насочени имейли на своите клиенти.
В следващата графика нанасяте общите разходи и възрастта на клиентите.
library(ggplot2) df <- data.frame(age = c(18, 21, 22, 24, 26, 26, 27, 30, 31, 35, 39, 40, 41, 42, 44, 46, 47, 48, 49, 54), spend = c(10, 11, 22, 15, 12, 13, 14, 33, 39, 37, 44, 27, 29, 20, 28, 21, 30, 31, 23, 24) ) ggplot(df, aes(x = age, y = spend)) + geom_point()
В тази точка се вижда модел
- Долу вляво можете да видите млади хора с по-ниска покупателна способност
- Горе-среден отразява хората с работа, за която могат да си позволят да харчат повече
- И накрая, възрастни хора с по-нисък бюджет.
На фигурата по-горе групирате наблюденията на ръка и дефинирате всяка от трите групи. Този пример е донякъде ясен и много визуален. Ако нови наблюдения са добавени към набора от данни, можете да ги обозначите в кръговете. Вие определяте кръга въз основа на нашата преценка. Вместо това можете да използвате Machine Learning за обективно групиране на данните.
В този урок ще научите как да използвате k-означава алгоритъм.
Алгоритъм на K-средните стойности
K-means е най-широко използваният метод за клъстеризация. Алгоритъмът датира от 1950-те години на миналия век и оттогава е усъвършенстван многократно.
Алгоритъмът се опитва да намери групи чрез минимизиране на разстоянието между наблюденията, т.нар локален оптимален решения. Разстоянията се измерват въз основа на координатите на наблюденията. Например, в двумерно пространство координатите са просто x и y.
Алгоритъмът работи по следния начин:
- Стъпка 1: Изберете k начални центроида на случаен принцип в пространството на характеристиките
- Стъпка 2: Присвоете всяко наблюдение на най-близкия клъстерен център, центроидТова води до k групи
- Стъпка 3: Shift началния центроид към средната стойност на координатите в рамките на група.
- Стъпка 4: Минимизирайте разстоянието според новите центроиди. Създават се нови граници. Така наблюденията ще се преместват от една група в друга
- Повтаряйте, докато нито едно наблюдение не промени групите
K-средните стойности обикновено измерват евклидовото разстояние между две наблюдения x и y:
Налични са и други мерки, като например разстоянието на Манхатън или Минковски. Обърнете внимание, че K-mean връща различни групи всеки път, когато изпълнявате алгоритъма. Припомнете си, че първите първоначални предположения са случайни и изчислявайте разстоянията, докато алгоритъмът достигне хомогенност в рамките на групите. Тоест, k-mean е много чувствителен към първия избор и освен ако броят на наблюденията и групите не е малък, е почти невъзможно да се получи същото клъстериране.
Избор на броя на клъстерите
Друга трудност, срещана при k-mean, е изборът на броя на клъстерите. Можете да зададете висока стойност на k, което означава голям брой групи, за да подобрите хомогенността в рамките на групата, но рискувате... свръхоборудване данните. Прекаленото напасване означава, че производителността спада рязко при нови данни, защото моделът е запомнил шума в тази конкретна извадка, а не основния модел.
Броят на клъстерите зависи от естеството на набора от данни, индустрията, бизнеса и т.н. Въпреки това има основно правило за избор на подходящия брой клъстери:
където n е броят на наблюденията в набора от данни.
На практика си струва да отделите време за търсене на стойността на k, която най-добре отговаря на нуждите на бизнеса.
Ще използваме набора от данни за цените на персоналните компютри, за да извършим нашия анализ на клъстери. Този набор от данни съдържа 6259 наблюдения и 10 функции. Наборът от данни наблюдава цената от 1993 г. до 1995 г. на 486 персонални компютъра в САЩ. Променливите са цена, скорост, ram, екран, cd между другото.
Ще продължите както следва:
- Импортиране на данни
- Обучете модела
- Оценете модела
Импортиране на данни
K-means не е подходящ за факторни променливи, защото работи с разстояния, а дискретните етикети нямат смислено разстояние между тях. Премахнете трите категорични колони (cd, multi, premium) заедно с индекса на реда X. Този набор от данни не съдържа липсващи стойности.
library(dplyr) PATH <-"https://raw.githubusercontent.com/guru99-edu/R-Programming/master/computers.csv" df <- read.csv(PATH) %>% select(-c(X, cd, multi, premium)) glimpse(df)
Продукция
## Observations: 6,259 ## Variables: 7 ## $ price <int> 1499, 1795, 1595, 1849, 3295, 3695, 1720, 1995, 2225, 2... ## $ speed <int> 25, 33, 25, 25, 33, 66, 25, 50, 50, 50, 33, 66, 50, 25, ... ## $ hd <int> 80, 85, 170, 170, 340, 340, 170, 85, 210, 210, 170, 210... ## $ ram <int> 4, 2, 4, 8, 16, 16, 4, 2, 8, 4, 8, 8, 4, 8, 8, 4, 2, 4, ... ## $ screen <int> 14, 14, 15, 14, 14, 14, 14, 14, 14, 15, 15, 14, 14, 14, ... ## $ ads <int> 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, ... ## $ trend <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...
От обобщената статистика можете да видите, че данните имат големи стойности. Добра практика преди прилагането на метод, базиран на разстояние, е да се стандартизират данните, така че всяка променлива да има средна стойност от нула и стандартно отклонение от едноБез него цената, чиито стойности достигат хиляди, би доминирала при изчисляването на разстоянието, а размерът на екрана би имал почти никакво значение.
summary(df)
Изход:
## price speed hd ram ## Min. : 949 Min. : 25.00 Min. : 80.0 Min. : 2.000 ## 1st Qu.:1794 1st Qu.: 33.00 1st Qu.: 214.0 1st Qu.: 4.000 ## Median :2144 Median : 50.00 Median : 340.0 Median : 8.000 ## Mean :2220 Mean : 52.01 Mean : 416.6 Mean : 8.287 ## 3rd Qu.:2595 3rd Qu.: 66.00 3rd Qu.: 528.0 3rd Qu.: 8.000 ## Max. :5399 Max. :100.00 Max. :2100.0 Max. :32.000 ## screen ads trend ## Min. :14.00 Min. : 39.0 Min. : 1.00 ## 1st Qu.:14.00 1st Qu.:162.5 1st Qu.:10.00 ## Median :14.00 Median :246.0 Median :16.00 ## Mean :14.61 Mean :221.3 Mean :15.93 ## 3rd Qu.:15.00 3rd Qu.:275.0 3rd Qu.:21.50 ## Max. :17.00 Max. :339.0 Max. :35.00
Премащабирате променливите с функцията scale() на библиотеката dplyr. Трансформацията намалява влиянието на отклоненията и позволява да се сравни едно единствено наблюдение със средната стойност. Ако стандартизирана стойност (или Z-скор) е висока, можете да бъдете уверени, че това наблюдение наистина е над средната (голям z-резултат означава, че тази точка е далеч от средната стойност по отношение на стандартното отклонение. Z-резултат от две показва, че стойността е 2 стандартна отклонения от средната стойност Забележете, z-резултатът следва гаусово разпределение и е симетричен около средната стойност.
# Note: speed is deliberately left out of the scaled data frame rescale_df <- df %>% mutate(price_scal = scale(price), hd_scal = scale(hd), ram_scal = scale(ram), screen_scal = scale(screen), ads_scal = scale(ads), trend_scal = scale(trend)) %>% select(-c(price, speed, hd, ram, screen, ads, trend))
R base има функция за изпълнение на алгоритъма за k средна стойност. Основната функция на k mean е:
kmeans(df, k) arguments: -df: dataset used to run the algorithm -k: Number of clusters
Обучете модела
На фигура три е показано подробно как работи алгоритъмът. Можете да наблюдавате всяка стъпка графично с анимационния пакет, написан от Yihui Xie, който е създал и knitr за R Markdown. Пакетът не е в conda каналите, така че го инсталирайте от CRAN:
install.packages("animation")
След като заредите библиотеката, добавяте .ani след kmeans и R ще начертае всички стъпки. За целите на илюстрацията изпълнявате само алгоритъма с премащабираните променливи hd и ram с три клъстера.
set.seed(2345) library(animation) kmeans.ani(rescale_df[2:3], 3)
Code Обяснение
- kmeans.ani(rescale_df[2:3], 3): Изберете колони 2 и 3 от набора от данни rescale_df и стартирайте алгоритъма с k, задавани на 3. Начертайте анимацията.
Можете да интерпретирате анимацията по следния начин:
- Стъпка 1: R произволно избира три точки
- Стъпка 2: Изчислете евклидовото разстояние и начертайте клъстерите. Имате един клъстер в зелено долу вляво, един голям клъстер, оцветен в черно вдясно и един червен между тях.
- Стъпка 3: Изчислете центроида, т.е. средната стойност на клъстерите
- Повторете, докато данните не променят клъстера
Алгоритъмът се събра след седем итерации. Можете да стартирате алгоритъма на k-mean в нашия набор от данни с пет клъстера и да го наречете pc_cluster.
pc_cluster <-kmeans(rescale_df, 5)
Списъкът pc_cluster съдържа седем полезни елемента:
- pc_cluster$cluster: Клъстерът, присвоен на всяко наблюдение
- pc_cluster$centers: Клъстерните центрове
- pc_cluster$totss: Общата сума на квадратите
- pc_cluster$withinss: В рамките на сумата от квадрати, една стойност на клъстер
- pc_cluster$tot.withinss: Сумата на withinss
- pc_cluster$betweenss: Обща сума на квадратите минус вътрешната сума на квадратите
- pc_cluster$size: Брой наблюдения във всеки клъстер
Вие ще използвате сумата от вътрешната сума на квадрат (т.е. tot.withinss), за да изчислите оптималния брой клъстери k. Намирането на k наистина е съществена задача.
Как да намерим оптималното k с метода на лакътя
Една техника за избор на най-доброто k се нарича метод на лакътя. Този метод използва вътрешногрупова хомогенност или вътрешногрупова хетерогенност за оценка на променливостта. С други думи, интересувате се от процента на дисперсията, обяснен от всеки клъстер. Можете да очаквате променливостта да се увеличи с броя на клъстерите, алтернативно хетерогенността намалява. Нашето предизвикателство е да намерим k, което е отвъд намаляващата възвръщаемост. Добавянето на нов клъстер не подобрява променливостта на данните, тъй като остава много малко информация за обяснение.
В този урок намираме тази точка, използвайки мярката за хетерогенност. Общата сума на квадратите в клъстерите е tot.withinss в списъка, върнат от kmean().
Можете да конструирате лакътната графика и да намерите оптималното k, както следва:
- Стъпка 1: Конструирайте функция за изчисляване на общата сума на квадратите в клъстерите
- Стъпка 2: Изпълнете алгоритъма в диапазон от k стойности
- Стъпка 3: Създайте рамка с данни с резултатите от алгоритъма
- Стъпка 4: График на резултатите
Стъпка 1) Конструирайте функция за изчисляване на общата сума на квадратите в клъстерите
Вие създавате функцията, която изпълнява алгоритъма на k-средната стойност и съхранява сумата от квадрати в клъстерите
kmean_withinss <- function(k) { cluster <- kmeans(rescale_df, k) return (cluster$tot.withinss) }
Code Обяснение
- функция (k): Задайте броя на аргументите във функцията
- kmeans(rescale_df, k): Изпълнете алгоритъма за тази стойност на k
- return(cluster$tot.withinss): Съхранявайте общата сума на квадратите в клъстерите
Тествайте функцията с k равно на 2.
Изход:
## Try with 2 cluster
kmean_withinss(2)
Изход:
## [1] 27087.07
Стъпка 2) Стартирайте алгоритъма n пъти
Ще използвате функцията sapply(), за да изпълните алгоритъма в диапазон от k. Тази техника е по-бърза от създаването на цикъл и съхраняването на стойността.
# Set maximum cluster max_k <-20 # Run algorithm over a range of k wss <- sapply(2:max_k, kmean_withinss)
Code Обяснение
- max_k <- 20: Задайте максималната стойност на k на 20
- sapply(2:max_k, kmean_withinss): Изпълнете функцията kmean_withinss() в диапазон 2:max_k, т.е. 2 до 20.
Стъпка 3) Създайте рамка от данни с резултатите от алгоритъма
След като функцията е написана и тествана, изпълнете я в диапазона от 2 до 20 и запазете всяка стойност на tot.withinss.
# Create a data frame to plot the graph elbow <-data.frame(2:max_k, wss)
Code Обяснение
- data.frame(2:max_k, wss): Създайте рамка с данни с изхода на алгоритъма, съхраняван в wss
Стъпка 4) Начертайте резултатите
Начертавате графиката, за да визуализирате къде е точката на лакътя
# Plot the graph with gglop ggplot(elbow, aes(x = X2.max_k, y = wss)) + geom_point() + geom_line() + scale_x_continuous(breaks = seq(1, 20, by = 1))
От графиката можете да видите, че оптималното k е седем, където кривата започва да има намаляваща възвръщаемост.
След като получите нашето оптимално k, стартирате отново алгоритъма с k равно на 7 и оценявате клъстерите.
Разглеждане на клъстерите
pc_cluster_2 <-kmeans(rescale_df, 7)
Както споменахме преди, можете да получите достъп до останалата интересна информация в списъка, върнат от kmean().
pc_cluster_2$cluster pc_cluster_2$centers pc_cluster_2$size
Оценката е субективна и зависи от това за какво са предназначени клъстерите. Целта тук е да се групират компютри с подобни спецификации. Експерт в областта би могъл да направи това ръчно, но процесът би бил бавен и податлив на грешки. K-средните групират...ping обективно и оставя на експерта да интерпретира и назове резултата.
Като предварителна оценка можете да проверите размера на клъстерите.
pc_cluster_2$size
Изход:
## [1] 608 1596 1231 580 1003 699 542
Най-големият клъстер, номер 2, съдържа 1,596 наблюдения, докато най-малкият, номер 7, съдържа само 542 компютъра. Може би е добре да има хомогенност между клъстерите, ако не е така, може да се наложи по-рядка подготовка на данните.
С централния компонент получавате по-задълбочен поглед върху данните. Редовете се отнасят до номерацията на клъстера, а колоните - до променливите, използвани от алгоритъма. Стойностите са средният резултат за всеки клъстер за интересуващата колона. Стандартизацията улеснява интерпретацията. Положителните стойности показват, че z-резултатът за даден клъстер е над общата средна стойност. Например, клъстер 4 има най-висока средна цена (price_scal = 1.09), докато клъстер 5 има най-ниската (-0.82).
center <-pc_cluster_2$centers center
Изход:
## price_scal hd_scal ram_scal screen_scal ads_scal trend_scal ## 1 -0.6372457 -0.7097995 -0.691520682 -0.4401632 0.6780366 -0.3379751 ## 2 -0.1323863 0.6299541 0.004786730 2.6419582 -0.8894946 1.2673184 ## 3 0.8745816 0.2574164 0.513105797 -0.2003237 0.6734261 -0.3300536 ## 4 1.0912296 -0.2401936 0.006526723 2.6419582 0.4704301 -0.4132057 ## 5 -0.8155183 0.2814882 -0.307621003 -0.3205176 -0.9052979 1.2177279 ## 6 0.8830191 2.1019454 2.168706085 0.4492922 -0.9035248 1.2069855 ## 7 0.2215678 -0.7132577 -0.318050275 -0.3878782 -1.3206229 -1.5490909
Можете да създадете топлинна карта с ggplot, за да ни помогнете да подчертаем разликата между категориите.
Цветовете по подразбиране на ggplot трябва да бъдат променени с библиотеката RColorBrewer. Можете да използвате conda библиотека и кода за стартиране в терминала:
conda install -c r r-rcolorbrewer
За да създадете топлинна карта, трябва да продължите в три стъпки:
- Изградете рамка от данни със стойностите на центъра и създайте променлива с номера на клъстера
- Преоформете данните с функцията gather() на библиотеката tidyr. Искате да трансформирате данни от широки към дълги.
- Създайте палитрата от цветове с цвятRampФункция Palette().
Стъпка 1) Изградете рамка за данни
Нека създадем набора от данни за преоформяне
library(tidyr) # create dataset with the cluster number cluster <- c(1: 7) center_df <- data.frame(cluster, center) # Reshape the data center_reshape <- gather(center_df, features, values, price_scal: trend_scal) head(center_reshape)
Изход:
## cluster features values ## 1 1 price_scal -0.6372457 ## 2 2 price_scal -0.1323863 ## 3 3 price_scal 0.8745816 ## 4 4 price_scal 1.0912296 ## 5 5 price_scal -0.8155183 ## 6 6 price_scal 0.8830191
Стъпка 2) Създайте цветовата палитра
Кодът по-долу изгражда палитрата от цветове, използвани от топлинната карта.
library(RColorBrewer) # Create the palette hm.palette <-colorRampPalette(rev(brewer.pal(10, 'RdYlGn')),space='Lab')
Стъпка 3) Визуализирайте
Можете да начертаете графиката и да видите как изглеждат клъстерите.
# Plot the heat map ggplot(data = center_reshape, aes(x = features, y = cluster, fill = values)) + scale_y_continuous(breaks = seq(1, 7, by = 1)) + geom_tile() + coord_equal() + scale_fill_gradientn(colours = hm.palette(90)) + theme_classic()
Как да получите възпроизводими K-средни резултати със set.seed() и nstart
В урока се отбелязва, че k-means връща различни групи при всяко изпълнение. Това не е странност, с която да се живее, а проблем с две стандартни решения, и нито едно от тях не се използва в горните примери.
1. Фиксирайте началната точка с set.seed(). Първоначалните центроиди се изтеглят на случаен принцип, така че едно и също извикване произвежда различни клъстери всеки път. Задаването на начален елемент прави целия анализ възпроизводим:
set.seed(123)
pc_cluster_2 <- kmeans(rescale_df, 7)
2. Изпълнете няколко стартирания и запазете най-доброто с nstart. Единичен случаен старт може да се сближи до лош локален оптимум. Аргументът nstart изпълнява алгоритъма многократно от различни случайни стартове и връща този с най-малък общ резултат в рамките на сумата от квадрати:
set.seed(123)
pc_cluster_2 <- kmeans(rescale_df, centers = 7, nstart = 25)
Двадесет и пет старта е обичайната препоръка и струва много малко при набор от данни с такъв размер. Без тях, самата крива на лакътя става нестабилна, защото всяка точка на графиката идва от един-единствен лош или щастлив старт. Следователно функцията kmean_withinss(), дефинирана по-рано, трябва да бъде записана като:
kmean_withinss <- function(k) { cluster <- kmeans(rescale_df, centers = k, nstart = 25) return (cluster$tot.withinss) }
3. Увеличете iter.max, ако алгоритъмът предупреди. Ако R отчете „не се е сближило след 10 итерации“, предайте iter.max = 50, за да му дадете повече място.
K-средни срещу йерархични Clusterв R
K-means не е единственият наличен метод за клъстеризиране и изборът обикновено се свежда до размера на данните и дали вече знаете колко групи искате.
| Критерии | К-средства | йерархически |
|---|---|---|
| Брой клъстери | Трябва да се избере предварително | Избран след това, чрез изрязване на дендрограмата |
| Стабилност на резултатите | Варира в зависимост от случайния старт | Детерминистичен |
| скалируемост | Обработва много големи набори от данни | Проблеми отвъд няколко хиляди реда |
| Cluster оформянето | Предполага приблизително сферични, сходни по размер групи | По-гъвкав |
| Продукция | Плосък набор от етикети | Дендрограма, показваща вложена структура |
| R функция | kmeans(df, k) | hclust(разстояние(df)) |
# Hierarchical alternative on the same scaled data hc <- hclust(dist(rescale_df), method = "ward.D2") plot(hc) groups <- cutree(hc, k = 7)
С 6,259 наблюдения, йерархичното клъстериране трябва да изгради матрица на разстоянията от приблизително 19.6 милиона двойки, поради което k-means е практичният избор за този набор от данни. Обърнете внимание също, че k-means приема клъстери с подобен размер и приблизително сферична форма; когато това предположение е неуспешно, DBSCAN обработва неправилни форми и идентифицира отклонения, вместо да насилствено групира всяка точка.
К-средства Clusterинг в R: Справочник на функции
Всяка функция, използвана в този урок, е изброена по-долу:
| Пакет | Цел | функция | аргумент |
|---|---|---|---|
| база | Тренирайте k-средно | kmeans() | df, k |
| Клъстер за достъп | kmeans()$cluster | ||
| Cluster центрове | kmeans()$centers | ||
| Cluster размери | kmeans()$size | ||
| Общо в рамките на сумата от квадрати | kmeans()$tot.withinss | Използва се по метода на лакътя | |
| Между сумата от квадрати | kmeans()$betweens | ||
| база | Възпроизводим цикъл | set.seed() | стойност на семената |
| база | Стабилизиране на резултата | kmeans(df, k, nstart = 25) | нстарт |








