{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# t-SNE\n", "t-Distributed Stochastic Neighbor Embedding (t-SNE)\n", "\n", "Buen vídeo básico de introducción al t-SNE\n", "https://www.youtube.com/watch?v=NEaUSP4YerM\n", "\n", "https://towardsdatascience.com/an-introduction-to-t-sne-with-python-example-5a3a293108d1\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## t-SNE\n", "\n", "Para probar el método, vamos a crear un *dataset* formado por **tres grupos** de puntos generados con distintas localizaciones y varianzas." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "\n", "C1 = np.random.normal(loc=0., scale=1., size=(10,3))\n", "I1 = np.ones(10, dtype=int)\n", "\n", "#C2 = np.random.normal(loc=2., scale=0.1, size=(10,3))\n", "C2 = np.random.normal(loc=5., scale=1., size=(10,3))\n", "I2 = np.ones(10, dtype=int)*2\n", "\n", "#C3 = np.random.normal(loc=5, scale=2, size=(10,3))\n", "C3 = np.random.normal(loc=10, scale=1., size=(10,3))\n", "I3 = np.ones(10, dtype=int)*3\n", "\n", "\n", "df1 = pd.DataFrame(data=C1, columns=[\"x\", \"y\", \"z\"])\n", "df1I = pd.DataFrame(data=I1, columns=[\"class\"])\n", "\n", "df2 = pd.DataFrame(data=C2, columns=[\"x\", \"y\", \"z\"])\n", "df2I = pd.DataFrame(data=I2, columns=[\"class\"])\n", "\n", "df3 = pd.DataFrame(data=C3, columns=[\"x\", \"y\", \"z\"])\n", "df3I = pd.DataFrame(data=I3, columns=[\"class\"])\n", "\n", "\n", "result1 = pd.concat([df1, df1I], axis = 1, ignore_index=True, sort=False)\n", "result2 = pd.concat([df2, df2I], axis = 1, ignore_index=True, sort=False)\n", "result3 = pd.concat([df3, df3I], axis = 1, ignore_index=True, sort=False)\n", "\n", "df = pd.concat([result1, result2, result3])\n", "df.columns = [\"x\",\"y\", \"z\",\"class\"]\n", "df = df.reset_index(drop=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Veamos los puntos de forma tabulada.\n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | x | \n", "y | \n", "z | \n", "class | \n", "
---|---|---|---|---|
0 | \n", "0.166524 | \n", "0.476437 | \n", "-0.748905 | \n", "1 | \n", "
1 | \n", "-0.260890 | \n", "-1.210117 | \n", "1.111706 | \n", "1 | \n", "
2 | \n", "1.483352 | \n", "0.980338 | \n", "2.013879 | \n", "1 | \n", "
3 | \n", "-0.008549 | \n", "0.257644 | \n", "-1.536449 | \n", "1 | \n", "
4 | \n", "-1.467212 | \n", "-0.370246 | \n", "0.176544 | \n", "1 | \n", "
5 | \n", "-0.035987 | \n", "0.426323 | \n", "-1.165189 | \n", "1 | \n", "
6 | \n", "-1.098647 | \n", "0.331815 | \n", "1.964918 | \n", "1 | \n", "
7 | \n", "-0.272549 | \n", "-0.040916 | \n", "-0.370012 | \n", "1 | \n", "
8 | \n", "2.678083 | \n", "0.933871 | \n", "-0.728749 | \n", "1 | \n", "
9 | \n", "1.314680 | \n", "0.550044 | \n", "-1.232873 | \n", "1 | \n", "
10 | \n", "5.063146 | \n", "4.676758 | \n", "6.091572 | \n", "2 | \n", "
11 | \n", "4.005999 | \n", "4.868296 | \n", "5.885338 | \n", "2 | \n", "
12 | \n", "4.395932 | \n", "5.603112 | \n", "5.080207 | \n", "2 | \n", "
13 | \n", "5.908465 | \n", "5.186550 | \n", "6.903519 | \n", "2 | \n", "
14 | \n", "3.197914 | \n", "5.841706 | \n", "4.253857 | \n", "2 | \n", "
15 | \n", "5.017807 | \n", "4.312943 | \n", "3.940999 | \n", "2 | \n", "
16 | \n", "3.890963 | \n", "6.252370 | \n", "5.864753 | \n", "2 | \n", "
17 | \n", "4.683445 | \n", "5.941964 | \n", "4.850334 | \n", "2 | \n", "
18 | \n", "4.606564 | \n", "6.254284 | \n", "4.996100 | \n", "2 | \n", "
19 | \n", "3.944945 | \n", "4.605639 | \n", "5.809857 | \n", "2 | \n", "
20 | \n", "10.027336 | \n", "11.041746 | \n", "10.127516 | \n", "3 | \n", "
21 | \n", "8.923284 | \n", "9.785343 | \n", "11.444244 | \n", "3 | \n", "
22 | \n", "8.983430 | \n", "9.807272 | \n", "9.374686 | \n", "3 | \n", "
23 | \n", "8.087111 | \n", "8.450916 | \n", "8.720797 | \n", "3 | \n", "
24 | \n", "9.362836 | \n", "9.986216 | \n", "8.472149 | \n", "3 | \n", "
25 | \n", "10.091924 | \n", "9.338093 | \n", "9.719824 | \n", "3 | \n", "
26 | \n", "8.936871 | \n", "11.359872 | \n", "10.348214 | \n", "3 | \n", "
27 | \n", "10.474326 | \n", "11.126252 | \n", "10.260523 | \n", "3 | \n", "
28 | \n", "9.603450 | \n", "9.553276 | \n", "10.102165 | \n", "3 | \n", "
29 | \n", "8.888365 | \n", "10.522096 | \n", "8.616896 | \n", "3 | \n", "
Q_points
será nuestro conjunto de puntos tridimensionales y P_points
será nuestro conjunto de puntos bidimensionales con los que intentaremos visualizar el primer conjunto."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"Q_points = df.values[:,0:3] # Tomamos las coordenadas de los puntos, no la clase\n",
"P_points = np.random.uniform(0, 10, size=(30,2)) # Generamos puntos al azar"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Si visualizamos el conjunto de puntos bidimensional, veremos que está totalmente desordenado (está generado al azar)."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"P
y Q
. Los puntos P
son los que tenemos que \"mover\", por eso requieren gradiente."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"device = 'cuda' if torch.cuda.is_available() else 'cpu'\n",
"device = 'cpu'\n",
"\n",
"P = torch.tensor(P_points, requires_grad=True, dtype=torch.float, device=device)\n",
"Q = torch.tensor(Q_points, dtype=torch.float, device=device)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch: 0 loss: 39.479583740234375\n",
"Epoch: 10 loss: 15.956965446472168\n",
"Epoch: 20 loss: 13.391416549682617\n",
"Epoch: 30 loss: 12.188273429870605\n",
"Epoch: 40 loss: 10.87851333618164\n",
"Epoch: 50 loss: 10.16821575164795\n",
"Epoch: 60 loss: 9.989543914794922\n",
"Epoch: 70 loss: 9.744491577148438\n",
"Epoch: 80 loss: 9.489737510681152\n",
"Epoch: 90 loss: 8.615865707397461\n",
"Epoch: 100 loss: 8.053683280944824\n",
"Epoch: 110 loss: 7.864839553833008\n",
"Epoch: 120 loss: 7.308864593505859\n",
"Epoch: 130 loss: 6.854788780212402\n",
"Epoch: 140 loss: 5.771241188049316\n",
"Epoch: 150 loss: 4.689131736755371\n",
"Epoch: 160 loss: 4.214322566986084\n",
"Epoch: 170 loss: 4.072487831115723\n",
"Epoch: 180 loss: 4.051445007324219\n",
"Epoch: 190 loss: 4.03515625\n",
"Epoch: 200 loss: 4.021659851074219\n",
"Epoch: 210 loss: 4.013899803161621\n",
"Epoch: 220 loss: 3.9985787868499756\n",
"Epoch: 230 loss: 3.986757516860962\n",
"Epoch: 240 loss: 3.977696180343628\n",
"Epoch: 250 loss: 3.969468593597412\n",
"Epoch: 260 loss: 3.959566116333008\n",
"Epoch: 270 loss: 3.9487476348876953\n",
"Epoch: 280 loss: 3.9359965324401855\n",
"Epoch: 290 loss: 3.919861078262329\n",
"Epoch: 300 loss: 3.9039435386657715\n",
"Epoch: 310 loss: 3.8863189220428467\n",
"Epoch: 320 loss: 3.8603057861328125\n",
"Epoch: 330 loss: 3.8084962368011475\n",
"Epoch: 340 loss: 3.7537732124328613\n",
"Epoch: 350 loss: 3.695063591003418\n",
"Epoch: 360 loss: 3.590381383895874\n",
"Epoch: 370 loss: 3.4406182765960693\n",
"Epoch: 380 loss: 3.263678789138794\n",
"Epoch: 390 loss: 2.823730707168579\n",
"Epoch: 400 loss: 2.2120273113250732\n",
"Epoch: 410 loss: 0.6396467685699463\n",
"Epoch: 420 loss: 0.5637612342834473\n",
"Epoch: 430 loss: 0.5009985566139221\n",
"Epoch: 440 loss: 0.4680554270744324\n",
"Epoch: 450 loss: 0.4548220932483673\n",
"Epoch: 460 loss: 0.43580907583236694\n",
"Epoch: 470 loss: 0.436868280172348\n",
"Epoch: 480 loss: 0.4374592900276184\n",
"Epoch: 490 loss: 0.4361301362514496\n"
]
}
],
"source": [
"optimizer = torch.optim.RMSprop([P], lr=0.1)\n",
"\n",
"epochs = 500\n",
"\n",
"for k in range(epochs):\n",
" \n",
" PM = torch.tensor(np.zeros((len(P_points), len(P_points))), dtype=float, device=device)\n",
" QM = torch.tensor(np.zeros((len(P_points), len(P_points))), dtype=float, device=device)\n",
" \n",
" for i, q_row in enumerate(Q):\n",
" for j, q_column in enumerate(Q):\n",
" QM[i, j] = distance(q_row, q_column)\n",
" \n",
" QD = pdf(QM)\n",
" QD = torch.div(QD.t(), torch.sum(QD, dim=1)).t()\n",
" \n",
" for i, p in enumerate(P):\n",
" for j, q in enumerate(P):\n",
" PM[i, j] = distance(p, q)\n",
"\n",
" PD = pdf(PM)\n",
" PD = torch.div(PD.t(), torch.sum(PD, dim=1)).t()\n",
" \n",
" loss = torch.tensor([0.], device=device)\n",
" for pd, qd in zip(PD, QD):\n",
" loss += KL(pd, qd)\n",
" \n",
" if k%10 == 0:\n",
" print(\"Epoch:\", k, \"loss:\", loss.item())\n",
" \n",
"\n",
" loss.backward() \n",
" optimizer.step() \n",
" optimizer.zero_grad()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Visualizamos el resultado:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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/uGz9heft7/4vP3TWJ+1tVaFhYXKzs6W49Q8k8L3EQvHcdSxY8cj/u/E8y3YmyI+b//wWfuLz9tffN7+aYzPuraRigOYvAkAADxDsQAAAJ6JuWKRlJSku+++W0lJSUFHaRb4vP3DZ+0vPm9/8Xn7J+jP2vfJmwAAIH7F3IgFAABouigWAADAMxQLAADgGYoFAADwTMwVi8cff1xdunRRcnKyBg4cqKVLlwYdKe5MnjxZAwYMUHp6utq2batLL71U69atCzpWs3H//ffLGKNx48YFHSVubdq0Sddee61at26tlJQU9e7dWx9++GHQseJONBrVxIkTlZubq5SUFB177LG6995767zXBOrn3Xff1fDhw5WdnS1jjF566aUqz1trddddd6lDhw5KSUnR4MGD9fnnnzd6rpgqFrNnz9aECRN09913a8WKFerbt6+GDBmibdu2BR0trixcuFCjR4/WkiVLNG/ePJWVlemCCy5QUVFR0NHi3rJly/Tkk0+qT58+QUeJW7t27dKgQYOUkJCguXPn6pNPPtFDDz2krKysoKPFnQceeEBTp07VY489pk8//VQPPPCA/vCHP+jRRx8NOlpcKCoqUt++ffX4449X+/wf/vAHPfLII3riiSf0wQcfKC0tTUOGDNG+ffsaN5iNISeffLIdPXp05dfRaNRmZ2fbyZMnB5gq/m3bts1KsgsXLgw6SlwrLCy0Xbt2tfPmzbNnnXWWvfXWW4OOFJduu+02e/rppwcdo1kYNmyYvfHGG6tsu/zyy+3IkSMDShS/JNk5c+ZUfu26rm3fvr198MEHK7ft3r3bJiUl2ZkzZzZqlpgZsSgtLdXy5cs1ePDgym2O42jw4MFavHhxgMniX0FBgSSpVatWASeJb6NHj9awYcOq/B2H915++WXl5eXpqquuUtu2bdWvXz899dRTQceKS6eddprmz5+v9evXS5JWrVqlRYsWaejQoQEni38bNmzQli1bqnw/yczM1MCBAxv9mOn7TcgO144dOxSNRtWuXbsq29u1a6fPPvssoFTxz3VdjRs3ToMGDVKvXr2CjhO3Zs2apRUrVmjZsmVBR4l7X331laZOnaoJEyboN7/5jZYtW6axY8cqMTFR119/fdDx4srtt9+uSCSibt26KRQKKRqNatKkSRo5cmTQ0eLeli1bJKnaY+aB5xpLzBQLBGP06NFas2aNFi1aFHSUuJWfn69bb71V8+bNU3JyctBx4p7rusrLy9N9990nSerXr5/WrFmjJ554gmLhseeff17PPfecZsyYoZ49e2rlypUaN26csrOz+azjWMycCmnTpo1CoZC2bt1aZfvWrVvVvn37gFLFtzFjxujVV1/V22+/7cmt7lG95cuXa9u2berfv7/C4bDC4bAWLlyoRx55ROFwWNFoNOiIcaVDhw7q0aNHlW3du3fXN998E1Ci+PXrX/9at99+u0aMGKHevXvruuuu0/jx4zV58uSgo8W9A8fFII6ZMVMsEhMTddJJJ2n+/PmV21zX1fz583XqqacGmCz+WGs1ZswYzZkzRwsWLFBubm7QkeLaeeedp9WrV2vlypWVj7y8PI0cOVIrV65UKBQKOmJcGTRo0CGXT69fv16dO3cOKFH8Ki4uluNUPcyEQiG5rhtQouYjNzdX7du3r3LMjEQi+uCDDxr9mBlTp0ImTJig66+/Xnl5eTr55JM1ZcoUFRUVadSoUUFHiyujR4/WjBkz9I9//EPp6emV5+MyMzOVkpIScLr4k56efsj8lbS0NLVu3Zp5LY1g/PjxOu2003Tffffp6quv1tKlSzVt2jRNmzYt6GhxZ/jw4Zo0aZI6deqknj176qOPPtLDDz+sG2+8MehocWHPnj364osvKr/esGGDVq5cqVatWqlTp04aN26cfv/736tr167Kzc3VxIkTlZ2drUsvvbRxgzXqNSeN4NFHH7WdOnWyiYmJ9uSTT7ZLliwJOlLckVTtY/r06UFHaza43LRxvfLKK7ZXr142KSnJduvWzU6bNi3oSHEpEonYW2+91Xbq1MkmJyfbY445xt555522pKQk6Ghx4e233672e/X1119vra245HTixIm2Xbt2NikpyZ533nl23bp1jZ6L26YDAADPxMwcCwAA0PRRLAAAgGcoFgAAwDMUCwAA4BmKBQAA8AzFAgAAeIZiAQAAPEOxAAAAnqFYAAAAz1AsAACAZygWAADAMxQLAADgmf8PIJ1PBWvNBlsAAAAASUVORK5CYII=",
"text/plain": [
"