An image can contain many measurements, making its patterns hard to inspect directly. t-distributed stochastic neighbor embedding (t-SNE) maps high-dimensional observations into a low-dimensional space so that similar observations tend to remain close. It is nonlinear: unlike PCA, which seeks to capture variance through a linear transformation, t-SNE focuses on similarities between nearby points. section 6.4 section 6.9
The mapping is built by comparing similarities in two spaces:
- In the original space, center a Gaussian distribution on each point. Nearby points receive higher conditional similarity probabilities than distant points. section 6.4
- In the low-dimensional space, use a Cauchy distribution to obtain another set of similarity probabilities. section 6.4.1
- Measure the difference between the probability distributions with KL divergence, then reduce that cost using gradient descent. Perplexity controls the effective number of close neighbors considered. section 6.4.1
Plot iris measurements
Load the Iris features and their class labels, then run `TSNE(n_components=2, verbose=1, random_state=5).fit_transform(iris_data)`. Put the two resulting components and the labels into a dataframe and make a scatterplot colored by label. The resulting projection shows three separate groups corresponding to the three classes; the labels help interpret the plot rather than serving as inputs to the fit. section 6.4.2
iris_df = pd.DataFrame()
iris_df["iris_target"] = iris_target
iris_df["tSNE_first_component"] = fitted_data[:,0]
iris_df["tSNE_second_component"] = fitted_data[:,1]
sns.scatterplot(x="tSNE_first_component", y="tSNE_second_component",
hue=iris_df.iris_target.tolist(),
palette=sns.color_palette("hls", 3),
data=iris_df).set(title="Iris data tSNE projection")
The plotting code pairs each fitted component with the original iris label, making the two-dimensional result interpretable. section 6.4.2
Inspect handwritten digits
For MNIST, reshape each image into a row of measurements before fitting a two-component t-SNE projection. Plot the components with digit labels as colors to inspect how the ten digit classes appear in the reduced space. section 6.4.2
(digit, digit_label), (_ , _) = mnist.load_data()
digit = reshape(digit, [digit.shape[0], digit.shape[1]*digit.shape[2]])
Step 2: the subsequent steps are exactly same to the last example we used.
tsne_MNIST = TSNE(n_components=2, verbose=1, random_state=5)
fitted_data = tsne_MNIST.fit_transform(digit)
mnist_df = pd.DataFrame()
mnist_df["digit_label"] = digit_label
mnist_df["tSNE_first_component"] = fitted_data[:,0]
mnist_df["tSNE_second_component"] = fitted_data[:,1]
sns.scatterplot(x="tSNE_first_component", y="tSNE_second_component", hue=mnist_df.digit_label.tolist(),
palette=sns.color_palette("hls", 10),
data=mnist_df).set(title="MNIST data T-SNE projection")
This implementation shows the image reshape, t-SNE fit, and labeled plot together. section 6.4.2
Try several hyperparameter values before settling on a plot. A suggested perplexity range is 5–50, with perplexity below the number of observations; denser data may call for a higher value. Read the result primarily as a view of local similarity, not as a guarantee that the apparent distances between clusters preserve global structure. If global structure, speed, or stability across runs matters, compare the result with UMAP. section 6.4.2 section 6.5.3

