{
  "id": 2000,
  "title": "Good first step: make graph more commutative",
  "url": "/competitions/FacebookRecruiting/discussion/2000",
  "author_name": "Aaron Schumacher",
  "post_date": "2012-06-06T18:56:59.963000",
  "votes": 22,
  "comment_count": 10,
  "views": 8129,
  "content": "<p>Hi! So, this graph is directed, meaning you can have A -&gt; B without having B -&gt; A. For kicks, I did a solution where my only predictions were those that made the graph more commutative. That is, if in the training set A -&gt; B but not B -&gt; A, and I had to\r\n predict for B, I predicted A. When there were more than ten such possible predictions, I just took the first that happened to be in the list. For some entries in the test set, I didn't make any prediction at all. I was wondering if I would get a score of zero,\r\n since this is such a simple technique and maybe the data was designed so that all good predictions didn't exist going either direction in the training set. But instead I got a score of 0.61523, which is currently good enough for third place. So: I suggest\r\n as a first step just introducing all the missing reciprocal edges that you can - then work on making a smart algorithm for your remaining guesses. No more low scores!</p>",
  "messages": [
    {
      "id": 11426,
      "postDate": "2012-06-06T18:56:59.963Z",
      "content": "<p>Hi! So, this graph is directed, meaning you can have A -&gt; B without having B -&gt; A. For kicks, I did a solution where my only predictions were those that made the graph more commutative. That is, if in the training set A -&gt; B but not B -&gt; A, and I had to\r\n predict for B, I predicted A. When there were more than ten such possible predictions, I just took the first that happened to be in the list. For some entries in the test set, I didn't make any prediction at all. I was wondering if I would get a score of zero,\r\n since this is such a simple technique and maybe the data was designed so that all good predictions didn't exist going either direction in the training set. But instead I got a score of 0.61523, which is currently good enough for third place. So: I suggest\r\n as a first step just introducing all the missing reciprocal edges that you can - then work on making a smart algorithm for your remaining guesses. No more low scores!</p>",
      "votes": 22
    },
    {
      "id": 11434,
      "postDate": "2012-06-07T01:03:36.550Z",
      "content": "<pre># <span>This code generates a file that gets a score of 0.61525</span></pre>\r\n<pre><span># Also at https://gist.github.com/2885835</span></pre>\r\n<pre>&nbsp;</pre>\r\n<pre>import csv<br><br>r = csv.reader(open('train.csv','r'))<br>r.next()<br><br>edges = set()<br>#commutative_graph = dict()<br>for edge in r:<br>    edges.add((edge[0], edge[1]))<br>#    commutative_graph.setdefault(edge[0], set()).add(edge[1])<br>#    commutative_graph.setdefault(edge[1], set()).add(edge[0])<br><br>missing_edges = set()<br>for edge in edges:<br>    if (edge[1], edge[0]) not in edges:<br>        missing_edges.add((edge[1], edge[0]))<br><br>missing_graph = dict()<br>for edge in missing_edges:<br>    missing_graph.setdefault(edge[0], set()).add(edge[1])<br><br>r = csv.reader(open('test.csv','r'))<br>r.next()<br><br>test_list = list()<br>for line in r:<br>    test_list.append(line[0])<br><br>test_lists = dict()<br>for node in test_list:<br>    test_lists[node] = list(missing_graph.get(node, set()))<br><br>file = open('output.csv','w')<br>w = csv.writer(file)<br>w.writerow(['source_node','destination_nodes'])<br>for node in test_list:<br>    w.writerow([node, &quot; &quot;.join(test_lists[node][0:9])])<br>file.close()</pre>",
      "votes": 14
    },
    {
      "id": 11899,
      "postDate": "2012-06-26T16:51:13.733Z",
      "content": "<p>The technique you describe is at the heart of <a href=\"http://www.kaggle.com/c/FacebookRecruiting/forums/t/2082/0-711-is-the-new-0\">\r\nDon Souleo's link-following technique</a>&nbsp;.</p>\r\n<p>On a slightly different note, I've found it useful to think in terms of how balanced the outbound links (from Node A --&gt; Node B) are to the inbound links (A &lt;-- B).&nbsp;</p>\r\n<p>Let's say Node A links to 100 nodes and is linked to by 50 nodes. &nbsp;Then its 'outbound ratio' is 100 / (100 &#43; 50) or 0.667. &nbsp;So, 'outbound ratio' lies in [0,1]. &nbsp;Looking at the conditional probability that an inbound link will be matched by an outbound link\r\n (that is, if B--&gt;A, what is the probability that A--&gt;B), and plotting according to a node's outbound ratio, I get the following chart.</p>\r\n<p>&nbsp;</p>\r\n<p><img src=\"http://farm9.staticflickr.com/8166/7448680610_617d5817e2.jpg\" alt=\"Probability that an inbound link will be matched by an outbound link\" width=\"500\" height=\"313\" style=\"display:block; margin-left:auto; margin-right:auto\"></p>\r\n<p style=\"text-align:left\">Intuitively, this makes sense (or perhaps is obvious ;-)</p>\r\n<p style=\"text-align:left\">The X-axis is the 'outbound ratio'. &nbsp;Smaller numbers mean more inbound links than outbound. &nbsp;Thus, we'd expect a low probability for an inbound link to be matched by an outbound link. &nbsp;The Y-axis is the conditional probability of\r\n a node having an outbound link given an inbound link.</p>\r\n<p style=\"text-align:left\">As 'outbound ratio' increases, so does probability of that an inbound link will be matched to an outbound link. &nbsp;After 50%, the probability levels off. &nbsp;Again, this might be stating the obvious, but understanding the predictive power\r\n of an inbound link based on a node's outbound ratio can be useful when blending multiple strategies. &nbsp;If a node has many inbound links and very few outbound (Justin Bieber on Twitter), then you're not going to get a lot from using inbound links. &nbsp;</p>",
      "votes": 4
    },
    {
      "id": 11889,
      "postDate": "2012-06-26T06:00:40.193Z",
      "content": "<p>Wow, i was working on a truncated file! had half the inputs - gave me half the score. Your reference helped me found it, thanks!</p>",
      "votes": 1
    },
    {
      "id": 11862,
      "postDate": "2012-06-25T02:56:24.383Z",
      "content": "<pre class=\"x_prettyprint\"><span class=\"x_pln\">w</span><span class=\"x_pun\">.</span><span class=\"x_pln\">writerow</span><span class=\"x_pun\">([</span><span class=\"x_pln\">node</span><span class=\"x_pun\">,</span><span class=\"x_str\">&quot; &quot;</span><span class=\"x_pun\">.</span><span class=\"x_pln\">join</span><span class=\"x_pun\">(</span><span class=\"x_pln\">test_lists</span><span class=\"x_pun\">[</span><span class=\"x_pln\">node</span><span class=\"x_pun\">][</span><span class=\"x_lit\">0</span><span class=\"x_pun\">:</span><span class=\"x_lit\">9</span><span class=\"x_pun\">])]) -&gt; should be </span><span class=\"x_pln\">test_lists</span><span class=\"x_pun\">[</span><span class=\"x_pln\">node</span><span class=\"x_pun\">][</span><span class=\"x_lit\">0</span><span class=\"x_pun\">:10</span><span class=\"x_pun\">] for the right number of suggestions (10)</span></pre>\r\n<pre class=\"x_prettyprint\">&nbsp;</pre>",
      "votes": 1
    },
    {
      "id": 11861,
      "postDate": "2012-06-25T01:14:05.940Z",
      "content": "<p>Hi drago! That's interesting; I don't know what's happening on your system. Let me know if you figure it out. Good luck!</p>",
      "votes": 1
    },
    {
      "id": 11860,
      "postDate": "2012-06-25T00:22:18.197Z",
      "content": "<p>I ran your code - it scored only 0.34736.</p>"
    },
    {
      "id": 11639,
      "postDate": "2012-06-16T02:09:43.867Z"
    },
    {
      "id": 11503,
      "postDate": "2012-06-10T06:12:21.557Z",
      "content": "<p>You just beat me to it, that's exactly the first thing I wanted to submit, but decided to first load everything to a db :)</p>"
    },
    {
      "id": 11498,
      "postDate": "2012-06-09T21:16:44.097Z",
      "content": "<p>wow, that's completely counterintuitive to what I've been doing i.e. filter out all non-reciprocating relationships and only work with reciprocating relationships (wouldn't want to be recommended as a friend to someone who's friend request I didn't accept\r\n - or to their friends).</p>"
    },
    {
      "id": 11429,
      "postDate": "2012-06-06T19:09:39.910Z",
      "rawMarkdown": "",
      "votes": 1,
      "isDeleted": true
    }
  ],
  "comments": [
    {
      "id": 11434,
      "author_name": "Aaron Schumacher",
      "author_url": "",
      "post_date": "2012-06-07T01:03:36.550000",
      "content": "<pre># <span>This code generates a file that gets a score of 0.61525</span></pre>\r\n<pre><span># Also at https://gist.github.com/2885835</span></pre>\r\n<pre>&nbsp;</pre>\r\n<pre>import csv<br><br>r = csv.reader(open('train.csv','r'))<br>r.next()<br><br>edges = set()<br>#commutative_graph = dict()<br>for edge in r:<br>    edges.add((edge[0], edge[1]))<br>#    commutative_graph.setdefault(edge[0], set()).add(edge[1])<br>#    commutative_graph.setdefault(edge[1], set()).add(edge[0])<br><br>missing_edges = set()<br>for edge in edges:<br>    if (edge[1], edge[0]) not in edges:<br>        missing_edges.add((edge[1], edge[0]))<br><br>missing_graph = dict()<br>for edge in missing_edges:<br>    missing_graph.setdefault(edge[0], set()).add(edge[1])<br><br>r = csv.reader(open('test.csv','r'))<br>r.next()<br><br>test_list = list()<br>for line in r:<br>    test_list.append(line[0])<br><br>test_lists = dict()<br>for node in test_list:<br>    test_lists[node] = list(missing_graph.get(node, set()))<br><br>file = open('output.csv','w')<br>w = csv.writer(file)<br>w.writerow(['source_node','destination_nodes'])<br>for node in test_list:<br>    w.writerow([node, &quot; &quot;.join(test_lists[node][0:9])])<br>file.close()</pre>",
      "votes": 14,
      "replies": []
    },
    {
      "id": 11899,
      "author_name": "Dave Klein",
      "author_url": "",
      "post_date": "2012-06-26T16:51:13.733000",
      "content": "<p>The technique you describe is at the heart of <a href=\"http://www.kaggle.com/c/FacebookRecruiting/forums/t/2082/0-711-is-the-new-0\">\r\nDon Souleo's link-following technique</a>&nbsp;.</p>\r\n<p>On a slightly different note, I've found it useful to think in terms of how balanced the outbound links (from Node A --&gt; Node B) are to the inbound links (A &lt;-- B).&nbsp;</p>\r\n<p>Let's say Node A links to 100 nodes and is linked to by 50 nodes. &nbsp;Then its 'outbound ratio' is 100 / (100 &#43; 50) or 0.667. &nbsp;So, 'outbound ratio' lies in [0,1]. &nbsp;Looking at the conditional probability that an inbound link will be matched by an outbound link\r\n (that is, if B--&gt;A, what is the probability that A--&gt;B), and plotting according to a node's outbound ratio, I get the following chart.</p>\r\n<p>&nbsp;</p>\r\n<p><img src=\"http://farm9.staticflickr.com/8166/7448680610_617d5817e2.jpg\" alt=\"Probability that an inbound link will be matched by an outbound link\" width=\"500\" height=\"313\" style=\"display:block; margin-left:auto; margin-right:auto\"></p>\r\n<p style=\"text-align:left\">Intuitively, this makes sense (or perhaps is obvious ;-)</p>\r\n<p style=\"text-align:left\">The X-axis is the 'outbound ratio'. &nbsp;Smaller numbers mean more inbound links than outbound. &nbsp;Thus, we'd expect a low probability for an inbound link to be matched by an outbound link. &nbsp;The Y-axis is the conditional probability of\r\n a node having an outbound link given an inbound link.</p>\r\n<p style=\"text-align:left\">As 'outbound ratio' increases, so does probability of that an inbound link will be matched to an outbound link. &nbsp;After 50%, the probability levels off. &nbsp;Again, this might be stating the obvious, but understanding the predictive power\r\n of an inbound link based on a node's outbound ratio can be useful when blending multiple strategies. &nbsp;If a node has many inbound links and very few outbound (Justin Bieber on Twitter), then you're not going to get a lot from using inbound links. &nbsp;</p>",
      "votes": 4,
      "replies": []
    },
    {
      "id": 11889,
      "author_name": "Doron",
      "author_url": "",
      "post_date": "2012-06-26T06:00:40.193000",
      "content": "<p>Wow, i was working on a truncated file! had half the inputs - gave me half the score. Your reference helped me found it, thanks!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 11862,
      "author_name": "nhan vu",
      "author_url": "",
      "post_date": "2012-06-25T02:56:24.383000",
      "content": "<pre class=\"x_prettyprint\"><span class=\"x_pln\">w</span><span class=\"x_pun\">.</span><span class=\"x_pln\">writerow</span><span class=\"x_pun\">([</span><span class=\"x_pln\">node</span><span class=\"x_pun\">,</span><span class=\"x_str\">&quot; &quot;</span><span class=\"x_pun\">.</span><span class=\"x_pln\">join</span><span class=\"x_pun\">(</span><span class=\"x_pln\">test_lists</span><span class=\"x_pun\">[</span><span class=\"x_pln\">node</span><span class=\"x_pun\">][</span><span class=\"x_lit\">0</span><span class=\"x_pun\">:</span><span class=\"x_lit\">9</span><span class=\"x_pun\">])]) -&gt; should be </span><span class=\"x_pln\">test_lists</span><span class=\"x_pun\">[</span><span class=\"x_pln\">node</span><span class=\"x_pun\">][</span><span class=\"x_lit\">0</span><span class=\"x_pun\">:10</span><span class=\"x_pun\">] for the right number of suggestions (10)</span></pre>\r\n<pre class=\"x_prettyprint\">&nbsp;</pre>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 11861,
      "author_name": "Aaron Schumacher",
      "author_url": "",
      "post_date": "2012-06-25T01:14:05.940000",
      "content": "<p>Hi drago! That's interesting; I don't know what's happening on your system. Let me know if you figure it out. Good luck!</p>",
      "votes": 1,
      "replies": []
    },
    {
      "id": 11860,
      "author_name": "Doron",
      "author_url": "",
      "post_date": "2012-06-25T00:22:18.197000",
      "content": "<p>I ran your code - it scored only 0.34736.</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 11639,
      "author_name": "vgoklani",
      "author_url": "",
      "post_date": "2012-06-16T02:09:43.867000",
      "content": "",
      "votes": 0,
      "replies": []
    },
    {
      "id": 11503,
      "author_name": "r0u1i",
      "author_url": "",
      "post_date": "2012-06-10T06:12:21.557000",
      "content": "<p>You just beat me to it, that's exactly the first thing I wanted to submit, but decided to first load everything to a db :)</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 11498,
      "author_name": "djmachet",
      "author_url": "",
      "post_date": "2012-06-09T21:16:44.097000",
      "content": "<p>wow, that's completely counterintuitive to what I've been doing i.e. filter out all non-reciprocating relationships and only work with reciprocating relationships (wouldn't want to be recommended as a friend to someone who's friend request I didn't accept\r\n - or to their friends).</p>",
      "votes": 0,
      "replies": []
    },
    {
      "id": 11429,
      "author_name": "",
      "author_url": "",
      "post_date": "2012-06-06T19:09:39.910000",
      "content": "",
      "votes": 1,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "11426": "",
    "11434": "",
    "11899": "",
    "11889": "",
    "11862": "",
    "11861": "",
    "11860": "",
    "11639": "",
    "11503": "",
    "11498": "",
    "11429": ""
  }
}