{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Exploring Hackers News Posts\n", "\n", "In this project, we'll compare two different types of posts from [Hacker News](https://news.ycombinator.com/), a popular site where technology related stories (or 'posts') are voted and commented upon. The two types of posts we'll explore begin with either `Ask HN` or `Show HN`.\n", "\n", "Users submit `Ask HN` posts to ask the Hacker News community a specific question, such as \"What is the best online course you've ever taken?\" Likewise, users submit `Show HN` posts to show the Hacker News community a project, product, or just generally something interesting.\n", "\n", "We'll specifically compare these two types of posts to determine the following:\n", "\n", "- Do `Ask HN` or `Show HN` receive more comments on average?\n", "- Do posts created at a certain time receive more comments on average?\n", "\n", "It should be noted that the data set we're working with was reduced from almost 300,000 rows to approximately 20,000 rows by removing all submissions that did not receive any comments, and then randomly sampling from the remaining submissions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction\n", "\n", "First, we'll read in the data and remove the headers." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['id', 'title', 'url', 'num_points', 'num_comments', 'author', 'created_at'],\n", " ['12224879',\n", " 'Interactive Dynamic Video',\n", " 'http://www.interactivedynamicvideo.com/',\n", " '386',\n", " '52',\n", " 'ne0phyte',\n", " '8/4/2016 11:52'],\n", " ['10975351',\n", " 'How to Use Open Source and Shut the Fuck Up at the Same Time',\n", " 'http://hueniverse.com/2016/01/26/how-to-use-open-source-and-shut-the-fuck-up-at-the-same-time/',\n", " '39',\n", " '10',\n", " 'josep2',\n", " '1/26/2016 19:30'],\n", " ['11964716',\n", " \"Florida DJs May Face Felony for April Fools' Water Joke\",\n", " 'http://www.thewire.com/entertainment/2013/04/florida-djs-april-fools-water-joke/63798/',\n", " '2',\n", " '1',\n", " 'vezycash',\n", " '6/23/2016 22:20'],\n", " ['11919867',\n", " 'Technology ventures: From Idea to Enterprise',\n", " 'https://www.amazon.com/Technology-Ventures-Enterprise-Thomas-Byers/dp/0073523429',\n", " '3',\n", " '1',\n", " 'hswarna',\n", " '6/17/2016 0:01']]" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Read in the data.\n", "import csv\n", "\n", "f = open('hacker_news.csv')\n", "hn = list(csv.reader(f))\n", "hn[:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Removing Headers from a List of Lists" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['id', 'title', 'url', 'num_points', 'num_comments', 'author', 'created_at']\n", "[['12224879', 'Interactive Dynamic Video', 'http://www.interactivedynamicvideo.com/', '386', '52', 'ne0phyte', '8/4/2016 11:52'], ['10975351', 'How to Use Open Source and Shut the Fuck Up at the Same Time', 'http://hueniverse.com/2016/01/26/how-to-use-open-source-and-shut-the-fuck-up-at-the-same-time/', '39', '10', 'josep2', '1/26/2016 19:30'], ['11964716', \"Florida DJs May Face Felony for April Fools' Water Joke\", 'http://www.thewire.com/entertainment/2013/04/florida-djs-april-fools-water-joke/63798/', '2', '1', 'vezycash', '6/23/2016 22:20'], ['11919867', 'Technology ventures: From Idea to Enterprise', 'https://www.amazon.com/Technology-Ventures-Enterprise-Thomas-Byers/dp/0073523429', '3', '1', 'hswarna', '6/17/2016 0:01'], ['10301696', 'Note by Note: The Making of Steinway L1037 (2007)', 'http://www.nytimes.com/2007/11/07/movies/07stein.html?_r=0', '8', '2', 'walterbell', '9/30/2015 4:12']]\n" ] } ], "source": [ "# Remove the headers.\n", "headers = hn[0]\n", "hn = hn[1:]\n", "print(headers)\n", "print(hn[:5])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see above that the data set contains the title of the posts, the number of comments for each post, and the date the post was created. Let's start by exploring the number of comments for each type of post. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Extracting Ask HN and Show HN Posts\n", "\n", "First, we'll identify posts that begin with either `Ask HN` or `Show HN` and separate the data for those two types of posts into different lists. Separating the data makes it easier to analyze in the following steps." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1744\n", "1162\n", "17194\n" ] } ], "source": [ "# Identify posts that begin with either `Ask HN` or `Show HN` and separate the data into different lists.\n", "import re\n", "ask_posts = []\n", "show_posts =[]\n", "other_posts = []\n", "\n", "for post in hn:\n", " title = post[1]\n", " match1 = re.search(r\"^Ask HN\", title, re.I)\n", " match2 = re.search(r\"^Show HN\", title, re.I)\n", " if match1:\n", " ask_posts.append(post)\n", " elif match2:\n", " show_posts.append(post)\n", " else:\n", " other_posts.append(post)\n", " \n", "print(len(ask_posts))\n", "print(len(show_posts))\n", "print(len(other_posts))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Calculating the Average Number of Comments for Ask HN and Show HN Posts\n", "\n", "Now that we separated `Ask HN` and `Show HN` posts into different lists, we'll calculate the average number of comments each type of post receives." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "14.038417431192661\n" ] } ], "source": [ "# Calculate the average number of comments `Ask HN` posts receive.\n", "ask_comments = [int(post[4]) for post in ask_posts]\n", "avg_ask_comments = sum(ask_comments) / len(ask_posts)\n", "print(avg_ask_comments)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10.31669535283993\n" ] } ], "source": [ "# Calculate the average number of comments `Show HN` posts receive.\n", "show_comments = [int(post[4]) for post in show_posts]\n", "avg_show_comments = sum(show_comments) / len(show_posts)\n", "print(avg_show_comments)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On average, `Ask HN` posts in our sample receive approximately 14 comments, whereas `Show HN` posts receive approximately 10. Since `Ask HN` posts are more likely to receive comments, we'll focus our remaining analysis just on these posts. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Finding the Amount of Ask HN Posts and Comments by Hour Created\n", "\n", "Next, we'll determine if we can maximize the amount of comments an `Ask HN` post receives by creating it at a certain time. First, we'll find the amount of `Ask HN` posts created during each hour of day, along with the number of comments those posts received. Then, we'll calculate the average amount of comments `Ask HN` posts created at each hour of the day receive." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'09': 251,\n", " '13': 1253,\n", " '10': 793,\n", " '14': 1416,\n", " '16': 1814,\n", " '23': 543,\n", " '12': 687,\n", " '17': 1146,\n", " '15': 4477,\n", " '21': 1745,\n", " '20': 1722,\n", " '02': 1381,\n", " '18': 1439,\n", " '03': 421,\n", " '05': 464,\n", " '19': 1188,\n", " '01': 683,\n", " '22': 479,\n", " '08': 492,\n", " '04': 337,\n", " '00': 447,\n", " '06': 397,\n", " '07': 267,\n", " '11': 641}" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Calculate the amount of `Ask HN` posts created during each hour of day and the number of comments received.\n", "import datetime as dt\n", "\n", "ask_comments = [int(post[4]) for post in ask_posts]\n", "created_date = [post[6] for post in ask_posts]\n", "\n", "result_list = zip(created_date, ask_comments)\n", "\n", "comments_by_hour = {}\n", "counts_by_hour = {}\n", "date_format = \"%m/%d/%Y %H:%M\"\n", "\n", "for date, comment in result_list:\n", " time = dt.datetime.strptime(date, date_format).strftime(\"%H\")\n", " if time in counts_by_hour:\n", " comments_by_hour[time] += comment\n", " counts_by_hour[time] += 1\n", " else:\n", " comments_by_hour[time] = comment\n", " counts_by_hour[time] = 1\n", "\n", "comments_by_hour" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Calculating the Average Number of Comments for Ask HN Posts by Hour" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['09', 5.5777777777777775],\n", " ['13', 14.741176470588234],\n", " ['10', 13.440677966101696],\n", " ['14', 13.233644859813085],\n", " ['16', 16.796296296296298],\n", " ['23', 7.985294117647059],\n", " ['12', 9.41095890410959],\n", " ['17', 11.46],\n", " ['15', 38.5948275862069],\n", " ['21', 16.009174311926607],\n", " ['20', 21.525],\n", " ['02', 23.810344827586206],\n", " ['18', 13.20183486238532],\n", " ['03', 7.796296296296297],\n", " ['05', 10.08695652173913],\n", " ['19', 10.8],\n", " ['01', 11.383333333333333],\n", " ['22', 6.746478873239437],\n", " ['08', 10.25],\n", " ['04', 7.170212765957447],\n", " ['00', 8.127272727272727],\n", " ['06', 9.022727272727273],\n", " ['07', 7.852941176470588],\n", " ['11', 11.051724137931034]]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Calculate the average amount of comments `Ask HN` posts created at each hour of the day receive.\n", "avg_by_hour = [[hr, comments_by_hour[hr] / counts_by_hour[hr]] for hr in comments_by_hour]\n", "avg_by_hour" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Sorting and Printing Values from a List of Lists" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Top 5 Hours for 'Ask HN' Comments\n", "15:00: 38.59 average comments per post\n", "02:00: 23.81 average comments per post\n", "20:00: 21.52 average comments per post\n", "16:00: 16.80 average comments per post\n", "21:00: 16.01 average comments per post\n" ] } ], "source": [ "# Sort the values and print the the 5 hours with the highest average comments.\n", "avg_by_hour = sorted(avg_by_hour, key=lambda result: result[1], reverse=True)\n", "\n", "print(\"Top 5 Hours for 'Ask HN' Comments\")\n", "for hr, avg in avg_by_hour[:5]:\n", " print(\"{}: {:.2f} average comments per post\".format(dt.datetime.strptime(hr, \"%H\").strftime(\"%H:%M\"),avg))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The hour that receives the most comments per post on average is 15:00, with an average of 38.59 comments per post. There's about a 60% increase in the number of comments between the hours with the highest and second highest \n", "average number of comments.\n", "\n", "According to the data set [documentation](https://www.kaggle.com/hacker-news/hacker-news-posts/home), the timezone used is Eastern Time in the US. So, we could also write 15:00 as 3:00 pm est." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Conclusion\n", "\n", "In this project, we analyzed `Ask HN` and `Show HN` posts to determine which type of post and time receive the most comments on average. Based on our analysis, to maximize the amount of comments a post receives, we'd recommend the post be categorized as `Ask HN` and created between 15:00 and 16:00 (3:00 pm est - 4:00 pm est). \n", "\n", "However, it should be noted that the data set we analyzed excluded posts without any comments. Given that, it's more accurate to say that *of the posts that received comments*, `Ask HN` posts received more comments on average and `Ask HN` posts created between 15:00 and 16:00 (3:00 pm est - 4:00 pm est) received the most comments on average. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.6" } }, "nbformat": 4, "nbformat_minor": 2 }