{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"from PIL import Image, ImageDraw, ImageFont\nfrom os import listdir\nimport os\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nimport torch.utils.data as data","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"markdown","source":"To display the full range of Japanese characters,I use Noto Sans, an open source font by Google which can display very almost all the characters used within this competition.\nThis is the url \"https://www.google.com/get/noto/#sans-jpan\"."},{"metadata":{"trusted":true},"cell_type":"code","source":"fontsize = 50\n\nfont = ImageFont.truetype('../input/font-data/NotoSansCJKjp-Regular.otf', fontsize, encoding='utf-8')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Visualising the training data"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = pd.read_csv('../input/kuzushiji-recognition/train.csv')\nunicode_map = {codepoint: char for codepoint, char in pd.read_csv('../input/kuzushiji-recognition/unicode_translation.csv').values}\nunicode_count = {codepoint: 0 for codepoint, _ in pd.read_csv('../input/kuzushiji-recognition/unicode_translation.csv').values}\nbox_hw_count = unicode_count.copy()\nbox_categorize = unicode_count.copy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# make label for prediction.\nunicode_label = {count:codeprint for count,(codeprint,_) in enumerate(unicode_map.items())}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# This function takes in a filename of an image, and the labels in the string format given in train.csv, and returns an image containing the bounding boxes and characters annotated\ndef visualize_training_data(image_fn, labels):\n    # Convert annotation string to array\n    labels = np.array(labels.split(' ')).reshape(-1, 5)\n    \n    # Read image\n    imsource = Image.open(image_fn).convert('RGBA')\n    bbox_canvas = Image.new('RGBA', imsource.size)\n    char_canvas = Image.new('RGBA', imsource.size)\n    bbox_draw = ImageDraw.Draw(bbox_canvas) # Separate canvases for boxes and chars so a box doesn't cut off a character\n    char_draw = ImageDraw.Draw(char_canvas)\n\n    for codepoint, x, y, w, h in labels:\n        x, y, w, h = int(x), int(y), int(w), int(h)\n        char = unicode_map[codepoint] # Convert codepoint to actual unicode character\n\n        # Draw bounding box around character, and unicode character next to it\n        bbox_draw.rectangle((x, y, x+w, y+h), fill=(255, 255, 255, 0), outline=(255, 0, 0, 255))\n        char_draw.text((x + w + fontsize/4, y + h/2 - fontsize), char, fill=(0, 0, 255, 255), font=font)\n\n    imsource = Image.alpha_composite(Image.alpha_composite(imsource, bbox_canvas), char_canvas)\n    imsource = imsource.convert(\"RGB\") # Remove alpha for saving in jpg format.\n    return np.asarray(imsource)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.random.seed(1337)\n\nfor i in range(2):\n    img, labels = df_train.values[np.random.randint(len(df_train))]\n    viz = visualize_training_data('../input/kuzushiji-recognition/train_images/{}.jpg'.format(img), labels)\n    \n    plt.figure(figsize=(15, 15))\n    plt.title(img)\n    plt.imshow(viz, interpolation='lanczos')\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Feature Engineering"},{"metadata":{},"cell_type":"markdown","source":"### 1. character  information\nTo know about characters, I will serch how many times the character is appeared,and number of character types."},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(len(df_train)):\n    img, labels = df_train.values[i]\n    if type(labels) == float:\n        continue\n    # Convert annotation string to array\n    labels = np.array(labels.split(' ')).reshape(-1, 5)\n    \n    for codepoint, x, y, w, h in labels:\n        unicode_count[codepoint] += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"unicode_count_df = pd.io.json.json_normalize(unicode_count)\nunicode_count_dict ={\n    \"Unicode\": unicode_count_df.columns.tolist(),\n    \"char\":list(unicode_map.values()),\n    \"count\": list(unicode_count_df.values[0])\n}\nunicode_count_df = pd.DataFrame(unicode_count_dict)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"characters_sorted_by_count = unicode_count_df.query('count > 0').sort_values('count', ascending=False)\ncharacters_sorted_by_count","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"characters_categorize = pd.DataFrame(\n    {\n        'number of appearances':['0','1~10','11~50','51~100','101~500','501~1000','1001~5,000','5,001~10,000','10,001~','1~','0~'],\n        'count':[len(unicode_count_df.query('count==0')),\n                 len(unicode_count_df.query('1<=count<=10')),\n                 len(unicode_count_df.query('11<=count<=50')),\n                len(unicode_count_df.query('51<=count<=100')),\n                len(unicode_count_df.query('101<=count<=500')),\n                len(unicode_count_df.query('501<=count<=1000')),\n                len(unicode_count_df.query('1001<=count<=5000')),\n                len(unicode_count_df.query('5001<=count<=10000')),\n                len(unicode_count_df.query('10001<=count')),\n                len(unicode_count_df.query('1<=count')),\n                len(unicode_count_df),]\n    }\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"characters_categorize","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#  character list\nprint(unicode_count_df.query('count==0')[\"char\"].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(unicode_count_df.query('1<=count<=10')[\"char\"].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(unicode_count_df.query('11<=count<=50')[\"char\"].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(unicode_count_df.query('51<=count<=100')[\"char\"].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(unicode_count_df.query('101<=count<=500')[\"char\"].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(unicode_count_df.query('501<=count<=1000')[\"char\"].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(unicode_count_df.query('1001<=count<=5000')[\"char\"].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(unicode_count_df.query('5001<=count<=10000')[\"char\"].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(unicode_count_df.query('10001<=count')[\"char\"].tolist())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"### 2. bounding box  information\nAs bounding box information, I will categorize by boxes's shape."},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(len(df_train)):\n    img, labels = df_train.values[i]\n    if type(labels) == float:\n        continue\n    # Convert annotation string to array\n    labels = np.array(labels.split(' ')).reshape(-1, 5)\n    \n    for codepoint, x, y, w, h in labels:\n        if h < w:\n            box_hw_count[codepoint] += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"box_info_dict = unicode_count_dict.copy()\nbox_info_dict[\"h<w\"] = [box_hw_count[codeprint] for codeprint in unicode_count_dict[\"Unicode\"]]\n\nbox_info = pd.DataFrame(box_info_dict)\n\nbox_info","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"box_rate =  box_info['h<w'] / box_info['count']\nbox_info = pd.concat([box_info,box_rate],axis=1)\nbox_info.columns = ['Unicode','char','count','h<w','rate']\nbox_info","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"I will categorize with boundingbox form.\ncategory 0 means NaN, 1 means h<w rate is more 99%, 2 means h<w rate is　1~99% , 3 means  h<w  rate is less than 1%."},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(len(box_info)):\n    if box_info.iat[i,4] >= 0.90:\n        box_categorize[box_info.iat[i,0]] = 1\n    elif box_info.iat[i,4] <= 0.10:\n        box_categorize[box_info.iat[i,0]] = 3\n    elif 0.10 < box_info.iat[i,4] < 0.90:\n        box_categorize[box_info.iat[i,0]] = 2\n    else :\n        box_categorize[box_info.iat[i,0]] = 0\n    \nbox_categorize_df = pd.DataFrame({'categorize':list(box_categorize.values())})\nbox_info = pd.concat([box_info,box_categorize_df],axis=1)\n\nbox_info","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Next, I will restrict characters by count."},{"metadata":{"trusted":true},"cell_type":"code","source":"box_info_restricted = box_info.query('count>100')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"box_categorize_distribution = pd.DataFrame({\n    'category':[0,1,2,3],\n    'count':[\n        len(box_info.query('categorize == 0')),\n        len(box_info.query('categorize == 1')),\n        len(box_info.query('categorize == 2')),\n        len(box_info.query('categorize == 3')),\n    ]\n})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"box_categorize_distribution","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"box_categorize_distribution_ristricted = pd.DataFrame({\n    'category':[0,1,2,3,4],\n    'count':[\n        len(box_info_restricted.query('categorize == 0')),\n        len(box_info_restricted.query('categorize == 1')),\n        len(box_info_restricted.query('categorize == 2')),\n        len(box_info_restricted.query('categorize == 3')),\n        len(box_info_restricted.query('categorize == 4')),\n    ]\n})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"box_categorize_distribution_ristricted","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"box_info_restricted.query('categorize == 1')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"box_info_restricted.query('categorize == 2')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"box_info_restricted.query('categorize == 3')","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":1}