Skip to content

Commit 6cff5b8

Browse files
committed
Changed tsne.py
1 parent 88666f0 commit 6cff5b8

File tree

1 file changed

+45
-33
lines changed

1 file changed

+45
-33
lines changed

machine_learning/tsne.py

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
"""
2727

2828
import doctest
29-
3029
import numpy as np
3130
from sklearn.datasets import load_iris
3231

@@ -38,49 +37,57 @@ def collect_dataset() -> tuple[np.ndarray, np.ndarray]:
3837
:return: Tuple containing feature matrix and target labels
3938
4039
Example:
41-
>>> x, y = collect_dataset()
42-
>>> x.shape
40+
>>> data_x, data_y = collect_dataset()
41+
>>> data_x.shape
4342
(150, 4)
44-
>>> y.shape
43+
>>> data_y.shape
4544
(150,)
4645
"""
4746
data = load_iris()
4847
return np.array(data.data), np.array(data.target)
4948

5049

51-
def compute_pairwise_affinities(x: np.ndarray, sigma: float = 1.0) -> np.ndarray:
50+
def compute_pairwise_affinities(data_x: np.ndarray, sigma: float = 1.0) -> np.ndarray:
5251
"""
5352
Computes pairwise affinities (P matrix) in high-dimensional space using Gaussian kernel.
5453
55-
:param x: Input data of shape (n_samples, n_features)
54+
:param data_x: Input data of shape (n_samples, n_features)
5655
:param sigma: Variance (Bandwidth) of the Gaussian kernel
5756
:return: Symmetrized probability matrix p
5857
5958
Example:
6059
>>> import numpy as np
61-
>>> x = np.array([[0.0, 0.0], [1.0, 0.0]])
62-
>>> p = compute_pairwise_affinities(x)
60+
>>> data_x = np.array([[0.0, 0.0], [1.0, 0.0]])
61+
>>> p = compute_pairwise_affinities(data_x)
6362
>>> float(round(p[0, 1], 3))
6463
0.25
6564
"""
66-
n_samples = x.shape[0]
67-
sum_x = np.sum(np.square(x), axis=1)
68-
d = np.add(np.add(-2 * np.dot(x, x.T), sum_x).T, sum_x)
65+
n_samples = data_x.shape[0]
66+
sum_x = np.sum(np.square(data_x), axis=1)
67+
d = np.add(np.add(-2 * np.dot(data_x, data_x.T), sum_x).T, sum_x)
6968
p = np.exp(-d / (2 * sigma ** 2))
7069
np.fill_diagonal(p, 0)
7170
p /= np.sum(p)
7271
return (p + p.T) / (2 * n_samples)
7372

7473

75-
def compute_low_dim_affinities(y: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
74+
def compute_low_dim_affinities(embedding_y: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
7675
"""
7776
Computes low-dimensional similarities (Q matrix) using Student-t distribution.
7877
79-
:param y: Low-dimensional embeddings (n_samples, n_components)
78+
:param embedding_y: Low-dimensional embeddings (n_samples, n_components)
8079
:return: Tuple (q, num) where q is the probability matrix and num is numerator array
80+
81+
Example:
82+
>>> embedding_y = np.array([[0.0, 0.0], [1.0, 0.0]])
83+
>>> q, num = compute_low_dim_affinities(embedding_y)
84+
>>> q.shape
85+
(2, 2)
86+
>>> num.shape
87+
(2, 2)
8188
"""
82-
sum_y = np.sum(np.square(y), axis=1)
83-
num = 1 / (1 + np.add(np.add(-2 * np.dot(y, y.T), sum_y).T, sum_y))
89+
sum_y = np.sum(np.square(embedding_y), axis=1)
90+
num = 1 / (1 + np.add(np.add(-2 * np.dot(embedding_y, embedding_y.T), sum_y).T, sum_y))
8491
np.fill_diagonal(num, 0)
8592
q = num / np.sum(num)
8693
return q, num
@@ -102,8 +109,8 @@ def apply_tsne(
102109
:return: Transformed dataset (low-dimensional embedding)
103110
104111
Example:
105-
>>> x, _ = collect_dataset()
106-
>>> y_emb = apply_tsne(x, n_components=2, n_iter=50)
112+
>>> data_x, _ = collect_dataset()
113+
>>> y_emb = apply_tsne(data_x, n_components=2, n_iter=50)
107114
>>> y_emb.shape
108115
(150, 2)
109116
"""
@@ -115,49 +122,54 @@ def apply_tsne(
115122
n_samples = data_x.shape[0]
116123

117124
# Initialize low-dimensional map randomly
118-
y = np.random.randn(n_samples, n_components) * 1e-4
125+
y_emb = np.random.randn(n_samples, n_components) * 1e-4
119126
p = compute_pairwise_affinities(data_x)
120127
p = np.maximum(p, 1e-12)
121128

122129
# Initialize parameters
123-
y_inc = np.zeros_like(y)
130+
y_inc = np.zeros_like(y_emb)
124131
momentum = 0.5
125132

126133
for i in range(n_iter):
127-
q, num = compute_low_dim_affinities(y)
134+
q, num = compute_low_dim_affinities(y_emb)
128135
q = np.maximum(q, 1e-12)
129136

130137
pq = p - q
131138

132139
# Compute gradient
133140
d_y = 4 * (
134-
np.dot((pq * num), y)
135-
- np.multiply(np.sum(pq * num, axis=1)[:, np.newaxis], y)
141+
np.dot((pq * num), y_emb)
142+
- np.multiply(np.sum(pq * num, axis=1)[:, np.newaxis], y_emb)
136143
)
137144

138145
# Update with momentum and learning rate
139146
y_inc = momentum * y_inc - learning_rate * d_y
140-
y += y_inc
147+
y_emb += y_inc
141148

142149
# Adjust momentum halfway through
143150
if i == int(n_iter / 4):
144151
momentum = 0.8
145152

146-
return y
153+
return y_emb
147154

148155

149156
def main() -> None:
150157
"""
151158
Driver function for t-SNE demonstration.
159+
160+
Example:
161+
>>> main() # doctest: +ELLIPSIS
162+
t-SNE embedding (first 5 points):
163+
...
152164
"""
153-
x, y_labels = collect_dataset()
154-
y_emb = apply_tsne(x, n_components=2, n_iter=300)
165+
data_x, data_y = collect_dataset()
166+
y_emb = apply_tsne(data_x, n_components=2, n_iter=300)
155167
print("t-SNE embedding (first 5 points):")
156168
print(y_emb[:5])
157169

158170
# Optional visualization (commented to avoid dependency)
159171
# import matplotlib.pyplot as plt
160-
# plt.scatter(y_emb[:, 0], y_emb[:, 1], c=y_labels, cmap="viridis")
172+
# plt.scatter(y_emb[:, 0], y_emb[:, 1], c=data_y, cmap="viridis")
161173
# plt.title("t-SNE Visualization of Iris Dataset")
162174
# plt.xlabel("Component 1")
163175
# plt.ylabel("Component 2")
@@ -181,13 +193,13 @@ def main() -> None:
181193
- n_iter: number of iterations for optimization
182194
183195
Output:
184-
- y: numpy array of shape (n_samples, n_components)
196+
- y_emb: numpy array of shape (n_samples, n_components)
185197
Each row is the low-dimensional embedding of the corresponding high-dimensional point.
186198
187199
How it works:
188-
1. Compute high-dimensional similarities (p matrix)
189-
2. Initialize low-dimensional map (y) randomly
190-
3. Compute low-dimensional similarities (q matrix)
191-
4. Minimize KL divergence between p and q using gradient descent
192-
5. Update y with momentum and learning rate iteratively
200+
1. Compute high-dimensional similarities (P matrix)
201+
2. Initialize low-dimensional map (y_emb) randomly
202+
3. Compute low-dimensional similarities (Q matrix)
203+
4. Minimize KL divergence between P and Q using gradient descent
204+
5. Update y_emb with momentum and learning rate iteratively
193205
"""

0 commit comments

Comments
 (0)