<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0">
 <channel>
  <title>SHRIPHANI PALAKODETY: Posts tagged 'data-science'</title>
  <description>SHRIPHANI PALAKODETY: Posts tagged 'data-science'</description>
  <link>http://blog.shriphani.com/tags/data-science.html</link>
  <lastBuildDate>Wed, 12 Nov 2014 21:24:54 UT</lastBuildDate>
  <pubDate>Wed, 12 Nov 2014 21:24:54 UT</pubDate>
  <ttl>1800</ttl>
  <item>
   <title>The Isomap Algorithm</title>
   <link>http://blog.shriphani.com/2014/11/12/the-isomap-algorithm/?utm_source=data-science&amp;utm_medium=RSS</link>
   <guid>urn:http-blog-shriphani-com:-2014-11-12-the-isomap-algorithm</guid>
   <pubDate>Wed, 12 Nov 2014 21:24:54 UT</pubDate>
   <description>&lt;html&gt;
&lt;p&gt;&lt;em&gt;This is part of a series on a family of dimension-reduction algorithms called non-linear dimension reduction. The goal here is to reduce the dimensions of a dataset (i.e. discard some columns in your data)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In previous posts, I discussed the &lt;a href="http://blog.shriphani.com/2014/10/29/low-dimension-embeddings-for-visualization/"&gt;MDS algorithm&lt;/a&gt; and presented &lt;a href="http://blog.shriphani.com/2014/11/02/powerful-ideas-in-manifold-learning/"&gt;some key ideas&lt;/a&gt;. In this post, I will describe how those ideas are leveraged in the Isomap algorithm. A clojure implementation based on core.matrix is also included.&lt;/p&gt;
&lt;!-- more--&gt;

&lt;h3 id="intuition"&gt;Intuition&lt;/h3&gt;

&lt;p&gt;Isomap uses the same core ideas as the MDS algorithm:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;
  &lt;p&gt;Obtain a matrix of proximities (distances between points in a  dataset).&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;
  &lt;p&gt;This distance matrix is a matrix of inner products.&lt;/p&gt;&lt;/li&gt;
 &lt;li&gt;
  &lt;p&gt;An eigendecomposition of this matrix gives us the lower dimension  embedding.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Isomap differs from MDS in one vital way - the construction of the distance matrix. In MDS, the distance between two points is just the euclidean distance.&lt;/p&gt;

&lt;p&gt;In Isomap, the distances between points are the weight of the shortest path in a point-graph.&lt;/p&gt;

&lt;p&gt;The point graph is constructed by placing an edge between two points if the euclidean distance between them falls under a certain threshold or between a point and its top $ k $ neighbors.&lt;/p&gt;

&lt;p&gt;This distance matrix captures the underlying manifold more accurately than one constructed using euclidean distances. The following toy example demonstrates this:&lt;/p&gt;

&lt;p&gt;&lt;img src="/img/isomap_data.png" /&gt;&lt;/p&gt;

&lt;p&gt;The data shown here looks like a swirl that starts at point 1 and ends at point 9. We would like to recover this phenomenon in our lower-dimension embedding.&lt;/p&gt;

&lt;p&gt;The first step is to build a distance matrix. Say we use euclidean distances between two points as the corresponding entry in the distance matrix.&lt;/p&gt;

&lt;p&gt;In this figure, it is clear that &lt;code&gt;euclidean_distance(1, 6) = euclidean_distance(1, 8)&lt;/code&gt; and &lt;code&gt;euclidean_distance(1, 5) = euclidean_distance(1, 9)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Clearly the distances computed here miss the &amp;ldquo;swirl&amp;rdquo; in the data entirely. Working with the point graph mentioned above helps us get around this problem.&lt;/p&gt;

&lt;p&gt;Let us build a point graph by adding an edge between a node and its nearest neighbor (so $ 1-NN $). The weight on the edge is the euclidean distance between the nodes. The distance between two points is the weight of the shortest path between these points. The point graph is shown below:&lt;/p&gt;

&lt;p&gt;&lt;img src="/img/isomap_point_graph.png" /&gt;&lt;/p&gt;

&lt;p&gt;Observe that when we use this newer distance metric, &lt;code&gt;distance(1, 6)&lt;/code&gt; is indeed less than  distance(1, 8) and  distance(1, 5) is indeed less than &lt;code&gt;distance(1, 9)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This distance function is clearly doing a better job of capturing the &amp;ldquo;swirl&amp;rdquo; in the data.&lt;/p&gt;

&lt;p&gt;The Isomap algorithm uses a distance matrix constructed like this in place of one constructed with euclidean distances. This distance matrix is then plugged into the MDS framework and an eigendecomposition is run on the double-centered matrix.&lt;/p&gt;

&lt;h3 id="implementation"&gt;Implementation&lt;/h3&gt;

&lt;p&gt;Let us do a clojure implementation.&lt;/p&gt;

&lt;p&gt;We have a point-set as a &lt;code&gt;core.matrix&lt;/code&gt; matrix. First, we compute the point-graph. I am going to place edges between a point and its 3 nearest neighbors (so $ 3-NN $). This routines expects a map of the type {point-index point-vector, &amp;hellip;}&lt;/p&gt;

&lt;div class="brush: clojure"&gt;
 &lt;table class="sourcetable"&gt;
  &lt;tbody&gt;
   &lt;tr&gt;
    &lt;td class="linenos"&gt;
     &lt;div class="linenodiv"&gt;
      &lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;
    &lt;td class="code"&gt;
     &lt;div class="source"&gt;
      &lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;build-point-graph&lt;/span&gt;
  &lt;span class="s"&gt;"A point graph is a k-NN graph. Edges between&lt;/span&gt;
&lt;span class="s"&gt;   a point and its 3 nearest neigbors"&lt;/span&gt;
  &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;indexed-points&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;build-point-graph&lt;/span&gt; &lt;span class="nv"&gt;indexed-points&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nv"&gt;indexed-points&lt;/span&gt; &lt;span class="nv"&gt;num-neighbors&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt; &lt;span class="nv"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;other-points&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;
                            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;not= &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
                            &lt;span class="nv"&gt;indexed-points&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;
           &lt;span class="nv"&gt;acc&lt;/span&gt;
           &lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;
                        &lt;span class="nv"&gt;first&lt;/span&gt;
                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;take &lt;/span&gt;&lt;span class="nv"&gt;num-neighbors&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sort-by&lt;/span&gt;
                               &lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;first &lt;/span&gt;&lt;span class="nv"&gt;%&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                               &lt;span class="nv"&gt;other-points&lt;/span&gt;&lt;span class="p"&gt;)))})))&lt;/span&gt;
      &lt;span class="p"&gt;{}&lt;/span&gt;
      &lt;span class="nv"&gt;indexed-points&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Then a simple Floyd Warshall algorithm implementation that computes the weights on the shortest paths. It takes the graph built in the previous step and the original indexed points and builds the graph.&lt;/p&gt;

&lt;div class="brush: clojure"&gt;
 &lt;table class="sourcetable"&gt;
  &lt;tbody&gt;
   &lt;tr&gt;
    &lt;td class="linenos"&gt;
     &lt;div class="linenodiv"&gt;
      &lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;
    &lt;td class="code"&gt;
     &lt;div class="source"&gt;
      &lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;floyd-warshall-distance&lt;/span&gt;
  &lt;span class="s"&gt;"Expected graph representation:&lt;/span&gt;
&lt;span class="s"&gt;    {V -&amp;gt; neighboring-points}"&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;a-graph&lt;/span&gt; &lt;span class="nv"&gt;indexed-points&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;indexed-points-dict&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;into &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="nv"&gt;indexed-points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nv"&gt;edges&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;
                  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="nv"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;concat &lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
                                     &lt;span class="nv"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
                  &lt;span class="p"&gt;[]&lt;/span&gt;
                  &lt;span class="nv"&gt;a-graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nv"&gt;inf-matrix&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;Double/POSITIVE_INFINITY&lt;/span&gt;
                      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;zero-matrix&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;indexed-points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;indexed-points&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

        &lt;span class="nv"&gt;zero-diag&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mset&lt;/span&gt; &lt;span class="nv"&gt;acc&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="nv"&gt;inf-matrix&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;indexed-points&lt;/span&gt; &lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;range&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="nv"&gt;weights-init&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;
                      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;acc&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
                        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mset&lt;/span&gt; &lt;span class="nv"&gt;acc&lt;/span&gt;
                              &lt;span class="nv"&gt;x&lt;/span&gt;
                              &lt;span class="nv"&gt;y&lt;/span&gt;
                              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt;
                               &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;indexed-points-dict&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                               &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;indexed-points-dict&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
                      &lt;span class="nv"&gt;zero-diag&lt;/span&gt;
                      &lt;span class="nv"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;old-distances&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;k&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;lt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mget&lt;/span&gt; &lt;span class="nv"&gt;old-distances&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mget&lt;/span&gt; &lt;span class="nv"&gt;old-distances&lt;/span&gt; &lt;span class="nv"&gt;k&lt;/span&gt; &lt;span class="nv"&gt;j&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mget&lt;/span&gt; &lt;span class="nv"&gt;old-distances&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;j&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mset&lt;/span&gt; &lt;span class="nv"&gt;old-distances&lt;/span&gt;
               &lt;span class="nv"&gt;i&lt;/span&gt;
               &lt;span class="nv"&gt;j&lt;/span&gt;
               &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mget&lt;/span&gt; &lt;span class="nv"&gt;old-distances&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mget&lt;/span&gt; &lt;span class="nv"&gt;old-distances&lt;/span&gt; &lt;span class="nv"&gt;k&lt;/span&gt; &lt;span class="nv"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
         &lt;span class="nv"&gt;old-distances&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
     &lt;span class="nv"&gt;weights-init&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;for &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;k&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;indexed-points&lt;/span&gt; &lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;indexed-points&lt;/span&gt; &lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="nv"&gt;j&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;indexed-points&lt;/span&gt; &lt;span class="nb"&gt;count &lt;/span&gt;&lt;span class="nv"&gt;range&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;k&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Once we have a distance matrix, we can simply feed it to MDS:&lt;/p&gt;

&lt;div class="brush: clojure"&gt;
 &lt;table class="sourcetable"&gt;
  &lt;tbody&gt;
   &lt;tr&gt;
    &lt;td class="linenos"&gt;
     &lt;div class="linenodiv"&gt;
      &lt;pre&gt;1
2
3
4
5
6
7&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;
    &lt;td class="code"&gt;
     &lt;div class="source"&gt;
      &lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;isomap&lt;/span&gt;
  &lt;span class="s"&gt;"Takes indexed-points and the target dimension"&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;points&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;indexed-points&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map-indexed&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="nv"&gt;points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nv"&gt;graph&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;build-point-graph&lt;/span&gt; &lt;span class="nv"&gt;indexed-points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nv"&gt;distances&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;floyd-warshall-distance&lt;/span&gt; &lt;span class="nv"&gt;graph&lt;/span&gt; &lt;span class="nv"&gt;indexed-points&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mds/distances-&amp;gt;points&lt;/span&gt; &lt;span class="nv"&gt;distances&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;And that&amp;rsquo;s it!&lt;/p&gt;

&lt;h3 id="examples"&gt;Examples&lt;/h3&gt;

&lt;p&gt;I will use word-vectors from word2vec for these 10 words: &lt;code&gt;river
lake
city
town
actor
doctor
dog
cat
animal
home&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The word vectors for these words are available in &lt;a href="/img/foo.csv"&gt;foo.csv&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let us reduce these to two dimensions. We get:&lt;/p&gt;

&lt;h4 id="isomap-embeddings"&gt;ISOMAP Embeddings&lt;/h4&gt;

&lt;iframe src="https://docs.google.com/spreadsheets/d/1zb8WGpVov_aYSsWREG9gsjYKv1KB-kPQUNfRHmW9LLY/pubchart?oid=1644191968&amp;amp;amp;format=interactive" style="width:100%;height:50vh;"&gt;&lt;/iframe&gt;

&lt;p&gt;The embeddings produced by the MDS algorithm are:&lt;/p&gt;

&lt;h4 id="mds-embeddings"&gt;MDS Embeddings&lt;/h4&gt;

&lt;iframe src="https://docs.google.com/spreadsheets/d/1yDeqAtGh_7kHvmsdLGsCzFMwFno1iJ9fn7zVqkToVoI/pubchart?oid=762847171&amp;amp;amp;format=interactive" style="width:100%;height:50vh;"&gt;&lt;/iframe&gt;

&lt;p&gt;Compared to the plot produced by MDS, we have more separation between terms - for instance &lt;code&gt;cat&lt;/code&gt; and &lt;code&gt;dog&lt;/code&gt; are place close by but they don&amp;rsquo;t overlap (unlike the MDS plot). This is a qualitative analysis, it is pretty hard to gauge which embedding is better.&lt;/p&gt;

&lt;h3 id="full-source"&gt;Full Source&lt;/h3&gt;

&lt;p&gt;See this repo: &lt;a href="https://github.com/shriphani/clojure-manifold"&gt;https://github.com/shriphani/clojure-manifold&lt;/a&gt;&lt;/p&gt;&lt;/html&gt;</description></item>
  <item>
   <title>Powerful Ideas in Manifold Learning</title>
   <link>http://blog.shriphani.com/2014/11/02/powerful-ideas-in-manifold-learning/?utm_source=data-science&amp;utm_medium=RSS</link>
   <guid>urn:http-blog-shriphani-com:-2014-11-02-powerful-ideas-in-manifold-learning</guid>
   <pubDate>Sun, 02 Nov 2014 10:10:47 UT</pubDate>
   <description>&lt;html&gt;
&lt;p&gt;In a &lt;a href="/2014/10/29/low-dimension-embeddings-for-visualization/"&gt;previous post&lt;/a&gt;, I described the MDS (multidimensional scaling) algorithm. This algorithm operates on a proximity matrix which is a matrix of distances between the points in a dataset. From this matrix, a configuration of points is retrieved in a lower dimension.&lt;/p&gt;

&lt;p&gt;The MDS strategy is:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;We have a matrix $ D $ for distances between points in the data.  This matrix is &lt;em&gt;symmetric&lt;/em&gt;.&lt;/li&gt;
 &lt;li&gt;We express distances as dot-products (using a proof from Schonberg).  This means that $ D $ is expressed as $ X^T X $. (Observe that $  X^T X $ is a matrix of dot-products).&lt;/li&gt;
 &lt;li&gt;Once we have $ X^T X $, dimension reduction is trivial. Running an  eigendecomposition on this matrix will produced centered  coordinates. The low-dimension embedding is recovered by discarding  eigenvalues (eigenvectors).&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Thus, assuming that we work with &lt;em&gt;euclidean distances&lt;/em&gt; between points, we retrieve an embedding that PCA itself would produce. Thus, &lt;strong&gt;MDS with euclidean distances is identical to PCA&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then what exactly is the value of running MDS on a dataset?&lt;/p&gt;

&lt;p&gt;First, the PCA is not the most powerful approach. For certain datasets, euclidean distances do not capture the shape of the underlying manifold. Running the steps of the MDS on a different distance matrix (at least one that doesn&amp;rsquo;t contain euclidean distances) can lead to better results - a technique that the &lt;a href="http://en.wikipedia.org/wiki/Isomap"&gt;Isomap algorithm&lt;/a&gt; exploits.&lt;/p&gt;

&lt;p&gt;Second, the PCA requires a vector-representation for points. In several situations, the objects in the dataset are not points in a metric space (like strings). We can retrieve distances between objects (say edit-distance for strings) and then obtain a vector-representation for the objects using MDS.&lt;/p&gt;

&lt;p&gt;In the next blog post, I will describe and implement the Isomap algorithm that leverages the ideas in the MDS strategy. Isomap constructs a distance matrix that attempts to do a better job at recovering the underlying manifold.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PROOFS:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;&lt;em&gt;Distances are dot-products:&lt;/em&gt;  &lt;a href="http://www.math.pku.edu.cn/teachers/yaoy/Fall2011/lecture11.pdf"&gt;These notes from Peking U&lt;/a&gt;  are easy to follow. I have mirrored them &lt;a href="/img/mds_proof.pdf"&gt;here&lt;/a&gt; in case that link 404s.&lt;/li&gt;&lt;/ul&gt;&lt;/html&gt;</description></item>
  <item>
   <title>Low Dimension Embeddings for Visualization</title>
   <link>http://blog.shriphani.com/2014/10/29/low-dimension-embeddings-for-visualization/?utm_source=data-science&amp;utm_medium=RSS</link>
   <guid>urn:http-blog-shriphani-com:-2014-10-29-low-dimension-embeddings-for-visualization</guid>
   <pubDate>Thu, 30 Oct 2014 03:15:52 UT</pubDate>
   <description>&lt;html&gt;
&lt;p&gt;Representation learning is a hot area in machine learning. In natural language processing (for example), learning long vectors for words has proven quite effective on several tasks. Often, these representations have several hundred dimensions. To perform a qualitative analysis of the learned representations, it helps to visualize them. Thus, we need a principled approach to drop from this high dimensional space to a lower dimensional space (like $ \mathbb{R}^2 $ for instance).&lt;/p&gt;

&lt;p&gt;In this blog post, I will discuss the Multidimensional scaling (MDS) algorithm - a manifold learning algorithm that recovers (or at least tries to recover) the underlying manifold that contains the data.&lt;/p&gt;

&lt;p&gt;MDS aims to find a configuration in a lower-dimension space that preserves distances between points in the data. In this post, I will provide intuition for this algorithm and an implementation for clojure (incanter).&lt;/p&gt;
&lt;!-- more--&gt;

&lt;p&gt;MDS works by preserving distances between points in the data. The end result of running this algorithm on a dataset is a spatial arrangement that preserves distances (to the best of its ability).&lt;/p&gt;

&lt;p&gt;For example, say you learn a representation for words - like word2vec. These representations are continuous vectors of 300 elements (at least the default vectors are). These representations preserve (or exhibit) some striking linguistic phenomena. For instance, $ R(man) - R(woman) \approx R(king) - R(queen) $. Words that are semantically similar tend to have similar representations.&lt;/p&gt;

&lt;p&gt;So how does one go about visualizing phenomena like these? Clearly, you want to be able to view these points in 2 dimensions (on a plot say) and also preserve some of the properties (i.e. similarity of semantically similar words).&lt;/p&gt;

&lt;p&gt;MDS operates on pairwise distances between data points. It retrieves an embedding of the data-points in a lower-dimensional space that preserves these distances. Thus, we can visualize the representations learned by using MDS to drop down to 2 dimensions. Ideally the distances should be preserved. Perfect.&lt;/p&gt;

&lt;p&gt;Here is an implementation for clojure (using &lt;code&gt;core.matrix&lt;/code&gt; - I had to set the implementation to &lt;code&gt;vectorz&lt;/code&gt; since svd seems to not be available by default):&lt;/p&gt;

&lt;div class="brush: clojure"&gt;
 &lt;table class="sourcetable"&gt;
  &lt;tbody&gt;
   &lt;tr&gt;
    &lt;td class="linenos"&gt;
     &lt;div class="linenodiv"&gt;
      &lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;
    &lt;td class="code"&gt;
     &lt;div class="source"&gt;
      &lt;pre&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;ns &lt;/span&gt;&lt;span class="nv"&gt;clojure-manifold.mds&lt;/span&gt;
  &lt;span class="s"&gt;"Implementation of MDS"&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:refer-clojure&lt;/span&gt; &lt;span class="ss"&gt;:exclude&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;* - + == &lt;/span&gt;&lt;span class="nv"&gt;/&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:require&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;clojure.core.matrix&lt;/span&gt; &lt;span class="ss"&gt;:refer&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;clojure.core.matrix.operators&lt;/span&gt; &lt;span class="ss"&gt;:refer&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;clojure.core.matrix.linear&lt;/span&gt; &lt;span class="ss"&gt;:refer&lt;/span&gt; &lt;span class="ss"&gt;:all&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set-current-implementation&lt;/span&gt; &lt;span class="ss"&gt;:vectorz&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;double-center&lt;/span&gt;
  &lt;span class="s"&gt;"Double centering:&lt;/span&gt;
&lt;span class="s"&gt;   0.5 * (matrix - row-mean - col-mean + grand-mean)"&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;a-matrix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;row-sum&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;apply + &lt;/span&gt;&lt;span class="nv"&gt;a-matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nv"&gt;col-sum&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;a-matrix&lt;/span&gt; &lt;span class="nv"&gt;transpose&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;apply &lt;/span&gt;&lt;span class="nv"&gt;+&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;num-rows&lt;/span&gt; &lt;span class="nv"&gt;num-cols&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;shape&lt;/span&gt; &lt;span class="nv"&gt;a-matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        
        &lt;span class="nv"&gt;row-mean&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;/ &lt;/span&gt;&lt;span class="nv"&gt;row-sum&lt;/span&gt; &lt;span class="nv"&gt;num-rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;repeat &lt;/span&gt;&lt;span class="nv"&gt;num-rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="nv"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nv"&gt;col-mean&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;-&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;/ &lt;/span&gt;&lt;span class="nv"&gt;col-sum&lt;/span&gt; &lt;span class="nv"&gt;num-cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;repeat &lt;/span&gt;&lt;span class="nv"&gt;num-cols&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="nv"&gt;matrix&lt;/span&gt;
                      &lt;span class="nv"&gt;transpose&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nv"&gt;grand-mean&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;/ &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce + &lt;/span&gt;&lt;span class="nv"&gt;row-sum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                         &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="nv"&gt;num-rows&lt;/span&gt; &lt;span class="nv"&gt;num-cols&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;new-matrix&lt;/span&gt; &lt;span class="nv"&gt;num-rows&lt;/span&gt; &lt;span class="nv"&gt;num-cols&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="mf"&gt;-0.5&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;a-matrix&lt;/span&gt;
           &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="nv"&gt;row-mean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;- &lt;/span&gt;&lt;span class="nv"&gt;col-mean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
           &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;+ &lt;/span&gt;&lt;span class="nv"&gt;grand-mean&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;proximity-matrix&lt;/span&gt;
  &lt;span class="s"&gt;"Construct a proximity matrix (of euclidean distances)"&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;a-matrix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
     &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Math/pow&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;distance&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                  &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="nv"&gt;a-matrix&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
   &lt;span class="nv"&gt;a-matrix&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;defn &lt;/span&gt;&lt;span class="nv"&gt;mds&lt;/span&gt;
  &lt;span class="s"&gt;"Take a matrix and find a configuration in n dimensions&lt;/span&gt;
&lt;span class="s"&gt;   that preserves directions"&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;a-matrix&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;D&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;proximity-matrix&lt;/span&gt; &lt;span class="nv"&gt;a-matrix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nv"&gt;centered-D&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;double-center&lt;/span&gt; &lt;span class="nv"&gt;D&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;U&lt;/span&gt; &lt;span class="ss"&gt;:U&lt;/span&gt;
         &lt;span class="nv"&gt;S&lt;/span&gt; &lt;span class="ss"&gt;:S&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;svd&lt;/span&gt; &lt;span class="nv"&gt;centered-D&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;* &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;submatrix&lt;/span&gt; &lt;span class="nv"&gt;U&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;submatrix&lt;/span&gt; &lt;span class="nv"&gt;S&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nv"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;I will test these on a few word-vectors from &lt;a href="https://code.google.com/p/word2vec/"&gt;word2vec&lt;/a&gt;. The words in question are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;river
lake
city
town
actor
doctor
dog
cat
animal
home&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The word vectors for these words are available in &lt;a href="/img/foo.csv"&gt;foo.csv&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I then ran MDS on this matrix like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;user&amp;gt; (use 'clojure-manifold.mds :reload)
nil
user&amp;gt; (def M (load-data "foo.csv"))
#'user/M
user&amp;gt; (save-csv (mds M 2) "foo-reduced.csv") ; reduce to 2 dimensions&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The plot looks like so:&lt;/p&gt;

&lt;iframe src="https://docs.google.com/spreadsheets/d/1yDeqAtGh_7kHvmsdLGsCzFMwFno1iJ9fn7zVqkToVoI/pubchart?oid=762847171&amp;amp;amp;format=interactive" style="width:100%;height:50vh;"&gt;&lt;/iframe&gt;

&lt;p&gt;Looking at this plot, we observe that the resulting configuration places semantically similar words close by. For instance &lt;code&gt;{dog, cat, animal}&lt;/code&gt;, &lt;code&gt;{home, actor, doctor}&lt;/code&gt;, &lt;code&gt;{lake, river}&lt;/code&gt; and &lt;code&gt;{city, town}&lt;/code&gt; are groups that are clustered together and the individual clusters are pretty far away from each other.&lt;/p&gt;

&lt;p&gt;In a later blog post, I will work through the proof.&lt;/p&gt;

&lt;p&gt;The source code for MDS is available in this repo: &lt;a href="https://github.com/shriphani/clojure-manifold"&gt;https://github.com/shriphani/clojure-manifold&lt;/a&gt;&lt;/p&gt;&lt;/html&gt;</description></item></channel></rss>