Related
When performing classification, we may want to predict the class label, and also to obtain a probability, certainty or confidence around the respective label. Probabilities can be much more informative than labels. To convey likelihood, we need calibrated probabilities. In calibrated probabilities, the probability reflects the true likelihood. For instance, if 10 observations obtain a probability of 0.8 and probability is calibrated, we expect around 8 of those to belong to the positive class. If the probability is calibrated, we should see a match between the number of positive cases and the predicted probability.
Only binary classification is supported by sklearn. How can we extend sklearn's calibration_curve module for multi-class classification problems and plot a Probability Calibration Curve when len(np.unique(y_true)) > 2 ? Here is my code that plots it for binary classifications.
from sklearn.calibration import calibration_curve
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, AutoMinorLocator)
import pathlib
from imblearn.pipeline import Pipeline
from sklearn.metrics import brier_score_loss
def __plot_calibration_curve_binary(clf, X_test, y_test, n_bins, strategy, **kwargs):
if 'probs' not in kwargs:
# score the test set
probs = clf.predict_proba(X_test)[:, 1]
fraction_of_positives, mean_predicted_value = calibration_curve(y_test, probs, n_bins=n_bins, strategy=strategy)
elif 'probs' in kwargs:
probs = kwargs['probs']
fraction_of_positives, mean_predicted_value = calibration_curve(y_test, probs, n_bins=n_bins, strategy=strategy)
else:
print("Please assign the probabilities(probs) or classifier to the function as shown in the example")
max_val = max(mean_predicted_value)
if 'fig_size' in kwargs and 'dpi' in kwargs:
fig, ax = plt.subplots(2, sharex=True, gridspec_kw={'height_ratios': [2, 1], 'hspace': 0.05}, figsize=kwargs['fig_size'], dpi=kwargs['dpi'], facecolor='white')
else:
fig, ax = plt.subplots(2, facecolor='white', sharex=True, gridspec_kw={'height_ratios': [2, 1], 'hspace': 0.05})
plt.rcParams["figure.facecolor"] = 'white'
plt.rcParams["axes.facecolor"] = 'white'
plt.rcParams["savefig.facecolor"] = 'white'
ax[0].xaxis.set_major_locator(MultipleLocator(0.1))
ax[1].xaxis.set_major_locator(MultipleLocator(0.1))
ax[0].xaxis.set_major_formatter('{x:.1f}')
ax[1].xaxis.set_major_formatter('{x:.1f}')
ax[0].yaxis.set_major_locator(MultipleLocator(0.1))
ax[0].yaxis.set_major_formatter('{x:.1f}')
ax[0].tick_params(which='both', width=1)
ax[0].tick_params(which='major', length=5)
ax[0].grid(True, zorder=0)
ax[1].grid(True, zorder=0)
if type(clf) == Pipeline:
estimator_name = type(clf['clf']).__name__
else:
estimator_name = type(clf).__name__
# print roc-auc
brier_score = ' (Brier Score : ' + str(round(brier_score_loss(y_test, probs), 4)) + ')'
#plot calibration curve
ax[0].plot(mean_predicted_value, fraction_of_positives, label = estimator_name + brier_score, zorder=2)
ax[0].scatter(mean_predicted_value, fraction_of_positives, zorder=3)
#plot perfect calibration line
ax[0].plot(np.linspace(0, max_val, n_bins), np.linspace(0, max_val, n_bins), linestyle='--', color='red', label='Perfect calibration', zorder=1)
#plot number of observation per prediction interval
ax[1].hist(probs, bins=n_bins, density=True, stacked=True, alpha=0.3, zorder=1)
#add labels and legends
ax[1].set_xlabel('Probability Predictions', fontsize=18)
ax[0].set_ylabel('Fraction of positive examples', fontsize=18)
ax[1].set_ylabel('Fraction of examples', fontsize=18)
if 'title' in kwargs:
ax[0].set_title(kwargs['title'], fontsize=18)
else:
ax[0].set_title('Probability Calibration Curve', fontsize=18)
ax[0].legend(loc='upper left')
ax[0].set_xlim([0.0, 1.0])
ax[1].set_xlim([0.0, 1.0])
ax[0].set_ylim([0.0, 1.0])
plt.show()
if 'save_fig_path' in kwargs:
path = pathlib.Path(kwargs['save_fig_path'])
path.parent.mkdir(parents=True, exist_ok=True)
if 'dpi' in kwargs:
fig.savefig(kwargs['save_fig_path'], dpi=kwargs['dpi'], facecolor=fig.get_facecolor(), edgecolor='none')
else:
fig.savefig(kwargs['save_fig_path'], facecolor=fig.get_facecolor(), edgecolor='none')
return fig, ax
def __plot_calibration_curve_multiclass(clf, X_test, y_test, n_bins, strategy, **kwargs):
print("Only binary classification is supported.")
def plot_calibration_curve(clf, X_test, y_test, n_bins=10, strategy='uniform', **kwargs):
"""
Plots probability calibration curve for the given model
Parameters
----------
clf : estimators to plot probability calibration curve
estimator instance (either sklearn.Pipeline, imblearn.Pipeline or a classifier)
PRE-FITTED classifier or a PRE-FITTED Pipeline in which the last estimator is a classifier.
X_test : pandas.DataFrame of shape (n_samples, n_features)
Test values.
y_test : pandas.Series of shape (n_samples,)
Target values.
n_bins: int, default=10
Number of bins to discretize the [0, 1] interval.
A bigger number requires more data.
Bins with no samples (i.e. without corresponding values in probs) will not be returned,
thus the returned arrays may have less than n_bins values.
strategy : {'uniform', 'quantile'}, default='uniform'
Strategy used to define the widths of the bins.
**kwargs : The following options are available with kwargs
probs: array-like of shape (n_samples,)
Probabilities of the positive class.
fig_size : tuple
Size (inches) of the plot.
dpi : int, default = 100
Image DPI.
title : str
The title of the plot.
save_fig_path : str
Full path where to save the plot. Will generate the folders if they don't exist already.
Returns
-------
fig : Matplotlib.pyplot.Figure
Figure from matplotlib
ax : Matplotlib.pyplot.Axe
Axe object from matplotlib
Example Syntax #1 : Plot calibration curve from estimator
-----------------
fig, ax = plot_calibration_curve(rf_pipe, X_test, y_test, n_bins=10, strategy='uniform',
fig_size=(12, 10), dpi=100,
save_fig_path="dir1/dir2/calibration_curve.png")
Example Syntax #2 : Plot the calibration curve using the calculated probabilities
-----------------
fig, ax = plot_calibration_curve(rf_pipe, X_test, y_test, n_bins=10, strategy='uniform',
probs=probs, fig_size=(12, 10), dpi=100,
save_fig_path="dir1/dir2/calibration_curve.png")
"""
if (len(y_test.unique()) == 2):
fig, ax = __plot_calibration_curve_binary(clf, X_test, y_test, n_bins=n_bins, strategy=strategy, **kwargs)
else:
fig, ax = __plot_calibration_curve_multiclass(clf, X_test, y_test, n_bins=n_bins, strategy=strategy, **kwargs)
return fig, ax
The output for the following syntax:
fig, ax = reporting.plot_calibration_curve(rf_pipe, X_test, y_test, n_bins=10, strategy='uniform',
probs=probs, fig_size=(12, 10), dpi=100,
save_fig_path="dir1/dir2/calibration_curve.png",
title='Probability Calibration Curve')
I have 3 regression models: Linear regression, Random Forest, and ANN.
Trying to compare them, I am plotting two plots: residuals and actual vs predicted.
Overall, the residuals suggest that most models predict the data well as they have a symmetric shape and follow the horizontal line. However, when evaluating the actual vs predicted, none of the models nearly follow the 45 degree line (suggesting perfect prediction). What am I doing wrong? Please see the relevant code below:
# Separate features from the label (add .values) to use arrays instead of dataframes
X = dataset2.iloc[:, 0:-1]
y = dataset2.iloc[:, -1]
# Split into training and testin sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 42)
# Scale the data
scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# Train OLS ####################################
ols_regressor = sm.OLS(y_train, X_train).fit()
# Predictions
y_pred_ols_test = ols_regressor.predict(X_test)
y_pred_ols_train = ols_regressor.predict(X_train)
# Train RF ####################################
rf = RandomForestRegressor(bootstrap=False,
max_depth=100,
max_features=3,
min_samples_leaf=1,
min_samples_split=5,
n_estimators=800)
rf.fit(X_train, y_train)
# Predictions
y_pred_rf_test = rf.predict(X_test)
y_pred_rf_train = rf.predict(X_train)
# Train RF ####################################
# ... TRAIN NN WITH KERAS AND TENSORFLOW ...
y_pred_nn_test = ann.predict(X_test)
y_pred_nn_train = ann.predict(X_train)
Here I am plotting the residuals:
fig, axes =plt.subplots(3,1,figsize=(8,12))
fig.suptitle('Residuals', fontweight="bold", fontsize=15)
# OLS #######################################
axes[0] = sns.residplot(ax=axes[0], x=y_pred_ols_test, y=y_test, data=dataset,
lowess=True,
color='darkcyan',
scatter_kws={'alpha': 0.5},
line_kws={'color': 'red', 'lw': 1, 'alpha': 0.8})
axes[0].set_xlim([-0.0050, 0.0005])
axes[0].set_ylim([-0.03, 0.03])
axes[0].set_title('Linear Regression')
axes[0].set_xlabel(' ')
axes[0].set_ylabel('Residuals')
# Random Forest ###############################
axes[1] = sns.residplot(ax=axes[1], x=y_pred_rf_test, y=y_test, data=dataset,
lowess=True,
color='darkcyan',
scatter_kws={'alpha': 0.5},
line_kws={'color': 'red', 'lw': 1, 'alpha': 0.8})
axes[1].set_xlim([-0.016, 0.006])
axes[1].set_ylim([-0.03, 0.03])
axes[1].set_title('Random Forest')
axes[1].set_xlabel(' ')
axes[1].set_ylabel('Residuals')
# Neural Network ###############################
axes[2] = sns.residplot(ax=axes[2], x=y_pred_nn_test, y=y_test, data=dataset,
lowess=True,
color='darkcyan',
scatter_kws={'alpha': 0.5},
line_kws={'color': 'red', 'lw': 1, 'alpha': 0.8})
axes[2].set_xlim([-0.018, -0.009])
axes[2].set_ylim([-0.03, 0.03])
axes[2].set_title('Artificial Neural Network)')
axes[2].set_xlabel('Predicted values')
axes[2].set_ylabel('Residuals')
plt.show()
Then I plot the predicted vs actual plot:
fig, axes =plt.subplots(3,1,figsize=(8,12))
fig.suptitle('Predicted vs Actual', fontweight="bold", fontsize=15)
# OLS #######################################
axes[0] = sns.regplot(ax=axes[0], x=y_pred_ols_test, y=y_test,
color='darkcyan',
scatter_kws={'alpha': 0.5},
line_kws={'color': 'red', 'lw': 1, 'alpha': 0.8})
x0 = -0.00415
x1 = 0.00025
y0 = -0.03
y1 = 0.03
# Plot 45 degree line
axes[0].plot([x0, x1], [y0, y1], ls="--", c="grey")
# # Axes Scale
axes[0].set_xlim([x0, x1])
axes[0].set_ylim([y0, y1])
# Labels
axes[0].set_title('Linear Regression')
axes[0].set_xlabel('')
axes[0].set_ylabel('True values')
# Random Forest ###############################
axes[1] = sns.regplot(ax=axes[1], x=y_pred_rf_test, y=y_test,
color='darkcyan',
scatter_kws={'alpha': 0.5},
line_kws={'color': 'red', 'lw': 1, 'alpha': 0.8})
x0 = -0.0125
x1 = 0.0045
y0 = -0.03
y1 = 0.03
# Plot 45 degree line
axes[1].plot([x0, x1], [y0, y1], ls="--", c="grey")
# Axes Scale
axes[1].set_xlim([x0, x1])
axes[1].set_ylim([y0, y1])
axes[1].set_title('Random Forest')
axes[1].set_xlabel(' ')
axes[1].set_ylabel('True values')
# NN #########################################
axes[2] = sns.regplot(ax=axes[2], x=y_pred_nn_test, y=y_test,
color='darkcyan',
scatter_kws={'alpha': 0.5},
line_kws={'color': 'red', 'lw': 1, 'alpha': 0.8})
x0 = -0.0175
x1 = -0.0092
y0 = -0.03
y1 = 0.03
# Plot 45 degree line
axes[2].plot([x0, x1], [y0, y1], ls="--", c="grey")
# Axes Scale
axes[2].set_xlim([x0, x1])
axes[2].set_ylim([y0, y1])
axes[2].set_title('Artificial Neural Network')
axes[2].set_xlabel('Predicted values')
axes[2].set_ylabel('True values')
plt.show()
Theoretically, the actual vs predicted plot should be good right? Considering that the residuals plot is symmetric and horizontal. What am I missing here?
For the actual vs predicted I also tried using sns.scatterplot() but it was the same really...
I tried to show a graph for Real Value Y and Prediction value Y1 in the graph that is classification-based (0,1,2,3), Y-axis looks good as it is 0-3, but X-axis shows a different scale. how I could fix it to show the same scale as Y-axis?
from sklearn.ensemble import RandomForestClassifier
x = train_dt.iloc[:, : -2 ].values
y = train_dt.iloc[:, -1].values #Trust_level
x1 = test_dt.iloc[:,: -2].values
y1 = test_dt.iloc[:, -1].values
regressor = RandomForestClassifier(n_estimators = 120, random_state = 0)
regressor.fit(x, y)
Y_pred = regressor.predict(x1)
score = regressor.score(x1, y1)
print(score)
And this is code for the graph
index = np.arange(0,len(y1))
fig, ax = plt.subplots(1,1,figsize=(20,10))
plt.plot(index,y1, label = 'Real Val')
plt.plot(index,Y_pred, label = 'Predicted Val')
plt.title('Real Val vs Predicted Val')
plt.xlabel('Real Val')
plt.ylabel('Predicted Val')
plt.legend()
how to fix this X-axis problem for being different scale as it should be (0,1,2,3)?
I'm hoping to use k-means clustering to plot and return the position of each cluster's centroid. The following groups two sets of xy scatter points into 6 clusters.
Using the df below, the coordinates in A and B and C and D are plotted as a scatter. I'm hoping to plot and return the centroid of each cluster.
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
df = pd.DataFrame(np.random.randint(-50,50,size=(100, 4)), columns=list('ABCD'))
fig, ax = plt.subplots()
Y_sklearn = df[['A','B','C','D']].values
model = KMeans(n_clusters = 4)
model.fit(Y_sklearn)
plt.scatter(Y_sklearn[:,0],Y_sklearn[:,1], c = model.labels_);
plt.scatter(Y_sklearn[:,2],Y_sklearn[:,3], c = model.labels_);
plt.show()
Solution
When you make a plot from KMeans prediction, if the number of features are more than two, you can only select two of the features (in your case, say, columns A and B) as the x and y coordinates on the 2D plane of the scatterplot. A better way to properly represent your higher-dimensional data on a 2D-plane would be some form of dimension-reduction: such as PCA. However, to keep the scope of this answer manageable I am only resorting to using the first two columns of the data X_train or X_test below and NOT using PCA to get the most important two dimensions.
I tried writing this answer so that anyone could start from zero experience and still follow along the code and run it to see what it does. Yes, it is long, and hence I have broken it down into multiple sections, so you could skip them if needed.
βFor your convenience you could get the entire code in this colab notebook:
π₯
βββ Jump to Section G to see the code used to make the plots.
π π π Section A gives a summary and is useful if you are just interested in the code to add the cluster-centers to your scatterplot.
List of Sections
A. Identification of Clusters in Data using KMeans Method
B. Import Libraries
C. Dummy Data
D. Custom Functions
E. Calculate True Cluster Centers
F. Define, Fit and Predict using KMeans Model
F.1. Predict for y_train using X_train
F.2. Predict for y_test using X_test
G. Make Figure with train, test and prediction data
References
A. Identification of Clusters in Data using KMeans Method
We will use sklearn.cluster.KMeans to identify the clusters. The attribute model.cluster_centers_ will give us the predicted cluster centers. Say, we want to find out 5 clusters in our training data, X_train with shape: (n_samples, n_features) and labels, y_train with shape: (n_samples,). The following code block fits the model to the data (X_train) and then predicts y and saves the prediction in y_pred_train variable.
# Define model
model = KMeans(n_clusters = 5)
# Fit model to training data
model.fit(X_train)
# Make prediction on training data
y_pred_train = model.predict(X_train)
# Get predicted cluster centers
model.cluster_centers_ # shape: (n_cluster, n_features)
## Displaying cluster centers on a plot
# if you just want to add cluster centers
# to your existing scatter-plot,
# just do this --->>
cluster_centers = model.cluster_centers_
plt.scatter(cluster_centers[:, 0], cluster_centers[:, 1],
marker='s', color='orange', s = 100,
alpha=0.5, label='pred')
This is the result βββ Jump to section G to see the code used to make the plots.
B. Import Libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
import pprint
%matplotlib inline
%config InlineBackend.figure_format = 'svg' # 'svg', 'retina'
plt.style.use('seaborn-white')
C. Dummy Data
We will use data generated in the following code-block. By design we create a dataset with 5 clusters and the following specifications. And then split the data into train and test blocks using sklearn.model_selection.train_test_split.
## Creating data with
# n_samples = 2500
# n_features = 4
# Expected clusters = 5
# centers = 5
# cluster_std = [1.0, 2.5, 0.5, 1.5, 2.0]
NUM_SAMPLES = 2500
RANDOM_STATE = 42
NUM_FEATURES = 4
NUM_CLUSTERS = 5
CLUSTER_STD = [1.0, 2.5, 0.5, 1.5, 2.0]
TEST_SIZE = 0.20
def dummy_data():
## Creating data with
# n_samples = 2500
# n_features = 4
# Expected clusters = 5
# centers = 5
# cluster_std = [1.0, 2.5, 0.5, 1.5, 2.0]
X, y = make_blobs(
n_samples = NUM_SAMPLES,
random_state = RANDOM_STATE,
n_features = NUM_FEATURES,
centers = NUM_CLUSTERS,
cluster_std = CLUSTER_STD
)
return X, y
def test_dummy_data(X, y):
assert X.shape == (NUM_SAMPLES, NUM_FEATURES), "Shape mismatch for X"
assert set(y) == set(np.arange(NUM_CLUSTERS)), "NUM_CLUSTER mismatch for y"
## D. Create Dummy Data
X, y = dummy_data()
test_dummy_data(X, y)
## Create train-test-split
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE)
D. Custom Functions
We will use the following 3 custom defined functions:
get_cluster_centers()
scatterplot()
add_cluster_centers()
def get_cluster_centers(X, y, num_clusters=None):
"""Returns the cluster-centers as numpy.array of
shape: (num_cluster, num_features).
"""
num_clusters = NUM_CLUSTERS if (num_clusters is None) else num_clusters
return np.stack([X[y==i].mean(axis=0) for i in range(NUM_CLUSTERS)])
def scatterplot(X, y,
cluster_centers=None,
alpha=0.5,
cmap='viridis',
legend_title="Classes",
legend_loc="upper left",
ax=None):
if ax is not None:
plt.sca(ax)
scatter = plt.scatter(X[:, 0], X[:, 1],
s=None, c=y, alpha=alpha, cmap=cmap)
legend = ax.legend(*scatter.legend_elements(),
loc=legend_loc, title=legend_title)
ax.add_artist(legend)
if cluster_centers is not None:
plt.scatter(cluster_centers[:, 0], cluster_centers[:, 1],
marker='o', color='red', alpha=1.0)
ax = plt.gca()
return ax
def add_cluster_centers(true_cluster_centers=None,
pred_cluster_centers=None,
markers=('o', 's'),
colors=('red, ''orange'),
s = (None, 200),
alphas = (1.0, 0.5),
center_labels = ('true', 'pred'),
legend_title = "Cluster Centers",
legend_loc = "upper right",
ax = None):
if ax is not None:
plt.sca(ax)
for idx, cluster_centers in enumerate([true_cluster_centers,
pred_cluster_centers]):
if cluster_centers is not None:
scatter = plt.scatter(
cluster_centers[:, 0], cluster_centers[:, 1],
marker = markers[idx],
color = colors[idx],
s = s[idx],
alpha = alphas[idx],
label = center_labels[idx]
)
legend = ax.legend(loc=legend_loc, title=legend_title)
ax.add_artist(legend)
return ax
E. Calculate True Cluster Centers
We will calculate the true cluster centers for train and test datasets and save the results to a dict: true_cluster_centers.
true_cluster_centers = {
'train': get_cluster_centers(X = X_train, y = y_train, num_clusters = NUM_CLUSTERS),
'test': get_cluster_centers(X = X_test, y = y_test, num_clusters = NUM_CLUSTERS)
}
# Show result
pprint.pprint(true_cluster_centers, indent=2)
Output:
{ 'test': array([[-2.44425795, 9.06004013, 4.7765817 , 2.02559904],
[-6.68967507, -7.09292101, -8.90860337, 7.16545582],
[ 1.99527271, 4.11374524, -9.62610383, 9.32625443],
[ 6.46362854, -5.90122349, -6.2972843 , -6.04963714],
[-4.07799392, 0.61599582, -1.82653858, -4.34758032]]),
'train': array([[-2.49685525, 9.08826 , 4.64928719, 2.01326914],
[-6.82913109, -6.86790673, -8.99780554, 7.39449295],
[ 2.04443863, 4.12623661, -9.64146529, 9.39444917],
[ 6.74707792, -5.83405806, -6.3480674 , -6.37184345],
[-3.98420601, 0.45335025, -1.23919526, -3.98642807]])}
F. Define, Fit and Predict using KMeans Model
model = KMeans(n_clusters = NUM_CLUSTERS, random_state = RANDOM_STATE)
model.fit(X_train)
## Output
# KMeans(algorithm='auto', copy_x=True, init='k-means++', max_iter=300,
# n_clusters=5, n_init=10, n_jobs=None, precompute_distances='auto',
# random_state=42, tol=0.0001, verbose=0)
F.1. Predict for y_train using X_train
## Process Prediction: train data
y_pred_train = model.predict(X_train)
# get model predicted cluster-centers
pred_train_cluster_centers = model.cluster_centers_ # shape: (n_cluster, n_features)
# sanity check
assert all([
y_pred_train.shape == (NUM_SAMPLES * (1 - TEST_SIZE),),
set(y_pred_train) == set(y_train)
])
F.2. Predict for y_test using X_test
## Process Prediction: test data
y_pred_test = model.predict(X_test)
# get model predicted cluster-centers
pred_test_cluster_centers = model.cluster_centers_ # shape: (n_cluster, n_features)
# sanity check
assert all([
y_pred_test.shape == (NUM_SAMPLES * TEST_SIZE,),
set(y_pred_test) == set(y_test)
])
G. Make Figure with train, test and prediction data
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(15, 6))
FONTSIZE = {'title': 16, 'suptitle': 20}
TITLE = {
'train': 'Train Data Clusters',
'test': 'Test Data Clusters',
'suptitle': 'Cluster Identification using KMeans Method',
}
CENTER_LEGEND_LABELS = ('true', 'pred')
LAGEND_PARAMS = {
'data': {'title': "Classes", 'loc': "upper left"},
'cluster_centers': {'title': "Cluster Centers", 'loc': "upper right"}
}
SCATTER_ALPHA = 0.4
CMAP = 'viridis'
CLUSTER_CENTER_PLOT_PARAMS = dict(
markers = ('o', 's'),
colors = ('red', 'orange'),
s = (None, 200),
alphas = (1.0, 0.5),
center_labels = CENTER_LEGEND_LABELS,
legend_title = LAGEND_PARAMS['cluster_centers']['title'],
legend_loc = LAGEND_PARAMS['cluster_centers']['loc']
)
SCATTER_PLOT_PARAMS = dict(
alpha = SCATTER_ALPHA,
cmap = CMAP,
legend_title = LAGEND_PARAMS['data']['title'],
legend_loc = LAGEND_PARAMS['data']['loc'],
)
## plot train data
data_label = 'train'
ax = axs[0]
plt.sca(ax)
ax = scatterplot(X = X_train, y = y_train,
cluster_centers = None,
ax = ax, **SCATTER_PLOT_PARAMS)
ax = add_cluster_centers(
true_cluster_centers = true_cluster_centers[data_label],
pred_cluster_centers = pred_train_cluster_centers,
ax = ax, **CLUSTER_CENTER_PLOT_PARAMS)
plt.title(TITLE[data_label], fontsize = FONTSIZE['title'])
## plot test data
data_label = 'test'
ax = axs[1]
plt.sca(ax)
ax = scatterplot(X = X_test, y = y_test,
cluster_centers = None,
ax = ax, **SCATTER_PLOT_PARAMS)
ax = add_cluster_centers(
true_cluster_centers = true_cluster_centers[data_label],
pred_cluster_centers = pred_test_cluster_centers,
ax = ax, **CLUSTER_CENTER_PLOT_PARAMS)
plt.title(TITLE[data_label], fontsize = FONTSIZE['title'])
plt.suptitle(TITLE['suptitle'],
fontsize = FONTSIZE['suptitle'])
plt.show()
# save figure
fig.savefig("kmeans_fit_result.png", dpi=300)
Result:
References
Documentation: sklearn.cluster.KMeans
Documnetation: sklearn.model_selection.train_test_split
Documentation: matplotlib.pyplot.legend
Documentation: sklearn.decomposition.PCA
Managing legend in scatterplot using matplotlib
Demo of KMeans Assumptions
Based on how you make the scatter plot, I guess A and B correspond to the xy coordinates of the first set of points, while C and D correspond to the xy coordinates of the second set of points. If so, you cannot apply Kmeans to the dataframe directly, since there are only two features, i.e., x and y coordinates. Finding the centroids is actually quite simple, all you need is model_zero.cluster_centers_.
Let's first construct a dataframe that will be better for visualization
import numpy as np
# set the seed for reproducible datasets
np.random.seed(365)
# cov matrix of a 2d gaussian
stds = np.eye(2)
# four cluster means
means_zero = np.random.randint(10,20,(4,2))
sizes_zero = np.array([20,30,15,35])
# four cluster means
means_one = np.random.randint(0,10,(4,2))
sizes_one = np.array([20,20,25,35])
points_zero = np.vstack([np.random.multivariate_normal(mean,stds,size=(size)) for mean,size in zip(means_zero,sizes_zero)])
points_one = np.vstack([np.random.multivariate_normal(mean,stds,size=(size)) for mean,size in zip(means_one,sizes_one)])
all_points = np.hstack((points_zero,points_one))
As you can see, the four clusters are constructed by sampling points from four Gaussians with different means. With this dataframe, here is how you can plot it
import matplotlib.patheffects as PathEffects
from sklearn.cluster import KMeans
df = pd.DataFrame(all_points, columns=list('ABCD'))
fig, ax = plt.subplots(figsize=(10,8))
scatter_zero = df[['A','B']].values
scatter_one = df[['C','D']].values
model_zero = KMeans(n_clusters=4)
model_zero.fit(scatter_zero)
model_one = KMeans(n_clusters=4)
model_one.fit(scatter_one)
plt.scatter(scatter_zero[:,0],scatter_zero[:,1],c=model_zero.labels_,cmap='bwr');
plt.scatter(scatter_one[:,0],scatter_one[:,1],c=model_one.labels_,cmap='bwr');
# plot the cluster centers
txts = []
for ind,pos in enumerate(model_zero.cluster_centers_):
txt = ax.text(pos[0],pos[1],
'cluster %i \n (%.1f,%.1f)' % (ind,pos[0],pos[1]),
fontsize=12,zorder=100)
txt.set_path_effects([PathEffects.Stroke(linewidth=5, foreground="aquamarine"),PathEffects.Normal()])
txts.append(txt)
for ind,pos in enumerate(model_one.cluster_centers_):
txt = ax.text(pos[0],pos[1],
'cluster %i \n (%.1f,%.1f)' % (ind,pos[0],pos[1]),
fontsize=12,zorder=100)
txt.set_path_effects([PathEffects.Stroke(linewidth=5, foreground="lime"),PathEffects.Normal()])
txts.append(txt)
zero_mean = np.mean(model_zero.cluster_centers_,axis=0)
one_mean = np.mean(model_one.cluster_centers_,axis=0)
txt = ax.text(zero_mean[0],zero_mean[1],
'point set zero',
fontsize=15)
txt.set_path_effects([PathEffects.Stroke(linewidth=5, foreground="violet"),PathEffects.Normal()])
txts.append(txt)
txt = ax.text(one_mean[0],one_mean[1],
'point set one',
fontsize=15)
txt.set_path_effects([PathEffects.Stroke(linewidth=5, foreground="violet"),PathEffects.Normal()])
txts.append(txt)
plt.show()
Running this code, you will get
I basically want to add a colorbar at each of the subplots in the code below (link to code ). My attempts add all color bars at the end of the loop in the last subplot.
print(__doc__)
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_mldata
from sklearn.neural_network import MLPClassifier
mnist = fetch_mldata("MNIST original")
# rescale the data, use the traditional train/test split
X, y = mnist.data / 255., mnist.target
X_train, X_test = X[:60000], X[60000:]
y_train, y_test = y[:60000], y[60000:]
# mlp = MLPClassifier(hidden_layer_sizes=(100, 100), max_iter=400, alpha=1e-4,
# solver='sgd', verbose=10, tol=1e-4, random_state=1)
mlp = MLPClassifier(hidden_layer_sizes=(50,), max_iter=10, alpha=1e-4,
solver='sgd', verbose=10, tol=1e-4, random_state=1,
learning_rate_init=.1)
mlp.fit(X_train, y_train)
print("Training set score: %f" % mlp.score(X_train, y_train))
print("Test set score: %f" % mlp.score(X_test, y_test))
fig, axes = plt.subplots(4, 4)
# use global min / max to ensure all weights are shown on the same scale
vmin, vmax = mlp.coefs_[0].min(), mlp.coefs_[0].max()
for coef, ax in zip(mlp.coefs_[0].T, axes.ravel()):
ax.matshow(coef.reshape(28, 28), cmap=plt.cm.gray, vmin=.5 * vmin,
vmax=.5 * vmax)
ax.set_xticks(())
ax.set_yticks(())
plt.show()
UPDATE:
based on the link in the comment below, here is the code which adds the colorbar at the right of the diagram
fig, axes = plt.subplots(4, 4)
# use global min / max to ensure all weights are shown on the same scale
vmin, vmax = mlp.coefs_[0].min(), mlp.coefs_[0].max()
for coef, ax in zip(mlp.coefs_[0].T, axes.ravel()):
im = ax.matshow(coef.reshape(28, 28), cmap=plt.cm.gray, vmin=.5 * vmin, vmax=.5 * vmax)
ax.set_xticks(())
ax.set_yticks(())
fig.subplots_adjust(right=0.8)
cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7])
fig.colorbar(im, cax=cbar_ax)
plt.show()