You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
642 lines
46 KiB
642 lines
46 KiB
{
|
|
"nbformat": 4,
|
|
"nbformat_minor": 0,
|
|
"metadata": {
|
|
"anaconda-cloud": "",
|
|
"kernelspec": {
|
|
"display_name": "R",
|
|
"language": "R",
|
|
"name": "ir"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": "r",
|
|
"file_extension": ".r",
|
|
"mimetype": "text/x-r-source",
|
|
"name": "R",
|
|
"pygments_lexer": "r",
|
|
"version": "3.4.1"
|
|
},
|
|
"colab": {
|
|
"name": "lesson_14.ipynb",
|
|
"provenance": [],
|
|
"collapsed_sections": [],
|
|
"toc_visible": true
|
|
},
|
|
"coopTranslator": {
|
|
"original_hash": "ad65fb4aad0a156b42216e4929f490fc",
|
|
"translation_date": "2025-12-19T16:53:53+00:00",
|
|
"source_file": "5-Clustering/2-K-Means/solution/R/lesson_15-R.ipynb",
|
|
"language_code": "te"
|
|
}
|
|
},
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "GULATlQXLXyR"
|
|
},
|
|
"source": [
|
|
"## R మరియు Tidy డేటా సూత్రాలను ఉపయోగించి K-Means క్లస్టరింగ్ను అన్వేషించండి.\n",
|
|
"\n",
|
|
"### [**పూర్వ-లెక్చర్ క్విజ్**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/29/)\n",
|
|
"\n",
|
|
"ఈ పాఠంలో, మీరు Tidymodels ప్యాకేజీ మరియు R ఎకోసిస్టమ్లోని ఇతర ప్యాకేజీలను (మేము వాటిని స్నేహితులు 🧑🤝🧑 అని పిలుస్తాము) ఉపయోగించి క్లస్టర్లను ఎలా సృష్టించాలో నేర్చుకుంటారు, మరియు మీరు ముందుగా దిగుమతి చేసిన నైజీరియన్ సంగీత డేటాసెట్ను ఉపయోగిస్తారు. మేము K-Means క్లస్టరింగ్ యొక్క ప్రాథమిక అంశాలను కవర్ చేస్తాము. మీరు ముందుగా నేర్చుకున్నట్లుగా, క్లస్టర్లతో పని చేయడానికి అనేక మార్గాలు ఉన్నాయి మరియు మీరు ఉపయోగించే పద్ధతి మీ డేటాపై ఆధారపడి ఉంటుంది. K-Means ను ప్రయత్నిస్తాము ఎందుకంటే ఇది అత్యంత సాధారణ క్లస్టరింగ్ సాంకేతికత. మొదలు పెడదాం!\n",
|
|
"\n",
|
|
"మీరు నేర్చుకునే పదాలు:\n",
|
|
"\n",
|
|
"- సిల్హౌట్ స్కోరింగ్\n",
|
|
"\n",
|
|
"- ఎల్బో పద్ధతి\n",
|
|
"\n",
|
|
"- ఇనర్షియా\n",
|
|
"\n",
|
|
"- వైవిధ్యం\n",
|
|
"\n",
|
|
"### **పరిచయం**\n",
|
|
"\n",
|
|
"[K-Means క్లస్టరింగ్](https://wikipedia.org/wiki/K-means_clustering) సిగ్నల్ ప్రాసెసింగ్ డొమైన్ నుండి ఉద్భవించిన పద్ధతి. ఇది డేటా గుంపులను వారి లక్షణాలలో సారూప్యతల ఆధారంగా `k క్లస్టర్లుగా` విభజించడానికి ఉపయోగిస్తారు.\n",
|
|
"\n",
|
|
"క్లస్టర్లు [Voronoi డయాగ్రామ్స్](https://wikipedia.org/wiki/Voronoi_diagram) గా దృశ్యమానమవుతాయి, ఇవి ఒక పాయింట్ (లేదా 'సీడ్') మరియు దాని సంబంధిత ప్రాంతాన్ని కలిగి ఉంటాయి.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../../../../../translated_images/te/voronoi.1dc1613fb0439b95.webp\"\n",
|
|
" width=\"500\"/>\n",
|
|
" <figcaption>ఇన్ఫోగ్రాఫిక్ జెన్ లూపర్ ద్వారా</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"K-Means క్లస్టరింగ్ క్రింది దశలను కలిగి ఉంటుంది:\n",
|
|
"\n",
|
|
"1. డేటా శాస్త్రవేత్త మొదట సృష్టించవలసిన క్లస్టర్ల సంఖ్యను నిర్దేశిస్తారు.\n",
|
|
"\n",
|
|
"2. తరువాత, అల్గోరిథం డేటా సెట్ నుండి యాదృచ్ఛికంగా K పరిశీలనలను ఎంపిక చేసి అవి క్లస్టర్ల ప్రారంభ కేంద్రాలుగా (అంటే, సెంట్రాయిడ్లు) ఉపయోగిస్తారు.\n",
|
|
"\n",
|
|
"3. తరువాత, మిగిలిన ప్రతి పరిశీలనను దాని సమీప సెంట్రాయిడ్కు కేటాయిస్తారు.\n",
|
|
"\n",
|
|
"4. తరువాత, ప్రతి క్లస్టర్ యొక్క కొత్త సగటును లెక్కించి సెంట్రాయిడ్ను ఆ సగటుకు తరలిస్తారు.\n",
|
|
"\n",
|
|
"5. ఇప్పుడు కేంద్రాలు పునః లెక్కించబడ్డాయి, ప్రతి పరిశీలనను మరో క్లస్టర్కు సమీపంగా ఉందా అని మళ్లీ తనిఖీ చేస్తారు. అన్ని అంశాలను నవీకరించిన క్లస్టర్ సగటులను ఉపయోగించి మళ్లీ కేటాయిస్తారు. క్లస్టర్ కేటాయింపు మరియు సెంట్రాయిడ్ నవీకరణ దశలను పునరావృతంగా చేస్తారు, క్లస్టర్ కేటాయింపులు మారడం ఆగేవరకు (అంటే, సమీకరణ సాధించబడినప్పుడు). సాధారణంగా, ప్రతి కొత్త పునరావృతం సెంట్రాయిడ్ల కదలిక తక్కువగా ఉన్నప్పుడు మరియు క్లస్టర్లు స్థిరంగా ఉన్నప్పుడు అల్గోరిథం ముగుస్తుంది.\n",
|
|
"\n",
|
|
"<div>\n",
|
|
"\n",
|
|
"> ప్రారంభ సెంట్రాయిడ్లుగా ఉపయోగించే యాదృచ్ఛిక k పరిశీలనల కారణంగా, ప్రతి సారి ఈ ప్రక్రియను అమలు చేసినప్పుడు కొంత భిన్నమైన ఫలితాలు రావచ్చు. అందుకే, ఎక్కువ అల్గోరిథములు అనేక *యాదృచ్ఛిక ప్రారంభాలు* ఉపయోగించి, తక్కువ WCSS ఉన్న పునరావృతాన్ని ఎంచుకుంటాయి. కాబట్టి, *అనుచిత స్థానిక గరిష్ఠాన్ని* నివారించడానికి ఎప్పుడూ K-Means ను అనేక *nstart* విలువలతో నడపడం బలంగా సిఫార్సు చేయబడుతుంది.\n",
|
|
"\n",
|
|
"</div>\n",
|
|
"\n",
|
|
"Allison Horst యొక్క [కళాకృతి](https://github.com/allisonhorst/stats-illustrations) ఉపయోగించి ఈ చిన్న యానిమేషన్ క్లస్టరింగ్ ప్రక్రియను వివరిస్తుంది:\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../images/kmeans.gif\"\n",
|
|
" width=\"550\"/>\n",
|
|
" <figcaption>@allison_horst కళాకృతి</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"క్లస్టరింగ్లో ఉత్పన్నమయ్యే ఒక ప్రాథమిక ప్రశ్న ఇది: మీ డేటాను ఎన్ని క్లస్టర్లుగా విభజించాలో మీరు ఎలా తెలుసుకుంటారు? K-Means ఉపయోగించడంలో ఒక లోపం ఏమిటంటే, మీరు `k` ను, అంటే `సెంట్రాయిడ్ల సంఖ్య` ను నిర్ణయించవలసి ఉంటుంది. అదృష్టవశాత్తు `ఎల్బో పద్ధతి` మంచి ప్రారంభ విలువను అంచనా వేయడంలో సహాయపడుతుంది. మీరు దీన్ని కొద్దిసేపట్లో ప్రయత్నిస్తారు.\n",
|
|
"\n",
|
|
"### \n",
|
|
"\n",
|
|
"**ముందస్తు అవసరం**\n",
|
|
"\n",
|
|
"మేము [మునుపటి పాఠం](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb) నుండి ఆపకుండా కొనసాగుతాము, అక్కడ మేము డేటా సెట్ను విశ్లేషించి, అనేక దృశ్యీకరణలు చేశాము మరియు ఆసక్తికరమైన పరిశీలనలకు డేటా సెట్ను ఫిల్టర్ చేసాము. దాన్ని తప్పకుండా చూడండి!\n",
|
|
"\n",
|
|
"ఈ మాడ్యూల్ను పూర్తి చేయడానికి కొన్ని ప్యాకేజీలు అవసరం. మీరు వాటిని ఇలాగే ఇన్స్టాల్ చేసుకోవచ్చు: `install.packages(c('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork'))`\n",
|
|
"\n",
|
|
"వేరే విధంగా, క్రింది స్క్రిప్ట్ ఈ మాడ్యూల్ను పూర్తి చేయడానికి అవసరమైన ప్యాకేజీలు మీ వద్ద ఉన్నాయా లేదా అని తనిఖీ చేసి, కొన్నివి లేకపోతే వాటిని ఇన్స్టాల్ చేస్తుంది.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "ah_tBi58LXyi"
|
|
},
|
|
"source": [
|
|
"suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\n",
|
|
"\n",
|
|
"pacman::p_load('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork')\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "7e--UCUTLXym"
|
|
},
|
|
"source": [
|
|
"మనం వెంటనే ప్రారంభిద్దాం!\n",
|
|
"\n",
|
|
"## 1. డేటాతో నృత్యం: 3 అత్యంత ప్రాచుర్యం పొందిన సంగీత శైలులను తగ్గించుకోండి\n",
|
|
"\n",
|
|
"ఇది మునుపటి పాఠంలో మనం చేసినదానికి ఒక సారాంశం. మనం కొంత డేటాను కట్ చేసి, విశ్లేషిద్దాం!\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "Ycamx7GGLXyn"
|
|
},
|
|
"source": [
|
|
"# Load the core tidyverse and make it available in your current R session\n",
|
|
"library(tidyverse)\n",
|
|
"\n",
|
|
"# Import the data into a tibble\n",
|
|
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/5-Clustering/data/nigerian-songs.csv\", show_col_types = FALSE)\n",
|
|
"\n",
|
|
"# Narrow down to top 3 popular genres\n",
|
|
"nigerian_songs <- df %>% \n",
|
|
" # Concentrate on top 3 genres\n",
|
|
" filter(artist_top_genre %in% c(\"afro dancehall\", \"afropop\",\"nigerian pop\")) %>% \n",
|
|
" # Remove unclassified observations\n",
|
|
" filter(popularity != 0)\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"# Visualize popular genres using bar plots\n",
|
|
"theme_set(theme_light())\n",
|
|
"nigerian_songs %>%\n",
|
|
" count(artist_top_genre) %>%\n",
|
|
" ggplot(mapping = aes(x = artist_top_genre, y = n,\n",
|
|
" fill = artist_top_genre)) +\n",
|
|
" geom_col(alpha = 0.8) +\n",
|
|
" paletteer::scale_fill_paletteer_d(\"ggsci::category10_d3\") +\n",
|
|
" ggtitle(\"Top genres\") +\n",
|
|
" theme(plot.title = element_text(hjust = 0.5))\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "b5h5zmkPLXyp"
|
|
},
|
|
"source": [
|
|
"🤩 అది బాగానే జరిగింది!\n",
|
|
"\n",
|
|
"## 2. మరిన్ని డేటా అన్వేషణ.\n",
|
|
"\n",
|
|
"ఈ డేటా ఎంత శుభ్రంగా ఉంది? బాక్స్ ప్లాట్లను ఉపయోగించి అవుట్లయర్లను తనిఖీ చేద్దాం. మేము తక్కువ అవుట్లయర్లతో ఉన్న సంఖ్యాత్మక కాలమ్స్పై దృష్టి సారిస్తాము (అయితే మీరు అవుట్లయర్లను శుభ్రం చేయవచ్చు). బాక్స్ప్లాట్లు డేటా పరిధిని చూపగలవు మరియు ఏ కాలమ్స్ ఉపయోగించాలో ఎంచుకోవడంలో సహాయపడతాయి. గమనించండి, బాక్స్ప్లాట్లు వ్యత్యాసాన్ని చూపవు, ఇది మంచి క్లస్టరబుల్ డేటా యొక్క ముఖ్యమైన అంశం. మరింత చదవడానికి [ఈ చర్చ](https://stats.stackexchange.com/questions/91536/deduce-variance-from-boxplot) చూడండి.\n",
|
|
"\n",
|
|
"[బాక్స్ప్లాట్లు](https://en.wikipedia.org/wiki/Box_plot) సంఖ్యాత్మక డేటా పంపిణీని గ్రాఫికల్గా చూపడానికి ఉపయోగిస్తారు, కాబట్టి ప్రాచుర్యం పొందిన సంగీత శైలులతో పాటు అన్ని సంఖ్యాత్మక కాలమ్స్ను *ఎంచుకోవడం* ప్రారంభిద్దాం.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "HhNreJKLLXyq"
|
|
},
|
|
"source": [
|
|
"# Select top genre column and all other numeric columns\n",
|
|
"df_numeric <- nigerian_songs %>% \n",
|
|
" select(artist_top_genre, where(is.numeric)) \n",
|
|
"\n",
|
|
"# Display the data\n",
|
|
"df_numeric %>% \n",
|
|
" slice_head(n = 5)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "uYXrwJRaLXyq"
|
|
},
|
|
"source": [
|
|
"ఎలా సెలక్షన్ హెల్పర్ `where` దీన్ని సులభం చేస్తుందో చూడండి 💁? ఇలాంటి ఇతర ఫంక్షన్లను [ఇక్కడ](https://tidyselect.r-lib.org/) అన్వేషించండి.\n",
|
|
"\n",
|
|
"ప్రతి సంఖ్యా లక్షణానికి బాక్స్ప్లాట్ తయారు చేయబోతున్నాము మరియు లూప్లను ఉపయోగించకుండా ఉండాలనుకుంటున్నాము, కాబట్టి మన డేటాను *దీర్ఘమైన* ఫార్మాట్లో పునఃరూపకల్పన చేద్దాం, ఇది మనకు `facets` - ప్రతి ఉపసమితి డేటాను ప్రదర్శించే ఉపగ్రాఫ్లను ఉపయోగించుకునే అవకాశం ఇస్తుంది.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "gd5bR3f8LXys"
|
|
},
|
|
"source": [
|
|
"# Pivot data from wide to long\n",
|
|
"df_numeric_long <- df_numeric %>% \n",
|
|
" pivot_longer(!artist_top_genre, names_to = \"feature_names\", values_to = \"values\") \n",
|
|
"\n",
|
|
"# Print out data\n",
|
|
"df_numeric_long %>% \n",
|
|
" slice_head(n = 15)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "-7tE1swnLXyv"
|
|
},
|
|
"source": [
|
|
"ఇంకా చాలా పొడవుగా! ఇప్పుడు కొంత `ggplots` సమయం! కాబట్టి ఏ `geom` ను ఉపయోగించబోతున్నాం?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "r88bIsyuLXyy"
|
|
},
|
|
"source": [
|
|
"# Make a box plot\n",
|
|
"df_numeric_long %>% \n",
|
|
" ggplot(mapping = aes(x = feature_names, y = values, fill = feature_names)) +\n",
|
|
" geom_boxplot() +\n",
|
|
" facet_wrap(~ feature_names, ncol = 4, scales = \"free\") +\n",
|
|
" theme(legend.position = \"none\")\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "EYVyKIUELXyz"
|
|
},
|
|
"source": [
|
|
"Easy-gg!\n",
|
|
"\n",
|
|
"ఇప్పుడు మనం ఈ డేటా కొంచెం శబ్దంగా ఉందని చూడవచ్చు: ప్రతి కాలమ్ను బాక్స్ప్లాట్గా పరిశీలించడం ద్వారా, మీరు అవుట్లయర్లను చూడవచ్చు. మీరు డేటాసెట్ను గమనించి ఈ అవుట్లయర్లను తొలగించవచ్చు, కానీ అది డేటాను చాలా తక్కువగా చేస్తుంది.\n",
|
|
"\n",
|
|
"ప్రస్తుతం, మనం క్లస్టరింగ్ వ్యాయామం కోసం ఉపయోగించబోయే కాలమ్లను ఎంచుకుందాం. సమాన పరిధులున్న సంఖ్యాత్మక కాలమ్లను ఎంచుకుందాం. మనం `artist_top_genre` ను సంఖ్యాత్మకంగా ఎన్కోడ్ చేయవచ్చు కానీ ఇప్పటికీ దాన్ని వదిలేస్తాము.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "-wkpINyZLXy0"
|
|
},
|
|
"source": [
|
|
"# Select variables with similar ranges\n",
|
|
"df_numeric_select <- df_numeric %>% \n",
|
|
" select(popularity, danceability, acousticness, loudness, energy) \n",
|
|
"\n",
|
|
"# Normalize data\n",
|
|
"# df_numeric_select <- scale(df_numeric_select)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "D7dLzgpqLXy1"
|
|
},
|
|
"source": [
|
|
"## 3. R లో k-means క్లస్టరింగ్ లెక్కించడం\n",
|
|
"\n",
|
|
"మనం R లో బిల్ట్-ఇన్ `kmeans` ఫంక్షన్ తో k-means లెక్కించవచ్చు, చూడండి `help(\"kmeans()\")`. `kmeans()` ఫంక్షన్ ప్రాథమిక ఆర్గ్యుమెంట్ గా అన్ని న్యూమరిక్ కాలమ్స్ ఉన్న డేటా ఫ్రేమ్ ను అంగీకరిస్తుంది.\n",
|
|
"\n",
|
|
"k-means క్లస్టరింగ్ ఉపయోగించే మొదటి దశ చివరి పరిష్కారంలో ఉత్పత్తి చేయబడే క్లస్టర్ల సంఖ్య (k) ను నిర్దేశించడం. మనం డేటాసెట్ నుండి 3 పాట జానర్లను తీసుకున్నామని తెలుసు, కాబట్టి 3 ను ప్రయత్నిద్దాం:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "uC4EQ5w7LXy5"
|
|
},
|
|
"source": [
|
|
"set.seed(2056)\n",
|
|
"# Kmeans clustering for 3 clusters\n",
|
|
"kclust <- kmeans(\n",
|
|
" df_numeric_select,\n",
|
|
" # Specify the number of clusters\n",
|
|
" centers = 3,\n",
|
|
" # How many random initial configurations\n",
|
|
" nstart = 25\n",
|
|
")\n",
|
|
"\n",
|
|
"# Display clustering object\n",
|
|
"kclust\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "hzfhscWrLXy-"
|
|
},
|
|
"source": [
|
|
"kmeans ఆబ్జెక్ట్లో `help(\"kmeans()\")` లో బాగా వివరించబడిన అనేక సమాచారం భాగాలు ఉంటాయి. ఇప్పటికీ, కొన్ని విషయాలపై దృష్టి పెట్టుకుందాం. డేటా 65, 110, 111 పరిమాణాల 3 క్లస్టర్లుగా విభజించబడిందని మనం చూస్తున్నాము. అవుట్పుట్లో 5 వేరియబుల్స్ అంతటా 3 గ్రూపుల క్లస్టర్ సెంటర్లు (సగటులు) కూడా ఉంటాయి.\n",
|
|
"\n",
|
|
"క్లస్టరింగ్ వెక్టర్ అనేది ప్రతి పరిశీలనకు క్లస్టర్ కేటాయింపు. అసలు డేటా సెట్కు క్లస్టర్ కేటాయింపును జోడించడానికి `augment` ఫంక్షన్ను ఉపయోగిద్దాం.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "0XwwpFGQLXy_"
|
|
},
|
|
"source": [
|
|
"# Add predicted cluster assignment to data set\n",
|
|
"augment(kclust, df_numeric_select) %>% \n",
|
|
" relocate(.cluster) %>% \n",
|
|
" slice_head(n = 10)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "NXIVXXACLXzA"
|
|
},
|
|
"source": [
|
|
"సరే, మనం ఇప్పుడు మన డేటా సెట్ను 3 గ్రూపుల సెట్గా విభజించాము. కాబట్టి, మన క్లస్టరింగ్ ఎంత మంచిదో చూద్దాం 🤷? మనం `Silhouette score` ని చూద్దాం\n",
|
|
"\n",
|
|
"### **Silhouette score**\n",
|
|
"\n",
|
|
"[Silhouette విశ్లేషణ](https://en.wikipedia.org/wiki/Silhouette_(clustering)) ఫలితంగా వచ్చిన క్లస్టర్ల మధ్య విడిపోవడం దూరాన్ని అధ్యయనం చేయడానికి ఉపయోగించవచ్చు. ఈ స్కోరు -1 నుండి 1 వరకు మారుతుంది, మరియు స్కోరు 1కి దగ్గరగా ఉంటే, క్లస్టర్ సాంద్రంగా ఉంటుంది మరియు ఇతర క్లస్టర్ల నుండి బాగా వేరుగా ఉంటుంది. 0కి దగ్గరగా ఉన్న విలువ సమీప క్లస్టర్లతో decision boundaryకి చాలా దగ్గరగా ఉన్న నమూనాలను సూచిస్తుంది.[source](https://dzone.com/articles/kmeans-silhouette-score-explained-with-python-exam).\n",
|
|
"\n",
|
|
"సగటు silhouette పద్ధతి వివిధ *k* విలువల కోసం పరిశీలనల సగటు silhouetteని లెక్కిస్తుంది. ఒక అధిక సగటు silhouette స్కోరు మంచి క్లస్టరింగ్ను సూచిస్తుంది.\n",
|
|
"\n",
|
|
"సగటు silhouette వెడల్పును లెక్కించడానికి cluster ప్యాకేజీలోని `silhouette` ఫంక్షన్ ఉపయోగించవచ్చు.\n",
|
|
"\n",
|
|
"> silhouetteని ఏదైనా [distance](https://en.wikipedia.org/wiki/Distance \"Distance\") మెట్రిక్తో లెక్కించవచ్చు, ఉదాహరణకు మనం [మునుపటి పాఠంలో](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb) చర్చించిన [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance \"Euclidean distance\") లేదా [Manhattan distance](https://en.wikipedia.org/wiki/Manhattan_distance \"Manhattan distance\") వంటి.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "Jn0McL28LXzB"
|
|
},
|
|
"source": [
|
|
"# Load cluster package\n",
|
|
"library(cluster)\n",
|
|
"\n",
|
|
"# Compute average silhouette score\n",
|
|
"ss <- silhouette(kclust$cluster,\n",
|
|
" # Compute euclidean distance\n",
|
|
" dist = dist(df_numeric_select))\n",
|
|
"mean(ss[, 3])\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "QyQRn97nLXzC"
|
|
},
|
|
"source": [
|
|
"మా స్కోరు **.549** ఉంది, కాబట్టి మధ్యలోనే ఉంది. ఇది మా డేటా ఈ రకమైన క్లస్టరింగ్కు ప్రత్యేకంగా అనుకూలంగా లేనట్టుగా సూచిస్తుంది. మనం ఈ అనుమానాన్ని దృశ్యరూపంలో నిర్ధారించగలమా చూద్దాం. [factoextra ప్యాకేజ్](https://rpkgs.datanovia.com/factoextra/index.html) క్లస్టరింగ్ను దృశ్యీకరించడానికి (`fviz_cluster()`) ఫంక్షన్లను అందిస్తుంది.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "7a6Km1_FLXzD"
|
|
},
|
|
"source": [
|
|
"library(factoextra)\n",
|
|
"\n",
|
|
"# Visualize clustering results\n",
|
|
"fviz_cluster(kclust, df_numeric_select)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "IBwCWt-0LXzD"
|
|
},
|
|
"source": [
|
|
"క్లస్టర్లలో ఉన్న ఓవర్ల్యాప్ మన డేటా ఈ రకమైన క్లస్టరింగ్కు ప్రత్యేకంగా అనుకూలంగా లేనట్టుగా సూచిస్తుంది కానీ మనం కొనసాగుదాం.\n",
|
|
"\n",
|
|
"## 4. ఉత్తమ క్లస్టర్లను నిర్ణయించడం\n",
|
|
"\n",
|
|
"K-Means క్లస్టరింగ్లో తరచుగా ఎదురయ్యే ఒక ప్రాథమిక ప్రశ్న ఇది - తెలియని క్లాస్ లేబుల్స్ లేకుండా, మీరు మీ డేటాను ఎన్ని క్లస్టర్లుగా విడగొట్టాలో ఎలా తెలుసుకుంటారు?\n",
|
|
"\n",
|
|
"మనం తెలుసుకోవడానికి ప్రయత్నించగల ఒక మార్గం డేటా నమూనాను ఉపయోగించి `క్లస్టర్ల సంఖ్య పెరుగుతూ` (ఉదా: 1-10 వరకు) క్లస్టరింగ్ మోడల్స్ సిరీస్ను సృష్టించడం, మరియు **సిల్హౌట్ స్కోర్** వంటి క్లస్టరింగ్ మెట్రిక్స్ను మూల్యాంకనం చేయడం.\n",
|
|
"\n",
|
|
"విభిన్న *k* విలువల కోసం క్లస్టరింగ్ అల్గోరిథమ్ను గణించి, **Within Cluster Sum of Squares** (WCSS) ను మూల్యాంకనం చేయడం ద్వారా ఉత్తమ క్లస్టర్ల సంఖ్యను నిర్ణయిద్దాం. మొత్తం వితిన్-క్లస్టర్ సమ్ ఆఫ్ స్క్వేర్ (WCSS) క్లస్టరింగ్ యొక్క సన్నిహితతను కొలుస్తుంది మరియు మనం దీన్ని όσο తక్కువగా ఉండాలని కోరుకుంటాము, తక్కువ విలువలు డేటా పాయింట్లు దగ్గరగా ఉన్నట్లు సూచిస్తాయి.\n",
|
|
"\n",
|
|
"1 నుండి 10 వరకు `k` యొక్క వివిధ ఎంపికల ప్రభావాన్ని ఈ క్లస్టరింగ్పై పరిశీలిద్దాం.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "hSeIiylDLXzE"
|
|
},
|
|
"source": [
|
|
"# Create a series of clustering models\n",
|
|
"kclusts <- tibble(k = 1:10) %>% \n",
|
|
" # Perform kmeans clustering for 1,2,3 ... ,10 clusters\n",
|
|
" mutate(model = map(k, ~ kmeans(df_numeric_select, centers = .x, nstart = 25)),\n",
|
|
" # Farm out clustering metrics eg WCSS\n",
|
|
" glanced = map(model, ~ glance(.x))) %>% \n",
|
|
" unnest(cols = glanced)\n",
|
|
" \n",
|
|
"\n",
|
|
"# View clustering rsulsts\n",
|
|
"kclusts\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "m7rS2U1eLXzE"
|
|
},
|
|
"source": [
|
|
"ఇప్పుడు మనకు ప్రతి క్లస్టరింగ్ అల్గోరిథం కోసం సెంటర్ *k* తో మొత్తం వితిన్-క్లస్టర్ సమ్-ఆఫ్-స్క్వేర్ల (tot.withinss) ఉంది, మనం [ఎల్బో పద్ధతి](https://en.wikipedia.org/wiki/Elbow_method_(clustering)) ఉపయోగించి ఆప్టిమల్ క్లస్టర్ల సంఖ్యను కనుగొంటాము. ఈ పద్ధతి క్లస్టర్ల సంఖ్య యొక్క ఫంక్షన్గా WCSS ను ప్లాట్ చేయడం మరియు వాడాల్సిన క్లస్టర్ల సంఖ్యగా [వక్ర రేఖ యొక్క ఎల్బో](https://en.wikipedia.org/wiki/Elbow_of_the_curve \"Elbow of the curve\") ను ఎంచుకోవడం కలిగి ఉంటుంది.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "o_DjHGItLXzF"
|
|
},
|
|
"source": [
|
|
"set.seed(2056)\n",
|
|
"# Use elbow method to determine optimum number of clusters\n",
|
|
"kclusts %>% \n",
|
|
" ggplot(mapping = aes(x = k, y = tot.withinss)) +\n",
|
|
" geom_line(size = 1.2, alpha = 0.8, color = \"#FF7F0EFF\") +\n",
|
|
" geom_point(size = 2, color = \"#FF7F0EFF\")\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "pLYyt5XSLXzG"
|
|
},
|
|
"source": [
|
|
"ప్లాట్ ఒక నుండి రెండు క్లస్టర్లకు సంఖ్య పెరిగినప్పుడు WCSSలో పెద్ద తగ్గుదల (కాబట్టి ఎక్కువ *టైట్నెస్*) చూపిస్తుంది, మరియు రెండు నుండి మూడు క్లస్టర్లకు మరింత గమనించదగిన తగ్గుదల ఉంటుంది. ఆ తర్వాత, తగ్గుదల తక్కువగా ఉంటుంది, ఫలితంగా చార్ట్లో సుమారు మూడు క్లస్టర్ల వద్ద ఒక `ఎల్బో` 💪 ఉంటుంది. ఇది రెండు నుండి మూడు తగినంతగా వేరు చేసిన డేటా పాయింట్ల క్లస్టర్లు ఉన్నాయని మంచి సూచన.\n",
|
|
"\n",
|
|
"ఇప్పుడు మనం `k = 3` ఉన్న క్లస్టరింగ్ మోడల్ను తీసుకోవచ్చు:\n",
|
|
"\n",
|
|
"> `pull()`: ఒకే కాలమ్ను తీసుకోవడానికి ఉపయోగిస్తారు\n",
|
|
">\n",
|
|
"> `pluck()`: జాబితాలు వంటి డేటా నిర్మాణాలను సూచించడానికి ఉపయోగిస్తారు\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "JP_JPKBILXzG"
|
|
},
|
|
"source": [
|
|
"# Extract k = 3 clustering\n",
|
|
"final_kmeans <- kclusts %>% \n",
|
|
" filter(k == 3) %>% \n",
|
|
" pull(model) %>% \n",
|
|
" pluck(1)\n",
|
|
"\n",
|
|
"\n",
|
|
"final_kmeans\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "l_PDTu8tLXzI"
|
|
},
|
|
"source": [
|
|
"చాలా బాగుంది! మనం పొందిన క్లస్టర్లను దృశ్యీకరించుకుందాం. `plotly` ఉపయోగించి కొంత ఇంటరాక్టివిటీ కావాలా?\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "dNcleFe-LXzJ"
|
|
},
|
|
"source": [
|
|
"# Add predicted cluster assignment to data set\n",
|
|
"results <- augment(final_kmeans, df_numeric_select) %>% \n",
|
|
" bind_cols(df_numeric %>% select(artist_top_genre)) \n",
|
|
"\n",
|
|
"# Plot cluster assignments\n",
|
|
"clust_plt <- results %>% \n",
|
|
" ggplot(mapping = aes(x = popularity, y = danceability, color = .cluster, shape = artist_top_genre)) +\n",
|
|
" geom_point(size = 2, alpha = 0.8) +\n",
|
|
" paletteer::scale_color_paletteer_d(\"ggthemes::Tableau_10\")\n",
|
|
"\n",
|
|
"ggplotly(clust_plt)\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "6JUM_51VLXzK"
|
|
},
|
|
"source": [
|
|
"ప్రతి క్లస్టర్ (వివిధ రంగులతో ప్రాతినిధ్యం వహించబడిన) వేర్వేరు జానర్లను (వివిధ ఆకారాలతో ప్రాతినిధ్యం వహించబడిన) కలిగి ఉంటుందని మనం ఆశించవచ్చు.\n",
|
|
"\n",
|
|
"మోడల్ యొక్క ఖచ్చితత్వాన్ని చూద్దాం.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"metadata": {
|
|
"id": "HdIMUGq7LXzL"
|
|
},
|
|
"source": [
|
|
"# Assign genres to predefined integers\n",
|
|
"label_count <- results %>% \n",
|
|
" group_by(artist_top_genre) %>% \n",
|
|
" mutate(id = cur_group_id()) %>% \n",
|
|
" ungroup() %>% \n",
|
|
" summarise(correct_labels = sum(.cluster == id))\n",
|
|
"\n",
|
|
"\n",
|
|
"# Print results \n",
|
|
"cat(\"Result:\", label_count$correct_labels, \"out of\", nrow(results), \"samples were correctly labeled.\")\n",
|
|
"\n",
|
|
"cat(\"\\nAccuracy score:\", label_count$correct_labels/nrow(results))\n"
|
|
],
|
|
"execution_count": null,
|
|
"outputs": []
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"id": "C50wvaAOLXzM"
|
|
},
|
|
"source": [
|
|
"ఈ మోడల్ యొక్క ఖచ్చితత్వం చెడుగా లేదు, కానీ గొప్పదిగా లేదు. డేటా K-Means క్లస్టరింగ్కు బాగా సరిపోవకపోవచ్చు. ఈ డేటా చాలా అసమతుల్యంగా ఉంది, చాలా తక్కువ సంబంధం ఉంది మరియు కాలమ్ విలువల మధ్య చాలా వ్యత్యాసం ఉంది కాబట్టి బాగా క్లస్టర్ చేయడం కష్టం. వాస్తవానికి, ఏర్పడే క్లస్టర్లు పైగా నిర్వచించిన మూడు జానర్ వర్గాల ద్వారా బలంగా ప్రభావితం లేదా వక్రీకృతమయ్యే అవకాశం ఉంది.\n",
|
|
"\n",
|
|
"అయితే, అది చాలా నేర్చుకునే ప్రక్రియ!\n",
|
|
"\n",
|
|
"Scikit-learn డాక్యుమెంటేషన్లో, మీరు ఇలాంటి మోడల్, క్లస్టర్లు బాగా వేరుగా లేని, 'వేరియన్స్' సమస్యను కలిగి ఉంటుందని చూడవచ్చు:\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../../../../../translated_images/te/problems.f7fb539ccd80608e.webp\"\n",
|
|
" width=\"500\"/>\n",
|
|
" <figcaption>Scikit-learn నుండి ఇన్ఫోగ్రాఫిక్</figcaption>\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"## **వేరియన్స్**\n",
|
|
"\n",
|
|
"వేరియన్స్ అనేది \"సగటు నుండి చదరపు తేడాల సగటు\"గా నిర్వచించబడింది [మూలం](https://www.mathsisfun.com/data/standard-deviation.html). ఈ క్లస్టరింగ్ సమస్య సందర్భంలో, ఇది మా డేటాసెట్ సంఖ్యలు సగటు నుండి కొంత ఎక్కువగా విభిన్నమవుతాయని సూచిస్తుంది.\n",
|
|
"\n",
|
|
"✅ ఈ సమస్యను సరిచేయడానికి మీరు చేయగల అన్ని మార్గాల గురించి ఆలోచించడానికి ఇది గొప్ప క్షణం. డేటాను కొంచెం సవరించాలా? వేరే కాలమ్స్ ఉపయోగించాలా? వేరే అల్గోరిథం ఉపయోగించాలా? సూచన: దాన్ని సాధారణీకరించడానికి [మీ డేటాను స్కేల్ చేయడం](https://www.mygreatlearning.com/blog/learning-data-science-with-k-means-clustering/) ప్రయత్నించండి మరియు ఇతర కాలమ్స్ను పరీక్షించండి.\n",
|
|
"\n",
|
|
"> ఈ '[వేరియన్స్ క్యాల్క్యులేటర్](https://www.calculatorsoup.com/calculators/statistics/variance-calculator.php)' ను ప్రయత్నించి ఈ భావనను మరింత అర్థం చేసుకోండి.\n",
|
|
"\n",
|
|
"------------------------------------------------------------------------\n",
|
|
"\n",
|
|
"## **🚀సవాలు**\n",
|
|
"\n",
|
|
"ఈ నోట్బుక్తో కొంత సమయం గడపండి, పారామితులను సవరించండి. డేటాను మరింత శుభ్రపరచడం ద్వారా (ఉదాహరణకు అవుట్లయర్స్ తొలగించడం) మోడల్ ఖచ్చితత్వాన్ని మెరుగుపరచగలరా? మీరు ఇచ్చిన డేటా నమూనాలకు ఎక్కువ బరువు ఇవ్వడానికి బరువులను ఉపయోగించవచ్చు. మరేమి చేయగలరు మంచి క్లస్టర్లు సృష్టించడానికి?\n",
|
|
"\n",
|
|
"సూచన: మీ డేటాను స్కేల్ చేయడానికి ప్రయత్నించండి. నోట్బుక్లో కామెంట్ చేసిన కోడ్ ఉంది, ఇది డేటా కాలమ్స్ను పరస్పరం పరిధి పరంగా మరింత సమానంగా చేయడానికి స్టాండర్డ్ స్కేలింగ్ను జోడిస్తుంది. సిల్హౌట్ స్కోరు తగ్గినప్పటికీ, ఎల్బో గ్రాఫ్లో 'కింక్' సాఫీగా మారుతుంది. ఇది డేటాను స్కేల్ చేయకుండా వదిలివేయడం వల్ల తక్కువ వేరియన్స్ ఉన్న డేటాకు ఎక్కువ బరువు కలుగుతుందని సూచిస్తుంది. ఈ సమస్యపై మరింత చదవండి [ఇక్కడ](https://stats.stackexchange.com/questions/21222/are-mean-normalization-and-feature-scaling-needed-for-k-means-clustering/21226#21226).\n",
|
|
"\n",
|
|
"## [**పోస్ట్-లెక్చర్ క్విజ్**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/30/)\n",
|
|
"\n",
|
|
"## **సమీక్ష & స్వీయ అధ్యయనం**\n",
|
|
"\n",
|
|
"- K-Means సిమ్యులేటర్ను [ఇలా ఒకటి](https://user.ceng.metu.edu.tr/~akifakkus/courses/ceng574/k-means/) చూడండి. మీరు ఈ టూల్ను ఉపయోగించి నమూనా డేటా పాయింట్లను విజువలైజ్ చేసి దాని సెంట్రాయిడ్లను నిర్ణయించవచ్చు. మీరు డేటా రాండమ్నెస్, క్లస్టర్ల సంఖ్య మరియు సెంట్రాయిడ్ల సంఖ్యను సవరించవచ్చు. ఇది డేటాను ఎలా గ్రూప్ చేయవచ్చో మీకు ఆలోచన ఇస్తుందా?\n",
|
|
"\n",
|
|
"- అలాగే, స్టాన్ఫోర్డ్ నుండి [K-Means పై ఈ హ్యాండౌట్](https://stanford.edu/~cpiech/cs221/handouts/kmeans.html) చూడండి.\n",
|
|
"\n",
|
|
"మీరు కొత్తగా పొందిన క్లస్టరింగ్ నైపుణ్యాలను K-Means క్లస్టరింగ్కు బాగా సరిపోయే డేటా సెట్లపై ప్రయత్నించాలనుకుంటున్నారా? దయచేసి చూడండి:\n",
|
|
"\n",
|
|
"- [ట్రైన్ మరియు క్లస్టరింగ్ మోడల్స్ను మూల్యాంకనం చేయండి](https://rpubs.com/eR_ic/clustering) Tidymodels మరియు స్నేహితులతో\n",
|
|
"\n",
|
|
"- [K-means క్లస్టర్ విశ్లేషణ](https://uc-r.github.io/kmeans_clustering), UC బిజినెస్ అనలిటిక్స్ R ప్రోగ్రామింగ్ గైడ్\n",
|
|
"\n",
|
|
"- [tidy డేటా సూత్రాలతో K-means క్లస్టరింగ్](https://www.tidymodels.org/learn/statistics/k-means/)\n",
|
|
"\n",
|
|
"## **అసైన్మెంట్**\n",
|
|
"\n",
|
|
"[వేరే క్లస్టరింగ్ పద్ధతులను ప్రయత్నించండి](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/2-K-Means/assignment.md)\n",
|
|
"\n",
|
|
"## ధన్యవాదాలు:\n",
|
|
"\n",
|
|
"[జెన్ లూపర్](https://www.twitter.com/jenlooper) ఈ మాడ్యూల్ యొక్క అసలు Python వెర్షన్ సృష్టించినందుకు ♥️\n",
|
|
"\n",
|
|
"[`అలిసన్ హోర్స్ట్`](https://twitter.com/allison_horst/) R ను మరింత ఆహ్లాదకరంగా మరియు ఆకర్షణీయంగా చేసే అద్భుతమైన చిత్రణలను సృష్టించినందుకు. ఆమె [గ్యాలరీ](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM)లో మరిన్ని చిత్రణలను చూడండి.\n",
|
|
"\n",
|
|
"సంతోషకరమైన అభ్యాసం,\n",
|
|
"\n",
|
|
"[ఎరిక్](https://twitter.com/ericntay), గోల్డ్ మైక్రోసాఫ్ట్ లెర్న్ స్టూడెంట్ అంబాసిడర్.\n",
|
|
"\n",
|
|
"<p >\n",
|
|
" <img src=\"../../../../../../translated_images/te/r_learners_sm.e4a71b113ffbedfe.webp\"\n",
|
|
" width=\"500\"/>\n",
|
|
" <figcaption>@allison_horst చేత కళాకృతి</figcaption>\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**అస్పష్టత**: \nఈ పత్రాన్ని AI అనువాద సేవ [Co-op Translator](https://github.com/Azure/co-op-translator) ఉపయోగించి అనువదించబడింది. మేము ఖచ్చితత్వానికి ప్రయత్నించినప్పటికీ, ఆటోమేటెడ్ అనువాదాల్లో పొరపాట్లు లేదా తప్పిదాలు ఉండవచ్చు. మూల పత్రం దాని స్వదేశీ భాషలో అధికారిక మూలంగా పరిగణించాలి. ముఖ్యమైన సమాచారానికి, ప్రొఫెషనల్ మానవ అనువాదం సిఫార్సు చేయబడుతుంది. ఈ అనువాదం వాడకంలో ఏర్పడిన ఏవైనా అపార్థాలు లేదా తప్పుదారుల కోసం మేము బాధ్యత వహించము.\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
|
|
]
|
|
}
|
|
]
|
|
} |