{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "e4f0efa9-587c-f984-dc6c-a059249b4be8"
      },
      "source": [
        "#Introduction\n",
        "Each pixel has values ranging from 0 to 255. For an image, it should be useful but for hand writing, perhaps having a binary value to whether there is/isn't  a stroke at a particular pixel might be sufficient. Let's see. \n",
        "\n",
        "#Binarizing Step\n",
        "We start by performing a simple preprocessing which was ran offline (~1.75 hours) since the notebook can only run codes for up to 20 minutes before the process being killed. **We use the mean for each image as the cutoff to perform \"local\" binarization**. Sample code to run offline is show here:"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "9131b060-f5ac-ea39-36d5-a17eed4670f5"
      },
      "source": [
        "train <- read.csv(\"../input/train.csv\")\n",
        "\n",
        "mean_=apply(train,1,mean)\n",
        "\n",
        "train_=train\n",
        "\n",
        "for(i in 1:dim(train_)[1])\n",
        "{\n",
        "\ttrain_[i,which(train_[i,]<mean_[i])]=-1\n",
        "\ttrain_[i,which(train_[i,]>=mean_[i])]=1\n",
        "}\n",
        "\n",
        "train_[,1]=train[,1]\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "58b20ff3-ac54-8387-7907-768a5bf2515d"
      },
      "source": [
        "To visualize, we created the following image plot (similar to that in the Minimum Distance Classifier kernel https://www.kaggle.com/olhacher/digit-recognizer/minimum-distance-classifier) but using the binarized train data instead of the original train data. \n",
        "\n",
        "*Note: We need perform the binarization only for the images that would be plot below since we could not upload the offline ran binarized train data.*"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "4871f9d4-ced6-50ec-157a-2d441d1eb5df"
      },
      "outputs": [],
      "source": [
        "train <- read.csv(\"../input/train.csv\")\n",
        "\n",
        "set.seed(71)\n",
        "data <- sample(as.integer(row.names(train[train$label==1,])),100)\n",
        "#binarization only for a subset to be plot later\n",
        "mean_=apply(train,1,mean)\n",
        "train__=train\n",
        "for(i in data)\n",
        "{\n",
        "\ttrain__[i,which(train__[i,]<mean_[i])]=-1\n",
        "\ttrain__[i,which(train__[i,]>=mean_[i])]=1\n",
        "}\n",
        "#end of binarization step\n",
        "par(mfrow=c(10,10),mar=c(0.1,0.1,0.1,0.1))\n",
        "\n",
        "for (k in data)\n",
        "{\n",
        "    row <- NULL\n",
        "    for (n in 2:785)\n",
        "        row[n-1] <- train__[k,n]\n",
        "    \n",
        "    matrix1 <- matrix(row,28,28,byrow=FALSE)\n",
        "    matrix2 <- matrix(rep(0,784),28,28)\n",
        "    \n",
        "    for (i in 1:28)\n",
        "        for (j in 1:28)\n",
        "            matrix2[i,28-j+1] <- matrix1[i,j]\n",
        "    if (k==26611)\n",
        "        image(matrix2, axes=FALSE, col=heat.colors(12))\n",
        "    else\n",
        "        image(matrix2, axes=FALSE, col=topo.colors(12))\n",
        "}\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "3f1cb552-9cd5-883c-5c37-ce739d79f375"
      },
      "source": [
        "For completness, the following is the image plot using the unbinarized original train data. Visually, not a drastic difference. Next we will see if the prediction accuracy varies. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "364ea4a6-04d8-fc1b-8e3d-0d65bcb09fb0"
      },
      "outputs": [],
      "source": [
        "par(mfrow=c(10,10),mar=c(0.1,0.1,0.1,0.1))\n",
        "\n",
        "\n",
        "for (k in data)\n",
        "{\n",
        "    row <- NULL\n",
        "    for (n in 2:785)\n",
        "        row[n-1] <- train[k,n]\n",
        "    \n",
        "    matrix1 <- matrix(row,28,28,byrow=FALSE)\n",
        "    matrix2 <- matrix(rep(0,784),28,28)\n",
        "    \n",
        "    for (i in 1:28)\n",
        "        for (j in 1:28)\n",
        "            matrix2[i,28-j+1] <- matrix1[i,j]\n",
        "    if (k==26611)\n",
        "        image(matrix2, axes=FALSE, col=heat.colors(12))\n",
        "    else\n",
        "        image(matrix2, axes=FALSE, col=topo.colors(12))\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "30481bcf-ddbb-36a2-60f3-c68f51667efb"
      },
      "source": [
        "#Acquiring Prediction Accuracies\n",
        "Below is the code snippet that we ran for both the binarized and unbinarized train data (similar to that from the Minimum Distance Classifier kernel https://www.kaggle.com/olhacher/digit-recognizer/minimum-distance-classifier) to acquire the prediction accuracies for comparison:"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "12af508a-8a25-a58f-f6d2-594881f45595"
      },
      "source": [
        "set.seed(25)\n",
        "intest <- sample(1:42000,10000)\n",
        "X_train <- train[-intest,-1]\n",
        "Y_train <- train[-intest,1]\n",
        "X_test <- train[intest,-1]\n",
        "Y_test <- train[intest,1]\n",
        "\n",
        "table(Y_train)\n",
        "table(Y_test)\n",
        "\n",
        "raw_train_set <- train[-intest,]\n",
        "final_train_set <- NULL\n",
        "\n",
        "\n",
        "for (i in 0:9)\n",
        "{\n",
        "\t\n",
        "    digit <- raw_train_set[raw_train_set$label==i,-1]\n",
        "    set.seed(222)\n",
        "    cluster <- kmeans(x = digit,centers = 25, iter.max = 20)\n",
        "    new_data <- cbind(rep(i,25),cluster$centers)\n",
        "    final_train_set<- rbind(final_train_set,new_data)\n",
        "}\n",
        "\n",
        "final_train_set<-as.data.frame(final_train_set)\n",
        "\n",
        "X_train <- final_train_set[,-1]\n",
        "Y_train <- final_train_set[,1]\n",
        "table (Y_train)\n",
        "\n",
        "rm(digit,cluster,new_data,i,raw_train_set,final_train_set)\n",
        "\n",
        "distances <- NULL\n",
        "X_train <- as.matrix(X_train)\n",
        "X_test <- as.matrix(X_test)\n",
        "m <- dim(X_train)[1]\n",
        "n <- dim(X_test)[1]\n",
        "\n",
        "for (j in 1:n)\n",
        "{\n",
        "    dist <- rowSums((X_train - t(replicate(m, X_test[j,])))^2)\n",
        "    distances<-cbind(distances,dist)\n",
        "}\n",
        "distances <- (t(distances))\n",
        "\n",
        "rows<-NULL\n",
        "for (i in 1:n)\n",
        "    rows <- c(rows, which.min(distances[i,])[[1]])\n",
        "\n",
        "predictions <- data.frame(predicted = Y_train[rows], actual = Y_test, cluster = rows)\n",
        "rm(dist,j,m,n,i,rows)\n",
        "\n",
        "accuracy <- function (pred,actual)\n",
        "{\n",
        "    conf_matrix <- table(predictions = pred, actual = actual)\n",
        "    sum <- 0\n",
        "    for (j in 1:10)\n",
        "        for (i in 1:10)\n",
        "            if (j == i)\n",
        "                sum<-sum+conf_matrix[i,j]\n",
        "    return(list(conf_matrix,sum/length(pred)))\n",
        "}\n",
        "\n",
        "print(accuracy(predictions$predicted,predictions$actual)[[2]])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "f5718a94-ba60-a87d-0111-77d298e2bc13"
      },
      "source": [
        "#Conclusion\n",
        "We did find one difference, **the prediction accuracy improved from 0.9369 to 0.9453 when the binarized train data was used.** Hence it was worthwhile to reduce the complexity of the data by binarizing the values. The time taken for the above code snippet (the k-means clustering to further reduce the train data followed by prediction) should be faster using the binarized data although I did not specifically compute the time to compare. However, there is an initial overhead for preprocessing, that is, to binarize the data which should be taken into consideration."
      ]
    }
  ],
  "metadata": {
    "_change_revision": 0,
    "_is_fork": false,
    "kernelspec": {
      "display_name": "R",
      "language": "R",
      "name": "ir"
    },
    "language_info": {
      "codemirror_mode": "r",
      "file_extension": ".r",
      "mimetype": "text/x-r-source",
      "name": "R",
      "pygments_lexer": "r",
      "version": "3.3.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}