Майнор по Анализу Данных, Группа ИАД-2

26/04/2017 Алгоритмы кластеризации

In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

%matplotlib inline

plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = (12,5)

# Для кириллицы на графиках
font = {'family': 'Verdana',
        'weight': 'normal'}
plt.rc('font', **font)

try:
    from ipywidgets import interact, IntSlider, fixed, FloatSlider
except ImportError:
    print u'Так надо'

Пищевая ценность продуктов

Загрузите файл food.txt. В нем содержится информация о пищевой ценности разных продуктов

# "Name" is the name of the item. # # "Energy" is the number of calories. # # "Protein" is the amount of protein in grams. # # "Fat" is the amount of fat in grams. # # "Calcium" is the amount of calcium in milligrams. # # "Iron" is the amount of iron in milligrams.
  • Подготовте данные к кластеризации - выполните нормализацию признаков
  • Сделайте иерарническую кластеризацию этого набора данных.
  • Изобразите дендрограмму
  • Выверите число кластеров и интерпретируйте их

Почему перед применением кластеризации признки необходимо нормализовать?

In [5]:
from scipy.cluster.hierarchy import dendrogram, fcluster, linkage
In [6]:
df = pd.read_csv('food.txt', sep=' ')
In [7]:
df.head()
Out[7]:
Name Energy Protein Fat Calcium Iron
0 Braised beef 340 20 28 9 2.6
1 Hamburger 245 21 17 9 2.7
2 Roast beef 420 15 39 7 2.0
3 Beefsteak 375 19 32 9 2.6
4 Canned beef 180 22 10 17 3.7
In [ ]:
 

K-means, метод "локтя" и меры качества кластеризации

  • Загрузите данные по ирисам
  • Определите количество кластеров для метода k-means с помощью метода "локтя"
  • Выполните кластеризацию и получите вектор с метками кластеров
  • Оцените качество кластеризации с помощью
    • ARI
    • Силуэта
In [1]:
from sklearn.datasets import load_iris
from sklearn.metrics import adjusted_rand_score, silhouette_samples, silhouette_score
from sklearn.cluster import KMeans
In [ ]:
 

Применение K-means на профилях с интересами

Загрузите данные в которых содержится описание интересов профилей учеников старшей школы США.

In [ ]:
df_sns = pd.read_csv('snsdata.csv', sep=',')
df_sns.head()

Данные устроены так:

  • Год выпуска
  • Пол
  • Возраст
  • Количество друзей
  • 36 ключевых слов, которые встречаются в профилe facebook (интересы, сообщества, встречи)
  • Удалите все признаки кроме 36 ключевых слов.
  • Нормализуйте данные - из каждого столбца вычтите его среднее значение и поделите на стандартное отклонение.
  • Используйте метод k-means чтобы выделить 9 кластеров
  • Интерпретируйте каждый кластер проанализировав полученные центройды
In [ ]:
from sklearn.cluster import KMeans
from sklearn.feature_extraction.text import TfidfTransformer
In [ ]:
## Your Code Here

Геоданные

Загрузите геоданные из geo_data.txt (uid, timestamp, lat, lon, location_id).

Будем пытаться кластеризовать данные с помощью DBSCAN и меры haversine

In [ ]:
import mpl_toolkits.basemap as bm
from sklearn.cluster import DBSCAN
from sklearn.neighbors import NearestNeighbors
In [ ]:
df_geo = pd.read_csv('geo_data.txt', sep='\t', header=None,
                     names=['lat', 'lon'])/10000
In [ ]:
df_geo.head()
In [ ]:
def plot_geo(lat, lon, labels=None):    
    try:
        lllat, lllon = lat.min()-1, lon.max()+1
        urlat, urlon = lat.max()+1, lon.min()-1

        plt.figure(figsize=(10, 10))

        m = bm.Basemap(
            llcrnrlon=lllon,
            llcrnrlat=lllat,
            urcrnrlon=urlon,
            urcrnrlat=urlat, 
            projection='merc',
            resolution='h'
        )

        m.drawcoastlines(linewidth=0.5)
        m.drawmapboundary(fill_color='#47A4C9', zorder=1)
        m.fillcontinents(color='#EBC4D8',lake_color='#47A4C9', zorder=2)

        parallels = np.linspace(lllat, urlat, 10)
        m.drawparallels(parallels,labels=[1,0,0,0],fontsize=10)
        # draw meridians
        meridians = np.linspace(urlon, lllon, 10)
        m.drawmeridians(meridians,labels=[0,0,0,1],fontsize=10)

        m.scatter(lon, lat, latlon=True, cmap=plt.cm.jet,
              zorder=3, lw=0, c=labels)
    except:
        print 'что-то пошло не так'
        plt.scatter(x=lon, y=lat, c=labels, cmap=plt.cm.jet)
        plt.axis('equal')

Для начала нарисуем все точки на карте

In [ ]:
plot_geo(df_geo.lat.values, df_geo.lon.values)

Мы будем использовать расстояние haversine - на входе требуются координаты в радианах. Выход тоже будет в радианах. Чтобы перейти от градусов в радианты мы можем вспомнить тригонометрию, а можем воспользоваться функцией np.radians.

Для кого, чтобы не терять связь с реальностью, будем иметь ввиду, что расстояние в 1 радиан на земном шаре равно примерно 6371.0088 километрам.

Создайте матрицу X с координатами в радианах

In [ ]:
km_in_radian = 6371.0088
X = ...

Как же определить, какие параметры для DBSCAN выставлять? Наибольшую проблемы представляет параметр eps.

Будем считать, что MinPts нам дан свыше (например MinPts = 20). Воспользуемся эвристикой, схожей с методом локтя для оценки eps:

  • Расчитайте среднее расстояние до k=MinPts ближайших соседей каждой точки (класс NearestNeighbors и метод kneighbors)
  • Отсортируйте полученный массив и выведите его на график
  • Выберите такое расстояние, где будет наблюдаться "перегиб"
In [ ]:
nn = NearestNeighbors(n_neighbors=20, algorithm='ball_tree', metric='haversine')
nn.fit(X)
In [ ]:
## Your Code Here

Определим eps мы можем начать кластеризацию

  • Создайте экземпляр класса DBSCAN, кластеризуйте данные
  • Выведите полученные метки кластеров и их частоты
  • Изобразите координаты точек, не попавших в кластер выбросов (метка -1)
In [ ]:
dbscan = DBSCAN(...)
## Your Code Here