import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
import mglearn
from IPython.display import display
%matplotlib inline
Plot twist: deadline 27 ноември (понеделник)
Формат: repository в GitHub с три notebook-а.
k
сходни групи, наречени клъстериДа се пробваме с make_blobs
:
from sklearn.datasets import make_blobs
X, y = make_blobs(random_state=1)
mglearn.discrete_scatter(X[:, 0], X[:, 1]);
Така изглежда само X
, където няма информация за категориите.
X
Ще се опитаме да открием нещо такова с k-Means clustering:
mglearn.discrete_scatter(X[:, 0], X[:, 1], y);
Кодът би трябвало да изглежда съвсем познато, освен че fit
не примера y
:
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3, random_state=2)
kmeans.fit(X)
y_pred = kmeans.predict(X)
Да начертаем резултатите:
mglearn.discrete_scatter(X[:, 0], X[:, 1], y_pred);
Изглежда сме намерили същите клъстери. Това значи ли, че y == y_pred
?
y == y_pred
print(y)
print(y_pred)
y
и y_pred
създават идентични разделения на данните, но номерацията им е различна.
В sklearn има метрика, която хваща това:
from sklearn.metrics.cluster import adjusted_rand_score
adjusted_rand_score(y, y_pred)
adjusted_rand_score
има повече особености, но ще ги погледнем по-натам.
Как работи k-Means Clustering:
mglearn.plots.plot_kmeans_algorithm()
k-Means открива три центъра и класифицира всяка точка като член на клъстъра на най-близкия център.
kmeans.cluster_centers_
mglearn.plots.plot_kmeans_boundaries()
Един от параметрите на KMeans
е колко клъстера да намери алгоритъма. Обърнете внимание, че той не знае колко клъстера има в данните.
Това е възможен отговор за k=2
:
assignments = KMeans(n_clusters=2, random_state=0).fit_predict(X)
mglearn.discrete_scatter(X[:, 0], X[:, 1], assignments);
Това е възможен отговор за k=5
:
assignments = KMeans(n_clusters=5, random_state=0).fit_predict(X)
mglearn.discrete_scatter(X[:, 0], X[:, 1], assignments);
Един от проблемите на k-Means е че не може да се справи със всякаква форма на клъстерите. Например:
X_varied, y_varied = make_blobs(n_samples=200, cluster_std=[1.0, 2.5, 0.5], random_state=170)
y_pred = KMeans(n_clusters=3, random_state=0).fit_predict(X_varied)
mglearn.discrete_scatter(X_varied[:, 0], X_varied[:, 1], y_pred);
Вероятно по-добро разделение щеше да бъде гъстите региони бяха два от клъстерите и всичко между тях беше третия.
Ето и друг пример:
X, y = make_blobs(random_state=170, n_samples=600)
random = np.random.RandomState(74)
transformation = random.normal(size=(2, 2))
X = np.dot(X, transformation)
plt.scatter(X[:, 0], X[:, 1]);
Тук ясно се виждат три отделни клъстера. Но какво ли ще намери k-Means?
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
y_pred = kmeans.predict(X)
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap=mglearn.cm3)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], marker='^', c='orange', s=200, linewidth=2);
Друго, с което k-Means няма да се справи добре е make_moons
:
from sklearn.datasets import make_moons
X, y = make_moons(n_samples=200, noise=0.05, random_state=0)
plt.scatter(X[:, 0], X[:, 1]);
kmeans = KMeans(n_clusters=2)
kmeans.fit(X)
y_pred = kmeans.predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap=mglearn.cm2, s=60)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], marker='^', c='orange', s=100, linewidth=2);
Бихме могли да ползваме k-Means за да подобрим резултати от линеен модел.
Какво бихме постигнали с линеен SVM?
from sklearn.svm import LinearSVC
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
X, y = make_moons(n_samples=200, noise=0.05, random_state=0)
model = make_pipeline(StandardScaler(), LinearSVC(C=10))
model.fit(X, y)
model.score(X, y)
А ако прекераме данни през k-Means при k=10
?
kmeans = KMeans(n_clusters=10, random_state=0)
kmeans.fit(X)
plt.scatter(X[:, 0], X[:, 1], c=kmeans.predict(X), s=60, cmap='Paired')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=60, marker='^', c=range(kmeans.n_clusters), linewidth=2, cmap='Paired');
KMeans
има метод transform
, който връща дистанцията от центровете:
kmeans.transform(X)
Така си създадохме нови feature-и. И ако сега ги дадем на LinearSVC
:
from sklearn.pipeline import make_pipeline
pipeline = make_pipeline(
StandardScaler(),
KMeans(n_clusters=10, random_state=0),
LinearSVC(C=10)
)
pipeline.fit(X, y)
pipeline.score(X, y)
Разбира се, това беше абстрактно приложение върху синтетичен dataset. Прилагането на практика е малко по-сложно.
Как работи:
Какво значи "най-близки" клъстери се контролира от параметри.
Повече детайли в документацията.
mglearn.plots.plot_agglomerative_algorithm()
from sklearn.cluster import AgglomerativeClustering
X, y = make_blobs(random_state=1)
clustering = AgglomerativeClustering(n_clusters=3)
assignment = clustering.fit_predict(X)
mglearn.discrete_scatter(X[:, 0], X[:, 1], assignment);
Този алгоритъм също не се оправя добре с make_moons
:
X, y = make_moons(n_samples=200, noise=0.05, random_state=0)
clustering = AgglomerativeClustering(n_clusters=2)
assignment = clustering.fit_predict(X)
mglearn.discrete_scatter(X[:, 0], X[:, 1], assignment);
Поради начина си на работа, AgglomerativeClustering
няма predict
– той не може да генерализира за нови точки. Има само fit
и fit_predict
.
eps
и min_samples
min_samples
или повече съседи на eps
или по-малко разстояние.eps
дистанция от core samples, но не са core samples.Повече детайли в документацията.
mglearn.plots.plot_dbscan()
DBSCAN вече може да се справи с make_moons
:
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler
X, y = make_moons(n_samples=200, noise=0.05, random_state=0)
scaler = StandardScaler()
scaler.fit(X)
X_scaled = scaler.transform(X)
dbscan = DBSCAN()
clusters = dbscan.fit_predict(X_scaled)
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=clusters, s=60);
С подходящия eps
, DBSCAN може да се справи и онези странни три клъстера от по-рано:
X, y = make_blobs(random_state=170, n_samples=600)
random = np.random.RandomState(74)
transformation = random.normal(size=(2, 2))
X = np.dot(X, transformation)
scaler = StandardScaler()
scaler.fit(X)
X_scaled = scaler.transform(X)
dbscan = DBSCAN(eps=0.20)
clusters = dbscan.fit_predict(X_scaled)
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=clusters, s=60);
Обърнете внимание, че подобно на AgglomerativeClustering
, DBSCAN
има само fit_predict
.
Погледнахме за момент adjusted_rand_score
. Нека видим какво прави:
from sklearn.metrics.cluster import adjusted_rand_score
Ще пробваме пак с make_moons
:
X, y = make_moons(n_samples=200, noise=0.05, random_state=0)
scaler = StandardScaler()
scaler.fit(X)
X_scaled = scaler.transform(X)
plt.scatter(X[:, 0], X[:, 1]);
Ще видим оценката на тези три алгоритъма:
algorithms = [KMeans(n_clusters=2), AgglomerativeClustering(n_clusters=2), DBSCAN()]
Ще генерираме random_clusters
, който раздава произволен клъстър на всяка точка:
random_state = np.random.RandomState(seed=0)
random_clusters = random_state.randint(low=0, high=2, size=len(X))
random_clusters
И да начертаем диаграма:
fig, axes = plt.subplots(1, 4, figsize=(15, 3), subplot_kw={'xticks': (), 'yticks': ()})
axes[0].scatter(X_scaled[:, 0], X_scaled[:, 1], c=random_clusters, cmap=mglearn.cm3, s=60)
axes[0].set_title("Random assignment - ARI: {:.2f}".format(adjusted_rand_score(y, random_clusters)))
for ax, algorithm in zip(axes[1:], algorithms):
clusters = algorithm.fit_predict(X_scaled)
ax.scatter(X_scaled[:, 0], X_scaled[:, 1], c=clusters, cmap=mglearn.cm3, s=60)
ax.set_title("{} - ARI: {:.2f}".format(algorithm.__class__.__name__, adjusted_rand_score(y, clusters)))
mglearn.plots.plot_pca_illustration()
Бихме могли да го ползваме за визуализация.
Да се опитаме да го приложим върху cancer
. Първо, нека да видим какви feature-и има:
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
cancer = load_breast_cancer()
fig, axes = plt.subplots(15, 2, figsize=(10, 20))
malignant = cancer.data[cancer.target == 0]
benign = cancer.data[cancer.target == 1]
ax = axes.ravel()
for i in range(30):
_, bins = np.histogram(cancer.data[:, i], bins=50)
ax[i].hist(malignant[:, i], bins=bins, color=mglearn.cm3(0), alpha=.5)
ax[i].hist(benign[:, i], bins=bins, color=mglearn.cm3(2), alpha=.5)
ax[i].set_title(cancer.feature_names[i])
ax[i].set_yticks(())
fig.tight_layout()
cancer.data.shape
Преди да го прекараме през PCA е добре да мине през StandardScaler
:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(cancer.data)
X_scaled = scaler.transform(cancer.data)
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
pca.fit(X_scaled)
X_pca = pca.transform(X_scaled)
plt.figure(figsize=(8, 8))
mglearn.discrete_scatter(X_pca[:, 0], X_pca[:, 1], cancer.target)
plt.legend(cancer.target_names, loc='best')
plt.gca().set_aspect('equal');
pca.components_
plt.matshow(pca.components_, cmap='viridis')
plt.yticks([0, 1], ["First component", "Second component"])
plt.colorbar()
plt.xticks(range(len(cancer.feature_names)), cancer.feature_names, rotation=60, ha='left')
plt.xlabel("Feature")
plt.ylabel("Principal components");
from sklearn.model_selection import cross_val_score
X, y = cancer.data, cancer.target
pipeline = make_pipeline(StandardScaler(), LinearSVC(C=0.01))
cross_val_score(pipeline, X, y).mean()
for i in range(1, 10):
pipeline = make_pipeline(StandardScaler(), PCA(n_components=i), LinearSVC(C=0.01))
score = cross_val_score(pipeline, X, y).mean()
print("Score for {} components: {}".format(i, score))
Друг алгоритъм, полезен за декомпозиране:
Повече информация в документацията.
mglearn.plots.plot_nmf_illustration()
Декомпозиране на сигнал.
Може да ползваме NMF да извлечем оригиналните сигнали.
Да генерираме три сигнала:
S = mglearn.datasets.make_signals()
plt.figure(figsize=(12, 2))
plt.plot(S, '-')
plt.xlabel("Time")
plt.ylabel("Signal");
S.shape
Сега ще ги прекараме през 100 микрофона, всеки от които на произволна дистанция от всеки човек:
m = np.random.RandomState(0).uniform(size=(100, 3))
print(m.shape)
m[:5]
Това е матрица, където редовете са микрофони, а колоните са дистанцията от всеки микрофон.
Извеждаме 100 записа:
X = np.dot(S, m.T)
X.shape
plt.figure(figsize=(12, 2))
plt.plot(X[:, :3], '-');
from sklearn.decomposition import NMF
nmf = NMF(n_components=3, random_state=42)
nmf.fit_transform(X).shape
nmf = NMF(n_components=3, random_state=42)
S_ = nmf.fit_transform(X)
pca = PCA(n_components=3)
H = pca.fit_transform(X)
models = [S, S_, H]
names = ['True sources',
'NMF recovered signals',
'PCA recovered signals']
fig, axes = plt.subplots(3, figsize=(12, 8), gridspec_kw={'hspace': .5}, subplot_kw={'xticks': (), 'yticks': ()})
for model, name, ax in zip(models, names, axes):
ax.set_title(name)
ax.plot(model[:, :3], '-')
from sklearn.datasets import load_digits
digits = load_digits()
fig, axes = plt.subplots(2, 5, figsize=(10, 5), subplot_kw={'xticks':(), 'yticks': ()})
for ax, img in zip(axes.ravel(), digits.images):
ax.imshow(img)
Може да пробваме с PCA:
pca = PCA(n_components=2)
pca.fit(digits.data)
digits_pca = pca.transform(digits.data)
colors = ["#476A2A", "#7851B8", "#BD3430", "#4A2D4E", "#875525", "#A83683", "#4E655E", "#853541", "#3A3120", "#535D8E"]
plt.figure(figsize=(10, 10))
plt.xlim(digits_pca[:, 0].min(), digits_pca[:, 0].max())
plt.ylim(digits_pca[:, 1].min(), digits_pca[:, 1].max())
for i in range(len(digits.data)):
plt.text(digits_pca[i, 0], digits_pca[i, 1], str(digits.target[i]), color=colors[digits.target[i]], fontdict={'weight': 'bold', 'size': 9})
Въпреки, че има забележими клъстери от някои числа, PCA
не се справя идеално.
Може да пробваме TSNE.
from sklearn.manifold import TSNE
tsne = TSNE(random_state=0)
digits_tsne = tsne.fit_transform(digits.data)
plt.figure(figsize=(10, 10))
plt.xlim(digits_tsne[:, 0].min(), digits_tsne[:, 0].max() + 1)
plt.ylim(digits_tsne[:, 1].min(), digits_tsne[:, 1].max() + 1)
for i in range(len(digits.data)):
plt.text(digits_tsne[i, 0], digits_tsne[i, 1], str(digits.target[i]), color=colors[digits.target[i]], fontdict={'weight': 'bold', 'size': 9})