|
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930 |
- {
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {
- "scrolled": true
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "{'O', 'C'}\n",
- "{'O', 'C'}\n",
- "--- shortest path kernel built in 0.0002582073211669922 seconds ---\n",
- "3\n"
- ]
- },
- {
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX8AAAD8CAYAAACfF6SlAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzt3Xt4VPW97/H3l3soGlFiK6KgPlxqBaQNeANESIrgpWAVQa2gaATC3uo+9qlusFq794Huavc5rUJBRPBOBQWsoCSAiBQ8CaLcrIJsQZS7GBUSDOF3/lgz4xAmmUBmZs3l83qePMys9VtrvqzAZ61Zl9/PnHOIiEhmaeB3ASIikngKfxGRDKTwFxHJQAp/EZEMpPAXEclACn8RkQyk8BcRyUAKfxGRDKTwFxHJQI38LqAmrVq1cu3atfO7DBGRlLJ69eq9zrmcaO2SNvzbtWtHaWmp32WIiKQUM9tal3Y67SMikoEU/iIiGUjhLyKSgRT+IiIZSOEvIpKBFP4iIhlI4S8ikoEU/iIiGSgmD3mZ2ZXA/wUaAtOccxMjtBkCPAw44APn3E2x+OyUt3s3zJgBa9dCWRlkZ0OXLnDbbZAT9SE9EZETYvUdwN3MGgIfA/nAdqAEGOac2xjWpj3wN6Cvc26/mZ3unNtd23pzc3NdWj/hW1ICEybAwoXe+4qK7+dlZYFzMGAAPPAAdO/uT40iknLMbLVzLjdau1ic9ukBbHbObXHOfQe8BPyiWps7gSecc/sBogV/2ps8Gfr0gblzvdAPD36A8nJv2ty5XrvJk/2oUkTSWCzC/0zgs7D32wPTwnUAOpjZCjNbFThNdAwzKzCzUjMr3bNnTwxKS0KTJ8N998HBg97RfW2c89rdd592ACISU4m64NsIaA/0AYYBT5rZKdUbOeemOudynXO5Oel4vruk5PvgD/M4kAs0BUZEWi64A0jn02AiklCxCP/PgbPC3rcJTAu3HZjvnKt0zv0P3jWC9jH47NQyYYJ3Sqea1sB44Pbali0v95YXEYmBWIR/CdDezM4xsybAUGB+tTZz8Y76MbNWeKeBtsTgs1PH7t3exd0Ip3quAwYBp9W2vHOwYAGk6+kwEUmoeoe/c+4wMBZ4E/gQ+JtzboOZPWJm1waavQnsM7ONwFLg1865ffX97JQyY0b912EWm/WISMaLyX3+zrkFwIJq034b9toB/xb4yUxr1x57V8/xKi+HdetiU4+IZDQ94ZsoZWWxWc/+/bFZj4hkNIV/omRnx2Y9LVvGZj0iktEU/onSpQs0axZx1mGgAqgK/FQEph0jKws6d45XhSKSQRT+iTJiRI2z/gPIAiYCzwVe/0ekhs7Vuh4RkbpS+CfK6ad7ffWYHTPrYbze7sJ/Hq7eyAwGDlRnbyISEwr/RHrgAe/UzYnIyvKWFxGJAYV/InXvDo8+Cs2bH99yzZt7y+VG7ahPRKROYnKfvxyH0aO9P++7z7tvv5bO3ZwZlpXlBX9wORGRGNCRvx9Gj4Zly2DwYO8OoOqngrKyOGTGjosu8top+EUkxnTk75fcXJgzx+urZ8YM78nd/fu9+/g7d2Ze8+Y8NX8+b+pUj4jEQb1H8oqXtB/JK4qKigratm3L8uXL6dChg9/liEiKSORIXhIHzZo1Y+TIkUyaNMnvUkQkDSn8k9ioUaN49tln+fbbb/0uRUTSjMI/iZ199tn06tWL559/3u9SRCTNKPyT3NixY3niiSdI1mszIpKaFP5Jrl+/fnz33Xe88847fpciImlE4Z/kzIwxY8bw+OOP+12KiKQRhX8KGD58OIsWLWLHjh1+lyIiaULhnwKys7MZOnQoU6dO9bsUEUkTCv8UUVhYyNSpU6msrPS7FBFJAwr/FHHBBRfQvn17Xn31Vb9LEZE0oPBPIYWFhTzxxBN+lyEiaUDhn0IGDRrE5s2bWbdund+liEiKU/inkMaNG1NQUKCjfxGpN4V/iikoKGDWrFmUlZX5XYqIpDCFf4o544wz6N+/PzNnzvS7FBFJYQr/FBS88HvkyBG/SxGRFKXwT0E9e/akWbNmLF682O9SRCRFKfxTkJnptk8RqReFf4q6+eabWb58OVu3bvW7FBFJQQr/FPWDH/yAW2+9lb/+9a9+lyIiKUjhn8LGjBnD9OnTqaio8LsUEUkxMQl/M7vSzD4ys81mdn8t7X5pZs7Moo4sL9G1b9+eCy+8kJdfftnvUkQkxdQ7/M2sIfAEMAA4HxhmZudHaHcScDfwbn0/U743duxYDfQiIsctFkf+PYDNzrktzrnvgJeAX0Ro93vgD4DOUcTQwIED2bVrF6WlpX6XIiIpJBbhfybwWdj77YFpIWb2U+As59zrta3IzArMrNTMSvfs2ROD0tJfw4YNGT16tG77FJHjEvcLvmbWAPgT8L+itXXOTXXO5TrncnNycuJdWtoYOXIkr776Knv37vW7FBFJEbEI/8+Bs8LetwlMCzoJuAB4y8w+BS4G5uuib+y0atWKQYMGMX36dL9LEZEUEYvwLwHam9k5ZtYEGArMD850zpU551o559o559oBq4BrnXM6SR1DhYWFTJ48maqqKr9LEZEUUO/wd84dBsYCbwIfAn9zzm0ws0fM7Nr6rl/qpnv37uTk5LBgwQK/SxGRFGDOOb9riCg3N9fpDpbj88wzz/DCCy/wxhtv+F2KiPjEzFY756KeVtcTvmlkyJAhvPfee2zatMnvUkQkySn800izZs24/fbbmTx5st+liEiSU/inmVGjRjFz5kwOHDjgdykiksQU/mmmXbt29OzZkxdeeMHvUkQkiSn801BwoJdkvZgvIv5T+KehvLw8Dh48yIoVK/wuRUSSlMI/DTVo0EDDPIpIrRT+aWr48OG88cYb7Nixw+9SRCQJKfzT1CmnnMKQIUN48skn/S5FRJKQwj+NFRYWMnXqVCorK/0uRUSSjMI/jXXp0oVzzz2XefPm+V2KiCQZhX+a04VfEYlE4Z/mBg8ezEcffcT69ev9LkVEkojCP801adKEgoICJk2a5HcpIpJEFP4ZoKCggJdeeomysjK/SxGRJKHwzwCtW7cmLy+PZ555xu9SRCRJKPwzxNixY5k0aZL6+xERQOGfMXr16kWjRo1YsmSJ36WISBJQ+GcIM6OwsJDHH3/c71JEJAko/DPILbfcwttvv822bdv8LkVEfKbwzyAtWrTglltuYcqUKX6XIiI+U/hnmDFjxjBt2jQOHTrkdyki4iOFf4bp2LEjXbt25eWXX/a7FBHxkcI/A6m/HxFR+Gegq6++mi+++ILVq1f7XYqI+EThn4EaNmzI6NGjdfQvksEU/hlq5MiRvPrqq+zbt8/vUkTEBwr/DJWTk8M111zD008/7XcpIuIDhX8GKywsZNKkSVRVVfldiogkmMI/g/Xo0YPTTjuNN954w+9SRCTBFP4ZLNjfjy78imSemIS/mV1pZh+Z2WYzuz/C/H8zs41mttbMFptZ21h8rtTfjTfeSElJCZs3b/a7FBFJoHqHv5k1BJ4ABgDnA8PM7PxqzdYAuc65LsBs4L/q+7kSG1lZWdx+++1MnjzZ71JEJIFiceTfA9jsnNvinPsOeAn4RXgD59xS59zBwNtVQJsYfK7EyKhRo5g5cyYHDx6M3lhE0kIswv9M4LOw99sD02oyElgYg8+VGDnnnHO45JJLePHFF/0uRUQSJKEXfM3sFiAX+GMN8wvMrNTMSvfs2ZPI0jLe2LFjefzxxzXMo0iGiEX4fw6cFfa+TWDaUcwsDxgHXOuci9ifsHNuqnMu1zmXm5OTE4PSpK7y8/P59ttvWblypd+liEgCxCL8S4D2ZnaOmTUBhgLzwxuYWTdgCl7w747BZ0qMNWjQgDFjxui2T5EMUe/wd84dBsYCbwIfAn9zzm0ws0fM7NpAsz8CLYCXzex9M5tfw+rERyNGjGDBggXs2rXL71JEJM4sWc/x5ubmutLSUr/LyDgFBQWcffbZjB8/3u9SROQEmNlq51xutHZ6wleOUlhYyJQpUzh8+LDfpYhIHCn85Shdu3albdu2zJs3z+9SRCSOFP5yjLFjx+rCr0iaU/jLMa677jo+/PBDNm7c6HcpIhInCn85RpMmTbjzzjuZNGmS36WISJwo/CWiu+66ixdeeIGvv/7a71JEJA4U/hLRmWeeSb9+/Xj22Wf9LkVE4kDhLzUKDvSSrM+CiMiJU/hLjS6//HIaNGjA0qVL/S5FRGJM4S810jCPIulL4S+1uuWWW1i6dCmfffZZ9MYikjIU/lKrk046iZtvvpkpU6b4XYqIxJDCX6IqLCxk2rRpHDoUcRgGEUlBCn+JqlOnTlxwwQXMmTPH71JEJEYU/lInuvArkl4U/lIn11xzDZ999hlr1qzxuxQRiQGFv9RJo0aNGDVqlI7+RdKERvKSOtu9ezcdO3Zky6pVtJw3D9auhbIyyM6GLl3gttsgJ8fvMkUyWl1H8mqUiGIkPZy+dSuLWrTgpAsugEaNoKLi+5mvvAIPPQQDBsADD0D37v4VKiJR6bSP1M3kydCnD7mff06jw4ePDn6A8nJv2ty50KeP115EkpaO/CW6yZPhvvvg4EEsWlvn4OBBrz3A6NHxrk5EToCO/KV2JSWh4A93C3AGcDLQAZhWfbngDkDXbUSSksJfajdhgndKp5oHgE+Br4H5wHhgdfVG5eXe8iKSdBT+UrPdu2HhQu9UTjU/AZoGXlvg55PqjZyDBQtgz564likix0/hLzWbMaPW2WOA5kAnvFNAAyM1Mou6HhFJPIW/1Gzt2mPv6gkzCfgGWA5cx/ffBI5SXg7r1sWlPBE5cQp/qVlZWdQmDYGewHagxps79++PXU0iEhMKf6lZdnadmx4mwjn/gCPHsR4RSQyFv9SsSxdo1uyYybuBl4BvgSrgTeBFoF+EVZSb8dCcOQwePJgnnniCjz/+WAPCiyQBhb/UbMSIiJMN7xRPG6AlcB/wf4BrI7TNatqUfykt5YYbbqC0tJS+ffvSrl077rjjDmbNmsUe3Qkk4gt17Ca1u+46r8uGE/l3YgaDB0PYIDDOOf75z39SXFxMUVERy5Yt47zzziM/P5/8/Hx69uxJswjfNkSkburasZvCX2pXUkLlZZfRuLLy+Jdt3hyWLYPcmv8dVlZW8u6771JUVERxcTFr167l4osvDu0MunbtSoMG+oIqUld1Df+Y/K8ysyvN7CMz22xm90eY39TMZgXmv2tm7WLxuRJ/Excv5pGTT+ZIVtbxLdi8OTz6aK3BD9C4cWN69uzJ7373O1asWMH27dsZO3Ys27ZtY+jQofzoRz9i2LBhPPXUU2zbtq0efxMRCVfvI38zawh8DOTj3fFXAgxzzm0MazMG6OKcG2VmQ4HBzrkba1uvjvz95ZzjwQcfZM6cORQXF3Pm/PleXz3l5bWfAjKDrCwv+GPQqdu2bdtCp4gWL15My5YtQ98K+vTpQ7buJBI5SsJO+5jZJcDDzrn+gfcPADjnJoS1eTPQZqWZNQJ2Ajmulg9X+PvHOce9997LsmXLWLRoETnBAVpKS72+ehYs8EI+vM+frCxvpzBwoNeff5Qj/hNx5MgRPvjgg9DOYOXKlXTu3Dm0M7joooto3LhxzD9XJJUkMvyvB650zt0ReP8r4CLn3NiwNusDbbYH3n8SaLO3pvUq/P1RVVXFqFGjWL9+PQsXLuSUU045ttGePV6XDevWeQ9wtWwJnTt7dwclcCSv8vJyVqxYEbpe8Mknn9C7d2/y8vLIz8+nU6dOmEXthFokraTkSF5mVgAUAJx99tk+V5N5KisrGT58ODt37qSoqIgWLVpEbpiTA7/+dWKLiyArK4u8vDzy8vIA2Lt3L4sXL6aoqIjHHnuMqqqq0LeCfv368cMf/tDnikWSRywu+H4OnBX2vk1gWsQ2gdM+2cC+6ityzk11zuU653JzNBZsQlVUVHDDDTfw9ddf8/rrr9cc/EmsVatW3HjjjUybNo1PP/2UpUuX0r17d15++WU6depE165due+++3jzzTc5WG18ApFME4vTPo3wLvj2wwv5EuAm59yGsDaFQOewC77XOeeG1LZenfZJnAMHDjB48GCys7N5/vnnadKkid8lxdzhw4cpKSkJnSJas2YN3bt3D30z6NatGw0bNvS7TJF6S+h9/mY2EO8hz4bAdOfcf5rZI0Cpc26+mTUDngW6AV8CQ51zW2pbp8I/McrKyrj66qs577zzmDZtGo0aJdWZwLj55ptvWLZsWWhnsGvXLvr27Ru6XnDOOef4XaLICdFDXhLVvn37uPLKK+nRowd/+ctfMvphqs8//zx0F1FxcTEtWrQIfSu44ooraNmypd8litSJwl9qtXPnTvLz8xk4cCATJ07UXTFhnHOsW7cutDNYsWIFP/7xj0M7g0suuSQtT41JelD4S422bdtGXl4et956K+PGjVPwR3Ho0CH+8Y9/hL4V/POf/6Rnz56hncFPfvITbUNJGgp/iWjz5s3k5eVx9913c++99/pdTkr68ssvWbJkCUVFRRQVFVFRURG65TQvL4/WrVv7XaJkMIW/HGPDhg3079+f3/72txQUFPhdTtrYsmVLaEewZMkSWrduHfpW0Lt375S8bVZSl8JfjrJ69WquuuoqHnvsMW6++Wa/y0lbVVVVrF69OnSKqLS0lJ/+9KehnUFubq5uKZW4UvhLyIoVKxg8eDBTpkxh8ODBfpeTUQ4cOMDbb78d2hls376dK664InRL6XnnnRf/6wW7d3vdcaxd643LnJ3tjdJ2220J7Y5DEkPhLwAsXryYYcOG8eyzz9K/f3+/y8l4O3fuDN1FVFRURNOmTUPfCvr27ctpp50Wuw8rKfE64lu40HtfUfH9vGBHfAMGeB3xde8eu88VXyn8hddee42RI0cye/Zsevfu7Xc5Uo1zjo0bN4Z2BsuXL6d9+/ahncFll11G06ZNT2zlkyf70gW3+E/hn+FmzZrF3XffzWuvvUZ3HdWlhO+++45Vq1aFThGtX7+eSy+9NLQz6Ny5c90exAsG//H0XxQcfEc7gJSn8M9gTz/9NOPGjeONN96gS5cufpcjJ+irr75i6dKloVNEX3/9deh20vz8fNq0aXPsQiUl0KdPjcG/CegMXA88V31mHYbdlOSn8M9Qf/nLX/jjH/9IUVERHTt29LsciaFPP/30qFHNcnJyjhrV7KSTToLrroO5c2s81fNzoBxoS4TwN4PBg2HOnPj+RSSuFP4ZaOLEiTz55JMsXryYdu3a+V2OxNGRI0dYs2ZNaGfw7rvvcvmPf8yra9bQ+PDhiMu8BLwCnA9sJkL4AzRrBtu26S6gFJbQAdzFX845xo8fzzPPPMPy5csV/BmgQYMG/OxnP+M3v/lNqFfSx7p0qfGI/2vgt8Cfoq3YzLstVNJeZvTfm8aC4+2+/fbbLFu2DA2Ck5maN29Ox4oKqKqKOP9BYCTeSEu1Ki/3hueUtKfwT2FVVVXcddddbNy4kSVLlkQeb1cyR1lZxMnvA8XAmrquZ//+GBUkyUzhn6IqKyu59dZb2bVrF4sWLVL/MeI9uRvBW8CnQHBU7G+BKmAj8F6E9keys3U+OAPod5yCKioquP766/nmm29SdrxdiYMuXbwLttUUAJ/gfQN4HxgFXAW8GWEV5WY8/Mor3HDDDUydOpUtW2odcE9SmMI/xRw4cIBrr72Wpk2b8sorr5CVleV3SZIsRoyIOLk58KOwnxZAMyDS1aGspk0ZvWoV11xzDcuXL+eyyy7jvPPO46677mL27Nl8+eWXcSpeEk23eqaQTB1vV45DlPv8axXhPn/nHBs2bAg9dbx8+XI6duxIfn4+eXl59euCQuJC9/mnmX379tG/f38uvvhi/vznP2f0eLtSiyhP+NaqDk/4hndBUVRUxIYNG0JdUOTl5dGlSxf92/SZwj+NBMfbveqqq5gwYYKGDJTaJbBvn2AXFMGHzb766qujuqA466yzjrN4qS+Ff5oIjrc7fPhw/v3f/13BL3XjU6+eW7dupbi4OPRz6qmnhr4VXHHFFWTXcEeSxI7CPw1s2rSJ/Px87rnnHu655x6/y5FUU1rq9ee/YIEX8uXl388L9uc/cKDXn38cOnM7cuQIH3zwQehbwcqVK+ncuXPoW8FFF11EkyZNYv65mU7hn+LWr19P//79efjhh7nzzjv9LkdS2Z49XpcN69Z5D3C1bAmdO3t3ByXwifCKigpWrFgR2hls2rSJXr16hXYG559/vr7ZxoDCP4UFx9v905/+xE033eR3OSJxsXfv3qO6rD506FBoR9CvXz9at27td4kpSeGfooLj7U6dOpVBgwb5XY5IwnzyySehbwVLliyhdevWoZ1B7969vS6rJSqFfwoqLi7mpptu4rnnnuPnP/+53+WI+Kaqqor33nsv9HxBSUkJ3bp1C+0MunfvrudcaqDwTzHB8XbnzJlDr169/C5HJKkcOHCAd955J7Qz+PTTT+nTp0/oTqIOHTroekGAwj+FzJo1i3/913/l73//u8bbFamDXbt2sWTJktD1AjM76nrB6aef7neJvlH4p4jp06czfvx4jbcrcoKcc3z88cehbwVvvfUW7dq1C30r6NWrF82bN/e7zIRR+KeA4Hi7xcXFdOjQwe9yRNLC4cOHKSkpCX0rWLNmDT169AiNd9ytWzcaNmwYvwJ27/ZurV271htjITvb63H1ttsScmutwj/JTZgwgaeeeori4mINuygSR9988w3Lli0L3Um0c+dO+vbtGzpNdO6558bmg0pKvIfqFi703ldUfD8v+FDdgAHeQ3VxPL2bkPA3s1OBWUA7vPEihjjn9ldrcyEwGTgZbwyJ/3TOzYq27nQN/+B4u3PnzqWoqEj3Mosk2BdffBHaERQXF5OVlRU6RdS3b19OO+2041+pT91pRP6IxIT/fwFfOucmmtn9QEvn3G+qtekAOOfcJjNrDawGfuyc+6q2dadj+B85coR7772X5cuXs2jRIlq1auV3SSIZLdhldXBnEOyyOvit4NJLL6VZhAFyjpLAjvTqIlHh/xHQxzm3w8zOAN5yznWMsswHwPXOuU21tUu38K+qqqKgoIAPP/yQBQsWaLxdkSQU7LI6uDNYv349l156aWhncEyX1RG60D4EjMEbN/lL4DxgAjCg+ofVoQvtE5Go8P/KOXdK4LUB+4Pva2jfA5gJ/MQ5d6S2dadT+FdWVvKrX/2KPXv2MG/ePA27KJIivvrqK956663QKaL9+/fTr1+/0M7g7HvuOWbwnAPAH4EReOMmLwCGAevwzo+HRBg8JxZiFv5mVow3+lt144CZ4WFvZvudcy1rWM8ZeGNJD3fOraqhTQHekKOcffbZP9u6dWu0+pNeRUUFQ4YM4ciRI8yePTv6V0gRSVrbtm0LfSt4f9Ei3t+/n6Z1OIDuAjwE/LL6jGbNYNu2mN4FlFSnfczsZLzg/9/Oudl1WXc6HPkfOHCAQYMG0bJlS5577jl1XyuSRo784Q/w0EM0OHSo1na7gLbA+0Cn6jOzsuB3v4Nf/zpmddU1/Os73tp8YHjg9XBgXoRCmgCvAs/UNfjTQVlZGf3796dNmza8+OKLCn6RNNNg3bqowV8J3IwXjscEP3h3B61bF/vi6qC+4T8RyDezTUBe4D1mlmtm0wJthgC9gRFm9n7g58J6fm5S27t3L/369aNbt2489dRT8X2gRET8UVZW6+wjwK+AJsDjtTXcv7+2uXFTr27xnHP7gH4RppcCdwRePwc8V5/PSSU7duwgPz+fq6++WuPtiqSzWoakdMBIvFM+C4DGta2nZcTLpHFX3yN/CbN161Z69+7NsGHDFPwi6a5LF++CbQSjgQ+B14Cs2taRleWNquYDhX+MbNq0icsvv5zCwkLGjRun4BdJdyNGRJy8FZiCd4H3R0CLwM/zkRo7V+N64k3hHwPr16+nT58+jB8/XgOti2SK00/3+uqpdqDXFu+0TwXwbdjPzdWXN4OBAxM6jnI4hX89rV69mry8PB599FHuuOMOv8sRkUR64AHv1M2JyMrylveJwr8e3nnnHQYMGMCUKVMYNmyY3+WISKJ17+710XO84wUE+/aJcdcOx0ODYJ6g4Hi7zz//PPn5+X6XIyJ+CXbOliS9etaVjvxPwPz587npppuYM2eOgl9EvCBftszrq6dZs2NPBWVledMHD/ba+Rz8oCP/4/bSSy9xzz338Prrr2u8XRH5Xm6u10nbnj3eSF7r1nkPcLVs6d3OOWKEbxd3I1H4Q52HXZs+fToPPvggRUVFdPbp3lwRSXI5OTHtqydeMjv8axt27ZVX4KGHQsOu/XnlSh577DGWLl2q8XZFJOVlbvhHG3atvNz7c+5cKv/+d/ZkZ/N2aSlt27ZNbJ0iInGQmRd8w4ddi9altXM0rqzkdwcO0HbBgsTUJyISZ5kX/iUlEcfb/BIYDPwA7wm9F6ot1qC83FsuxccYEBGBTAz/CRO+P6UTphCv69VdeH1wjAY2VG9UXu4tLyKS4jIr/Hfv9i7uVjvVcwCYA/werwOmnsC1wLPVl3cOFizwbuUSEUlhmRX+M2ZEnPwx3pXv8Ht4uhLhyB+8J/RqWI+ISKrIrPBfu/bo2zkDvgVOrjYtG/gm0jp8HHZNRCRWMiv8axh2rQXwdbVpXwMn1bQen4ZdExGJlcwK/xqGXesAHAY2hU37APhJTevxadg1EZFYyazwr2HYtR8A1wG/xbv4uwKYhzf48jF8HHZNRCRWMiv8axkubRJQDpwODAMmU8ORv4/DromIxEpmhX8Nw64BnArMxTvy3wbcFGl5n4ddExGJlcwKf0jpYddERGIl88I/hYddExGJlczs1TNFh10TEYmVzDvyD0rBYddERGIlM4/8g1Js2DURkVjJ7PAPSpFh10REYiVzT/uIiGQwhb+ISAZS+IuIZCCFv4hIBqpX+JvZqWZWZGabAn/W2N2lmZ1sZtvN7PH6fKaIiNRffY/87wcWO+faA4sD72vye+Dten6eiIjEQH3D/xfAzMDrmcCgSI3M7GfAD4FF9fw8ERGJgfqG/w+dczsCr3fiBfxRzKwB8BhwX7SVmVmBmZWaWekeDZIuIhI3UR/yMrNi4EcRZo05U6GgAAAGFklEQVQLf+Occ2YWqZOcMcAC59x2i9CVcrV1TAWmBj53j5ltjVbfcWoF7I3xOmNNNdZfstcHqjEWkr0+8KfGtnVpFDX8nXN5Nc0zs11mdoZzboeZnQHsjtDsEqCXmY3BGy63iZl965yr7foAzrmY96tgZqXOuaTullM11l+y1weqMRaSvT5I7hrr273DfGA4MDHw57zqDZxzNwdfm9kIIDda8IuISHzV95z/RCDfzDYBeYH3mFmumU2rb3EiIhIf9Tryd87tA/pFmF4K3BFh+gxgRn0+s56m+vjZdaUa6y/Z6wPVGAvJXh8kcY3mahvIRERE0pK6dxARyUBpF/516XLCzK4ws/fDfirMbFBg3gwz+5+weRf6UWOgXVVYHfPDpp9jZu+a2WYzm2VmTRJdn5ldaGYrzWyDma01sxvD5sVtG5rZlWb2UeDvfsyNA2bWNLBNNge2UbuweQ8Epn9kZv1jVdMJ1PhvZrYxsN0Wm1nbsHkRf+cJrm9E4FbrYB13hM0bHvh3scnMhsejvjrW+N9h9X1sZl+FzUvENpxuZrvNbH0N883M/hyof62Z/TRsXkK2YVTOubT6Af4LuD/w+n7gD1Hanwp8CTQPvJ8BXJ8MNQLf1jD9b8DQwOu/AqMTXR/QAWgfeN0a2AGcEs9tCDQEPgHOBZoAHwDnV2szBvhr4PVQYFbg9fmB9k2BcwLraehTjVeE/XsbHayxtt95gusbATweYdlTgS2BP1sGXrf0o8Zq7f8FmJ6obRj4jN7AT4H1NcwfCCwEDLgYeDeR27AuP2l35E8du5wIcz2w0Dl3MK5VHe14awwxMwP6ArNPZPk6ilqfc+5j59ymwOsv8J7xiPeYlz2Azc65Lc6574CXArWGC699NtAvsM1+AbzknDvknPsfYHNgfQmv0Tm3NOzf2yqgTRzqOOH6atEfKHLOfemc2w8UAVcmQY3DgBfjUEeNnHNv4x001uQXwDPOswo4xbxnoRK1DaNKx/CP2uVENUM59h/Ofwa+qv23mTWNeYV1r7GZed1drAqelgJOA75yzh0OvN8OnOlTfQCYWQ+8I7RPwibHYxueCXwW9j7S3z3UJrCNyvC2WV2WTVSN4UbiHSEGRfqd+1HfLwO/v9lmdtZxLpuoGgmcMjsHWBI2Od7bsC5q+jskahtGlZJj+Fr9u5wIrucMoDPwZtjkB/ACrwnebVq/AR7xqca2zrnPzexcYImZrcMLs3qL8TZ8FhjunDsSmByTbZjuzOwWIBe4PGzyMb9z59wnkdcQN68BLzrnDpnZXXjfpPomuIa6GgrMds5VhU1Lhm2Y9FIy/F39u5wIGgK86pyrDFt38Ij3kJk9TR06pItXjc65zwN/bjGzt4BuwBy8r5CNAke2bYDP/ajPzE4GXgfGBb7aBtcdk20YwefAWWHvI/3dg222m1kjIBvYV8dlE1UjZpaHt6O93Dl3KDi9ht95LIMran3Oe34naBreNaDgsn2qLftWDGsLOp7f1VCgMHxCArZhXdT0d0jUNowqHU/7BLucgBq6nAhzzLnCQNgFz60PAiJezY93jWbWMni6xMxaAZcBG5131Wgp3rWKGpdPQH1NgFfxzmvOrjYvXtuwBGhv3t1OTfD+41e/myO89uuBJYFtNh8Yat7dQOcA7YH/F6O6jqtGM+sGTAGudc7tDpse8XfuQ31nhL29Fvgw8PpN4OeBOlsCP+fob80JqzFQZye8i6Yrw6YlYhvWxXzg1sBdPxcDZYGDokRtw+j8uMoczx+887uLgU1AMXBqYHouMC2sXTu8vXCDassvAdbhBdZzQAs/agQuDdTxQeDPkWHLn4sXXJuBl4GmPtR3C1AJvB/2c2G8tyHeXRQf4x3JjQtMewQvSAGaBbbJ5sA2Ojds2XGB5T4CBsTx32C0GouBXWHbbX6033mC65sAbAjUsRToFLbs7YFtuxm4za9tGHj/MDCx2nKJ2oYv4t3hVol33n4kMAoYFZhvwBOB+tfh9WmW0G0Y7UdP+IqIZKB0PO0jIiJRKPxFRDKQwl9EJAMp/EVEMpDCX0QkAyn8RUQykMJfRCQDKfxFRDLQ/wdyCo1UI9GkmAAAAABJRU5ErkJggg==\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f773eab40b8>"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[(0, {'label': 'C'}), (1, {'label': 'C'}), (2, {'label': 'C'}), (3, {'label': 'C'}), (4, {'label': 'O'})]\n",
- " -> \n"
- ]
- },
- {
- "data": {
- "image/png": "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efJkJkyYQMOGDRk5ciRXX301CcXHyxHxgZp9qrmzzjqLt956i7/+9a8MHTqUK6+8kk8++cTvsKq1jz76iBEjRpCSksKqVavIzs5mzZo1DB06VIlfqhwl/yrMzBg0aBCbNm2iU6dOpKWlcd999/HDDz/4HVq18eOPPzJnzhx69epF7969ad68ORs3bmTGjBl07dpVTTtSZSn5VwMJCQn89a9/Zd26dWzbto327dszY8YMdQ0Nw7fffssjjzxC27ZtefTRRxk2bBg7duzggQceIDk52e/wRMKm5F+NtGzZkunTp/PCCy/w+OOP0717d9auXet3WFXKunXruPHGGzn99NPZvHkzs2bNYsWKFfzud7+jTp06focnEjERSf5mdomZbTGzPDO7J8T6umb2YmD9+2aWEonjSmhF4wPdcMMN9O/fn2HDhrFr1y6/w4pZR44c4cUXX6Rbt24MGDCA008/nY8//pjJkydzzjnn+B2eSFSEnfzNrCYwAegLdAB+Z2bFn0K6EdjjnDsdeAJ4JNzjSulq1qzJjTfeyObNm2nUqBEdO3ZkzJgxHD582O/QYsZXX33FQw89REpKCk8//TR33nkn27dv59577+UUvdREqrlIXPl3AfKcc9udc4eBF4ABxeoMALID868AvUx3yipFUlISjz32GCtWrODtt9/mF7/4BfPnz/c7LN8451i5ciVDhgzhzDPP5IsvvmDRokW89dZbXH755dSqVcvvEEUqRSSSfwvgs6DlzwNlIes4544Ce4EmETi2lFO7du147bXXePLJJ7nrrrvo168fmzdv9jusSnPw4MGf3nk7ePBgOnfuzPbt23nmmWdITU31OzyRShdTN3zNbLiZrTGzNV9//bXf4VRLffv2JScnhz59+tC9e3fuvPNOvvvuO7/DiprPP/+cUaNG0bp1a2bMmMH999/Pxx9/zJ133kmjRo38Dk/EN5FI/l8ALYOWTwuUhaxjZrWAJODb4jtyzk1yzqU559LU5ho9derU4Y9//CMfffQR+/fvp3379jz77LPVZqgI5xzLly/nyiuvpFOnTnz//fcsX76cRYsW0b9/f70sRYTIJP/VwBlm1sbM6gDXAPOK1ZkHXB+YHwS86dQJ3XfNmjVj0qRJLFiwgClTppCWlsa//vUvv8OqsIKCAp599lnOPvtsbr75Znr27MmOHTsYO3Ys//Vf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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f773ca1cc88>"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[(0, {'label': 'CC'}), (1, {'label': 'CC'}), (2, {'label': 'CO'}), (3, {'label': 'CCCO'}), (4, {'label': 'OCC'})]\n",
- " -> \n"
- ]
- },
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f773c9a44e0>"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[(0, {'label': '0'}), (1, {'label': '0'}), (2, {'label': '3'}), (3, {'label': '1'}), (4, {'label': '2'})]\n"
- ]
- },
- {
- "data": {
- "image/png": "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mslLRKJeZmYm3bp1o27durzwwguUU1tASJrAXURiRtWqVXnjjTc4evQo7du355CGfCgyJX8RKRGSkpKYO3cuDRs2pGnTpuzZs8fvkEo0JX8RKTESEhJ4+umnuf/++2nWrBn//Oc//Q6pxFLyF5ES54EHHmDKlCl07tyZf/zjH36HUyIVKfmb2UVmtsLMdgZ+hhx+z8wuNLMvzOzZohxTRASga9euLF26lAceeICJEyf6HU6JU9Q7/6HAKudcPWBV4HMov8ebqlNEJCwaNmzIhg0bmDZtGgMHDuSHH37wO6QSo6jJvzswI/B+BtAjWCG9GU8+AAAKWklEQVQzawj8BFhexOOJiJylVq1arF+/nnfffZeePXvy3Xff+R1SiVDU5P8T59zewPuv8BL8WcysFPA0MLiIxxIRCapSpUosWbKElJQUWrVqxVdffeV3SFEvz+RvZivN7N0gr+45yznvabFgT4zdByx2zn2Rj2P1N7MtZrYlKysr37+EiEjZsmV58cUX6dq1K02aNOH999/3O6SolufwDs65tqHWmdk+M6vmnNtrZtXwJubJrQnQ3MzuAy4AyprZt865c9oHnHNTgangPeGb319CRATAzBg1ahR16tShdevWzJo1i9atW/sdVlQqarXPAuDOwPs7gddyF3DO3e6cu8w5Vxuv6mdmsMQvIhIud9xxB7NmzaJXr17MnDnT73CiUlGT/3ignZntBNoGPmNmqWY2vajBiYgUVuvWrVm9ejWjR49m7NixROs4Zn7RwG4iEtO++uorunbtytVXX83UqVMpW7as3yFFlAZ2ExEBLrnkEtasWcPhw4fp2LEjhw8f9jukqKDkLyIxr0KFCsybN4/69evTrFkzPvnkE79D8p2Sv4jEhYSEBCZNmkT//v1p1qwZ8V6trOQvInFl4MCBPPfcc3Ts2JGFCxf6HY5vNI2jiMSdHj16UL16dXr06MGnn37KAw884HdIxU53/iISl66//nrWr1/Pc889x6BBg+JuUDglfxGJW3Xq1GHDhg2888473HLLLRw9etTvkIqNkr+IxLWUlBSWLl1KhQoVaN26NZmZwUapiT1K/iIS98qVK8fMmTPp0KEDTZo04cMPP/Q7pIhTg6+ICN6gcI8++ih16tShZcuWzJ07lxYtWvgdVsTozl9EJIf09HReeuklbr75Zl566SW/w4kY3fmL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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f773c9957b8>"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[(0, {'label': 'C'}), (1, {'label': 'C'}), (2, {'label': 'C'}), (3, {'label': 'C'}), (4, {'label': 'C'}), (5, {'label': 'C'}), (6, {'label': 'O'})]\n",
- " -> \n"
- ]
- },
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f7788e0e390>"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[(0, {'label': 'CC'}), (1, {'label': 'CC'}), (2, {'label': 'CC'}), (3, {'label': 'CO'}), (4, {'label': 'CCCC'}), (5, {'label': 'CCCO'}), (6, {'label': 'OCC'})]\n",
- " -> \n"
- ]
- },
- {
- "data": {
- "image/png": "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\n",
- "text/plain": [
- "<matplotlib.figure.Figure at 0x7f773c95a5f8>"
- ]
- },
- "metadata": {},
- "output_type": "display_data"
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[(0, {'label': '0'}), (1, {'label': '0'}), (2, {'label': '0'}), (3, {'label': '3'}), (4, {'label': '4'}), (5, {'label': '1'}), (6, {'label': '2'})]\n",
- "--- shortest path kernel built in 0.00026607513427734375 seconds ---\n",
- "6\n"
- ]
- }
- ],
- "source": [
- "import sys\n",
- "import networkx as nx\n",
- "sys.path.insert(0, \"../\")\n",
- "from pygraph.utils.graphfiles import loadDataset\n",
- "from pygraph.kernels.spkernel import spkernel\n",
- "\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "\n",
- "def weisfeilerlehman_test(G):\n",
- " '''\n",
- " Weisfeiler-Lehman test of graph isomorphism.\n",
- " '''\n",
- "\n",
- " nx.draw_networkx(G)\n",
- " plt.show()\n",
- " nx.draw_networkx_labels(G, nx.spring_layout(G), labels = nx.get_node_attributes(G,'label'))\n",
- " print(G.nodes(data = True))\n",
- " \n",
- " set_multisets = []\n",
- " for node in G.nodes(data = True):\n",
- " # Multiset-label determination.\n",
- " multiset = [ G.node[neighbors]['label'] for neighbors in G[node[0]] ]\n",
- " # sorting each multiset\n",
- " multiset.sort()\n",
- " multiset = node[1]['label'] + ''.join(multiset) # concatenate to a string and add the prefix \n",
- " set_multisets.append(multiset)\n",
- " \n",
- " # label compression\n",
- "# set_multisets.sort() # this is unnecessary\n",
- " set_unique = list(set(set_multisets)) # set of unique multiset labels\n",
- " set_compressed = { value : str(set_unique.index(value)) for value in set_unique } # assign indices as the new labels\n",
- "# print(set_compressed)\n",
- "# print(set_multisets)\n",
- " \n",
- " # relabel nodes with multisets\n",
- " for node in G.nodes(data = True):\n",
- " node[1]['label'] = set_multisets[node[0]]\n",
- " print(' -> ')\n",
- " nx.draw_networkx(G)\n",
- " plt.show()\n",
- " print(G.nodes(data = True))\n",
- "\n",
- " \n",
- " # relabel nodes\n",
- " for node in G.nodes(data = True):\n",
- " node[1]['label'] = set_compressed[set_multisets[node[0]]]\n",
- " \n",
- " print(' -> ')\n",
- " nx.draw_networkx(G)\n",
- " plt.show()\n",
- " print(G.nodes(data = True))\n",
- "\n",
- "dataset, y = loadDataset(\"../../../../datasets/acyclic/Acyclic/dataset_bps.ds\")\n",
- "G1 = dataset[12]\n",
- "G2 = dataset[55]\n",
- "\n",
- "# init.\n",
- "kernel = 0 # init kernel\n",
- "num_nodes1 = G1.number_of_nodes()\n",
- "num_nodes2 = G2.number_of_nodes()\n",
- "\n",
- "# the first iteration.\n",
- "labelset1 = { G1.nodes(data = True)[i]['label'] for i in range(num_nodes1) }\n",
- "labelset2 = { G2.nodes(data = True)[i]['label'] for i in range(num_nodes2) }\n",
- "print(labelset1)\n",
- "print(labelset2)\n",
- "kernel += spkernel(G1, G2)\n",
- "print(kernel)\n",
- "\n",
- "\n",
- "\n",
- "for height in range(0, min(num_nodes1, num_nodes2)): #Q how to determine the upper bound of the height?\n",
- " if labelset1 != labelset2:\n",
- " break\n",
- " \n",
- " # Weisfeiler-Lehman test of graph isomorphism.\n",
- " weisfeilerlehman_test(G1)\n",
- " weisfeilerlehman_test(G2)\n",
- " \n",
- " # calculate kernel\n",
- " kernel += spkernel(G1, G2)\n",
- " \n",
- " # get label sets of both graphs\n",
- " labelset1 = { G1.nodes(data = True)[i]['label'] for i in range(num_nodes1) }\n",
- " labelset2 = { G2.nodes(data = True)[i]['label'] for i in range(num_nodes2) }\n",
- "# print(labelset1)\n",
- "# print(labelset2)\n",
- "\n",
- "print(kernel)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "{0: 'C', 1: 'C', 2: 'C', 3: 'C', 4: 'C', 5: 'O', 6: 'O'}\n",
- "{0: 'C', 1: 'C', 2: 'C', 3: 'C', 4: 'C', 5: 'C', 6: 'S', 7: 'S'}\n",
- "\n",
- " --- height = 0 --- \n",
- "\n",
- " --- for graph 0 --- \n",
- "\n",
- "labels_ori: ['C', 'C', 'C', 'C', 'C', 'O', 'O']\n",
- "num_of_each_label: {'C': 5, 'O': 2}\n",
- "num_of_labels: 2\n"
- ]
- },
- {
- "ename": "UnboundLocalError",
- "evalue": "local variable 'all_labels_ori' referenced before assignment",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mUnboundLocalError\u001b[0m Traceback (most recent call last)",
- "\u001b[0;32m<ipython-input-4-a65d6180cda5>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 328\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget_node_attributes\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mG2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'label'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 329\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 330\u001b[0;31m \u001b[0mweisfeilerlehmankernel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mG1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mG2\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheight\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 331\u001b[0m \u001b[0;31m# Kmatrix = weisfeilerlehmankernel(G1, G2)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m<ipython-input-4-a65d6180cda5>\u001b[0m in \u001b[0;36mweisfeilerlehmankernel\u001b[0;34m(height, base_kernel, *args)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[0margs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 79\u001b[0m \u001b[0;31m# print(args)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 80\u001b[0;31m \u001b[0mkernel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_wl_subtreekernel_do\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheight\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mheight\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbase_kernel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'subtree'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 81\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;31m# for WL edge kernel\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m<ipython-input-4-a65d6180cda5>\u001b[0m in \u001b[0;36m_wl_subtreekernel_do\u001b[0;34m(height, base_kernel, *args)\u001b[0m\n\u001b[1;32m 220\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'num_of_labels: %s'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mnum_of_labels\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 221\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 222\u001b[0;31m \u001b[0mall_labels_ori\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlabels_ori\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 223\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'all_labels_ori: %s'\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mall_labels_ori\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 224\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'all_labels_ori' referenced before assignment"
- ]
- }
- ],
- "source": [
- "# test of WL subtree kernel on many graphs\n",
- "\n",
- "import sys\n",
- "import pathlib\n",
- "from collections import Counter\n",
- "sys.path.insert(0, \"../\")\n",
- "\n",
- "import networkx as nx\n",
- "import numpy as np\n",
- "import time\n",
- "\n",
- "from pygraph.kernels.spkernel import spkernel\n",
- "from pygraph.kernels.pathKernel import pathkernel\n",
- "\n",
- "def weisfeilerlehmankernel(*args, height = 0, base_kernel = 'subtree'):\n",
- " \"\"\"Calculate Weisfeiler-Lehman kernels between graphs.\n",
- " \n",
- " Parameters\n",
- " ----------\n",
- " Gn : List of NetworkX graph\n",
- " List of graphs between which the kernels are calculated.\n",
- " /\n",
- " G1, G2 : NetworkX graphs\n",
- " 2 graphs between which the kernel is calculated.\n",
- " \n",
- " height : subtree height\n",
- " \n",
- " base_kernel : base kernel used in each iteration of WL kernel\n",
- " the default base kernel is subtree kernel\n",
- " \n",
- " Return\n",
- " ------\n",
- " Kmatrix/Kernel : Numpy matrix/int\n",
- " Kernel matrix, each element of which is the Weisfeiler-Lehman kernel between 2 praphs. / Weisfeiler-Lehman Kernel between 2 graphs.\n",
- " \n",
- " Notes\n",
- " -----\n",
- " This function now supports WL subtree kernel and WL shortest path kernel.\n",
- " \n",
- " References\n",
- " ----------\n",
- " [1] Shervashidze N, Schweitzer P, Leeuwen EJ, Mehlhorn K, Borgwardt KM. Weisfeiler-lehman graph kernels. Journal of Machine Learning Research. 2011;12(Sep):2539-61.\n",
- " \"\"\"\n",
- " if len(args) == 1: # for a list of graphs\n",
- "\n",
- "# print(args)\n",
- " start_time = time.time()\n",
- " \n",
- " # for WL subtree kernel\n",
- " if base_kernel == 'subtree': \n",
- " Kmatrix = _wl_subtreekernel_do(args[0], height = height, base_kernel = 'subtree')\n",
- " \n",
- " # for WL edge kernel\n",
- " elif base_kernel == 'edge':\n",
- " print('edge')\n",
- " \n",
- " # for WL shortest path kernel\n",
- " elif base_kernel == 'sp':\n",
- " Gn = args[0]\n",
- " Kmatrix = np.zeros((len(Gn), len(Gn)))\n",
- " \n",
- " for i in range(0, len(Gn)):\n",
- " for j in range(i, len(Gn)):\n",
- " Kmatrix[i][j] = _weisfeilerlehmankernel_do(Gn[i], Gn[j])\n",
- " Kmatrix[j][i] = Kmatrix[i][j]\n",
- "\n",
- " print(\"\\n --- Weisfeiler-Lehman %s kernel matrix of size %d built in %s seconds ---\" % (base_kernel, len(args[0]), (time.time() - start_time)))\n",
- " \n",
- " return Kmatrix\n",
- " \n",
- " else: # for only 2 graphs\n",
- " \n",
- " start_time = time.time()\n",
- " \n",
- " # for WL subtree kernel\n",
- " if base_kernel == 'subtree':\n",
- " \n",
- " args = [args[0], args[1]]\n",
- "# print(args)\n",
- " kernel = _wl_subtreekernel_do(args, height = height, base_kernel = 'subtree')\n",
- " \n",
- " # for WL edge kernel\n",
- " elif base_kernel == 'edge':\n",
- " print('edge')\n",
- " \n",
- " # for WL shortest path kernel\n",
- " elif base_kernel == 'sp':\n",
- " \n",
- "\n",
- " kernel = _pathkernel_do(args[0], args[1])\n",
- "\n",
- " print(\"\\n --- Weisfeiler-Lehman %s kernel built in %s seconds ---\" % (base_kernel, time.time() - start_time))\n",
- " \n",
- " return kernel\n",
- " \n",
- " \n",
- "def _weisfeilerlehmankernel_do(G1, G2):\n",
- " \"\"\"Calculate Weisfeiler-Lehman kernels between 2 graphs. This kernel use shortest path kernel to calculate kernel between two graphs in each iteration.\n",
- " \n",
- " Parameters\n",
- " ----------\n",
- " G1, G2 : NetworkX graphs\n",
- " 2 graphs between which the kernel is calculated.\n",
- " \n",
- " Return\n",
- " ------\n",
- " Kernel : int\n",
- " Weisfeiler-Lehman Kernel between 2 graphs.\n",
- " \"\"\"\n",
- " \n",
- " # init.\n",
- " kernel = 0 # init kernel\n",
- " num_nodes1 = G1.number_of_nodes()\n",
- " num_nodes2 = G2.number_of_nodes()\n",
- " height = 12 #min(num_nodes1, num_nodes2)) #Q how to determine the upper bound of the height?\n",
- " \n",
- " # the first iteration.\n",
- " labelset1 = { G1.nodes(data = True)[i]['label'] for i in range(num_nodes1) }\n",
- " labelset2 = { G2.nodes(data = True)[i]['label'] for i in range(num_nodes2) }\n",
- " kernel += pathkernel(G1, G2) # change your base kernel here (and one more below)\n",
- " \n",
- " for h in range(0, height):\n",
- "# if labelset1 != labelset2:\n",
- "# break\n",
- "\n",
- " # Weisfeiler-Lehman test of graph isomorphism.\n",
- " relabel(G1)\n",
- " relabel(G2)\n",
- "\n",
- " # calculate kernel\n",
- " kernel += pathkernel(G1, G2) # change your base kernel here (and one more before)\n",
- "\n",
- " # get label sets of both graphs\n",
- " labelset1 = { G1.nodes(data = True)[i]['label'] for i in range(num_nodes1) }\n",
- " labelset2 = { G2.nodes(data = True)[i]['label'] for i in range(num_nodes2) }\n",
- " \n",
- " return kernel\n",
- "\n",
- "\n",
- "def relabel(G):\n",
- " '''\n",
- " Relabel nodes in graph G in one iteration of the 1-dim. WL test of graph isomorphism.\n",
- " \n",
- " Parameters\n",
- " ----------\n",
- " G : NetworkX graph\n",
- " The graphs whose nodes are relabeled.\n",
- " '''\n",
- " \n",
- " # get the set of original labels\n",
- " labels_ori = list(nx.get_node_attributes(G, 'label').values())\n",
- " print(labels_ori)\n",
- " num_of_each_label = dict(Counter(labels_ori))\n",
- " print(num_of_each_label)\n",
- " num_of_labels = len(num_of_each_label)\n",
- " print(num_of_labels)\n",
- " \n",
- " set_multisets = []\n",
- " for node in G.nodes(data = True):\n",
- " # Multiset-label determination.\n",
- " multiset = [ G.node[neighbors]['label'] for neighbors in G[node[0]] ]\n",
- " # sorting each multiset\n",
- " multiset.sort()\n",
- " multiset = node[1]['label'] + ''.join(multiset) # concatenate to a string and add the prefix \n",
- " set_multisets.append(multiset)\n",
- " print(set_multisets)\n",
- " \n",
- " # label compression\n",
- "# set_multisets.sort() # this is unnecessary\n",
- " set_unique = list(set(set_multisets)) # set of unique multiset labels\n",
- " print(set_unique)\n",
- " set_compressed = { value : str(set_unique.index(value) + num_of_labels + 1) for value in set_unique } # assign new labels\n",
- " print(set_compressed)\n",
- " \n",
- " # relabel nodes\n",
- "# nx.relabel_nodes(G, set_compressed, copy = False)\n",
- " for node in G.nodes(data = True):\n",
- " node[1]['label'] = set_compressed[set_multisets[node[0]]]\n",
- " print(nx.get_node_attributes(G, 'label'))\n",
- "\n",
- " # get the set of compressed labels\n",
- " labels_comp = list(nx.get_node_attributes(G, 'label').values())\n",
- " print(labels_comp)\n",
- " num_of_each_label.update(dict(Counter(labels_comp)))\n",
- " print(num_of_each_label)\n",
- " \n",
- " \n",
- "def _wl_subtreekernel_do(*args, height = 0, base_kernel = 'subtree'):\n",
- " \"\"\"Calculate Weisfeiler-Lehman subtree kernels between graphs.\n",
- " \n",
- " Parameters\n",
- " ----------\n",
- " Gn : List of NetworkX graph\n",
- " List of graphs between which the kernels are calculated.\n",
- " \n",
- " Return\n",
- " ------\n",
- " Kmatrix/Kernel : Numpy matrix/int\n",
- " Kernel matrix, each element of which is the Weisfeiler-Lehman kernel between 2 praphs.\n",
- " \"\"\"\n",
- " \n",
- "# print(args)\n",
- " Gn = args[0]\n",
- "# print(Gn)\n",
- "\n",
- " Kmatrix = np.zeros((len(Gn), len(Gn)))\n",
- " all_num_of_labels_occured = 0 # number of the set of letters that occur before as node labels at least once in all graphs\n",
- " \n",
- " # initial for height = 0\n",
- " print('\\n --- height = 0 --- ')\n",
- " all_labels_ori = set() # all unique orignal labels in all graphs in this iteration\n",
- " all_num_of_each_label = [] # number of occurence of each label in each graph in this iteration\n",
- " all_set_compressed = {} # a dictionary mapping original labels to new ones in all graphs in this iteration\n",
- " num_of_labels_occured = all_num_of_labels_occured # number of the set of letters that occur before as node labels at least once in all graphs\n",
- "\n",
- " # for each graph\n",
- " for idx, G in enumerate(Gn):\n",
- " # get the set of original labels\n",
- " print('\\n --- for graph %d --- \\n' % (idx))\n",
- " labels_ori = list(nx.get_node_attributes(G, 'label').values())\n",
- " print('labels_ori: %s' % (labels_ori))\n",
- " num_of_each_label = dict(Counter(labels_ori)) # number of occurence of each label in graph\n",
- " print('num_of_each_label: %s' % (num_of_each_label))\n",
- " all_num_of_each_label.append(num_of_each_label)\n",
- " print('all_num_of_each_label: %s' % (all_num_of_each_label))\n",
- " num_of_labels = len(num_of_each_label) # number of all unique labels\n",
- " print('num_of_labels: %s' % (num_of_labels))\n",
- " \n",
- "\n",
- " all_labels_ori.update(labels_ori)\n",
- " print('all_labels_ori: %s' % (all_labels_ori))\n",
- " \n",
- " # calculate subtree kernel with the 0th iteration and add it to the final kernel\n",
- " for i in range(0, len(Gn)):\n",
- " for j in range(i, len(Gn)):\n",
- " labels = set(list(all_num_of_each_label[i].keys()) + list(all_num_of_each_label[j].keys()))\n",
- " print('\\n labels: %s' % (labels))\n",
- " vector1 = np.matrix([ (all_num_of_each_label[i][label] if (label in all_num_of_each_label[i].keys()) else 0) for label in labels ])\n",
- " vector2 = np.matrix([ (all_num_of_each_label[j][label] if (label in all_num_of_each_label[j].keys()) else 0) for label in labels ])\n",
- " print('\\n vector1: %s' % (vector1))\n",
- " print('\\n vector2: %s' % (vector2))\n",
- " Kmatrix[i][j] += np.dot(vector1, vector2.transpose())\n",
- " Kmatrix[j][i] = Kmatrix[i][j]\n",
- " \n",
- " \n",
- " \n",
- " # iterate each height\n",
- " for h in range(height + 1):\n",
- " print('\\n --- height = %d --- ' % (h))\n",
- " all_labels_ori = set() # all unique orignal labels in all graphs in this iteration\n",
- "# all_labels_comp = set() # all unique compressed labels in all graphs in this iteration\n",
- " all_num_of_each_label = [] # number of occurence of each label in each graph in this iteration\n",
- " all_set_compressed = {} # a dictionary mapping original labels to new ones in all graphs in this iteration\n",
- " num_of_labels_occured = all_num_of_labels_occured # number of the set of letters that occur before as node labels at least once in all graphs\n",
- " \n",
- " # for each graph\n",
- " for idx, G in enumerate(Gn):\n",
- " # get the set of original labels\n",
- " print('\\n --- for graph %d --- \\n' % (idx))\n",
- " labels_ori = list(nx.get_node_attributes(G, 'label').values())\n",
- " print('labels_ori: %s' % (labels_ori))\n",
- " num_of_each_label = dict(Counter(labels_ori)) # number of occurence of each label in graph\n",
- " print('num_of_each_label: %s' % (num_of_each_label))\n",
- " num_of_labels = len(num_of_each_label) # number of all unique labels\n",
- " print('num_of_labels: %s' % (num_of_labels))\n",
- " \n",
- " all_labels_ori.update(labels_ori)\n",
- " print('all_labels_ori: %s' % (all_labels_ori))\n",
- " # num_of_labels_occured += num_of_labels #@todo not precise\n",
- " num_of_labels_occured = all_num_of_labels_occured + len(all_labels_ori) + len(all_set_compressed)\n",
- " print('num_of_labels_occured: %s' % (num_of_labels_occured))\n",
- " \n",
- " set_multisets = []\n",
- " for node in G.nodes(data = True):\n",
- " # Multiset-label determination.\n",
- " multiset = [ G.node[neighbors]['label'] for neighbors in G[node[0]] ]\n",
- " # sorting each multiset\n",
- " multiset.sort()\n",
- " multiset = node[1]['label'] + ''.join(multiset) # concatenate to a string and add the prefix \n",
- " set_multisets.append(multiset)\n",
- " print('multiset: %s' % (set_multisets))\n",
- "\n",
- " # label compression\n",
- " # set_multisets.sort() # this is unnecessary\n",
- " set_unique = list(set(set_multisets)) # set of unique multiset labels\n",
- " print('set_unique: %s' % (set_unique))\n",
- " # a dictionary mapping original labels to new ones. \n",
- " set_compressed = {}\n",
- " # if a label occured before, assign its former compressed label, else assign the number of labels occured + 1 as the compressed label \n",
- " for value in set_unique:\n",
- " if value in all_set_compressed.keys():\n",
- " set_compressed.update({ value : all_set_compressed[value] })\n",
- " else:\n",
- " set_compressed.update({ value : str(num_of_labels_occured + 1) })\n",
- " num_of_labels_occured += 1\n",
- "# set_compressed = { value : (all_set_compressed[value] if value in all_set_compressed.keys() else str(set_unique.index(value) + num_of_labels_occured + 1)) for value in set_unique }\n",
- " print('set_compressed: %s' % (set_compressed))\n",
- " \n",
- " all_set_compressed.update(set_compressed)\n",
- " print('all_set_compressed: %s' % (all_set_compressed))\n",
- "# num_of_labels_occured += len(set_compressed) #@todo not precise\n",
- " print('num_of_labels_occured: %s' % (num_of_labels_occured))\n",
- " \n",
- "\n",
- " # relabel nodes\n",
- " # nx.relabel_nodes(G, set_compressed, copy = False)\n",
- " for node in G.nodes(data = True):\n",
- " node[1]['label'] = set_compressed[set_multisets[node[0]]]\n",
- " print('\\n compressed labels: %s' % (nx.get_node_attributes(G, 'label')))\n",
- "\n",
- " # get the set of compressed labels\n",
- " labels_comp = list(nx.get_node_attributes(G, 'label').values())\n",
- " print('labels_comp: %s' % (labels_comp))\n",
- " num_of_each_label.update(dict(Counter(labels_comp)))\n",
- " print('num_of_each_label: %s' % (num_of_each_label))\n",
- " all_num_of_each_label.append(num_of_each_label)\n",
- " print('all_num_of_each_label: %s' % (all_num_of_each_label))\n",
- " \n",
- " # calculate subtree kernel with h iterations and add it to the final kernel\n",
- " for i in range(0, len(Gn)):\n",
- " for j in range(i, len(Gn)):\n",
- " labels = set(list(all_num_of_each_label[i].keys()) + list(all_num_of_each_label[j].keys()))\n",
- " print('\\n labels: %s' % (labels))\n",
- " vector1 = np.matrix([ (all_num_of_each_label[i][label] if (label in all_num_of_each_label[i].keys()) else 0) for label in labels ])\n",
- " vector2 = np.matrix([ (all_num_of_each_label[j][label] if (label in all_num_of_each_label[j].keys()) else 0) for label in labels ])\n",
- " print('\\n vector1: %s' % (vector1))\n",
- " print('\\n vector2: %s' % (vector2))\n",
- " Kmatrix[i][j] += np.dot(vector1, vector2.transpose())\n",
- " Kmatrix[j][i] = Kmatrix[i][j]\n",
- " \n",
- " all_num_of_labels_occured += len(all_labels_ori)\n",
- " print('\\n all_num_of_labels_occured: %s' % (all_num_of_labels_occured))\n",
- " print('\\n Kmatrix: %s' % (Kmatrix))\n",
- "\n",
- " return Kmatrix\n",
- "\n",
- " \n",
- "# main\n",
- "import sys\n",
- "from collections import Counter\n",
- "import networkx as nx\n",
- "sys.path.insert(0, \"../\")\n",
- "from pygraph.utils.graphfiles import loadDataset\n",
- "from pygraph.kernels.spkernel import spkernel\n",
- "\n",
- "dataset, y = loadDataset(\"../../../../datasets/acyclic/Acyclic/dataset_bps.ds\")\n",
- "G1 = dataset[15]\n",
- "print(nx.get_node_attributes(G1, 'label'))\n",
- "G2 = dataset[80]\n",
- "print(nx.get_node_attributes(G2, 'label'))\n",
- "\n",
- "weisfeilerlehmankernel(G1, G2, height = 1)\n",
- "# Kmatrix = weisfeilerlehmankernel(G1, G2)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "- This script take as input a kernel matrix\n",
- "and returns the classification or regression performance\n",
- "- The kernel matrix can be calculated using any of the graph kernels approaches\n",
- "- The criteria used for prediction are SVM for classification and kernel Ridge regression for regression\n",
- "- For predition we divide the data in training, validation and test. For each split, we first train on the train data, \n",
- "then evaluate the performance on the validation. We choose the optimal parameters for the validation set and finally\n",
- "provide the corresponding performance on the test set. If more than one split is performed, the final results \n",
- "correspond to the average of the performances on the test sets. \n",
- "\n",
- "@references\n",
- " https://github.com/eghisu/GraphKernels/blob/master/GraphKernelsCollection/python_scripts/compute_perf_gk.py\n",
- "\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 0 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 0.49373626708984375 seconds ---\n",
- "[[ 10. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 16. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 10. ..., 22. 22. 24.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 130. 130. 122.]\n",
- " [ 20. 20. 22. ..., 130. 130. 122.]\n",
- " [ 20. 20. 24. ..., 122. 122. 154.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 12.761978\n",
- "With standard deviation: 10.086502\n",
- "\n",
- " Mean performance on test set: 9.014031\n",
- "With standard deviation: 6.357865\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 1 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 1.0043864250183105 seconds ---\n",
- "[[ 20. 14. 8. ..., 20. 20. 22.]\n",
- " [ 14. 32. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 20. ..., 25. 25. 30.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 188. 180. 145.]\n",
- " [ 20. 28. 25. ..., 180. 182. 145.]\n",
- " [ 22. 22. 30. ..., 145. 145. 238.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 22.747869\n",
- "With standard deviation: 7.561365\n",
- "\n",
- " Mean performance on test set: 19.457133\n",
- "With standard deviation: 5.057464\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 2 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 1.602942705154419 seconds ---\n",
- "[[ 30. 14. 8. ..., 20. 20. 23.]\n",
- " [ 14. 48. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 30. ..., 25. 25. 32.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 246. 209. 147.]\n",
- " [ 20. 28. 25. ..., 209. 220. 147.]\n",
- " [ 23. 22. 32. ..., 147. 147. 286.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 21.407092\n",
- "With standard deviation: 6.415967\n",
- "\n",
- " Mean performance on test set: 23.466810\n",
- "With standard deviation: 5.836831\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 3 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 2.2096023559570312 seconds ---\n",
- "[[ 40. 14. 8. ..., 20. 20. 23.]\n",
- " [ 14. 64. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 40. ..., 25. 25. 32.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 304. 217. 147.]\n",
- " [ 20. 28. 25. ..., 217. 250. 147.]\n",
- " [ 23. 22. 32. ..., 147. 147. 314.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 24.747018\n",
- "With standard deviation: 6.547340\n",
- "\n",
- " Mean performance on test set: 27.961360\n",
- "With standard deviation: 6.291821\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 4 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 2.7832393646240234 seconds ---\n",
- "[[ 50. 14. 8. ..., 20. 20. 23.]\n",
- " [ 14. 80. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 50. ..., 25. 25. 32.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 362. 217. 151.]\n",
- " [ 20. 28. 25. ..., 217. 280. 147.]\n",
- " [ 23. 22. 32. ..., 151. 147. 336.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 27.197367\n",
- "With standard deviation: 5.980185\n",
- "\n",
- " Mean performance on test set: 30.614531\n",
- "With standard deviation: 6.852841\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 5 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 3.276118040084839 seconds ---\n",
- "[[ 60. 14. 8. ..., 20. 20. 23.]\n",
- " [ 14. 96. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 60. ..., 25. 25. 32.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 420. 217. 151.]\n",
- " [ 20. 28. 25. ..., 217. 310. 147.]\n",
- " [ 23. 22. 32. ..., 151. 147. 358.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 29.010593\n",
- "With standard deviation: 6.073672\n",
- "\n",
- " Mean performance on test set: 32.130815\n",
- "With standard deviation: 7.062947\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 6 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 3.779860496520996 seconds ---\n",
- "[[ 70. 14. 8. ..., 20. 20. 23.]\n",
- " [ 14. 112. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 70. ..., 25. 25. 32.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 478. 217. 151.]\n",
- " [ 20. 28. 25. ..., 217. 340. 147.]\n",
- " [ 23. 22. 32. ..., 151. 147. 380.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 30.909632\n",
- "With standard deviation: 6.490001\n",
- "\n",
- " Mean performance on test set: 33.117974\n",
- "With standard deviation: 7.069399\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 7 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 4.446576833724976 seconds ---\n",
- "[[ 80. 14. 8. ..., 20. 20. 23.]\n",
- " [ 14. 128. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 80. ..., 25. 25. 32.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 536. 217. 151.]\n",
- " [ 20. 28. 25. ..., 217. 370. 147.]\n",
- " [ 23. 22. 32. ..., 151. 147. 402.]]\n",
- "\n",
- " Saving kernel matrix to file...\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- " Mean performance on val set: 31.870406\n",
- "With standard deviation: 6.522032\n",
- "\n",
- " Mean performance on test set: 33.964633\n",
- "With standard deviation: 7.270535\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 8 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 4.85552978515625 seconds ---\n",
- "[[ 90. 14. 8. ..., 20. 20. 23.]\n",
- " [ 14. 144. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 90. ..., 25. 25. 32.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 594. 217. 151.]\n",
- " [ 20. 28. 25. ..., 217. 400. 147.]\n",
- " [ 23. 22. 32. ..., 151. 147. 424.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 32.192715\n",
- "With standard deviation: 6.389616\n",
- "\n",
- " Mean performance on test set: 34.325288\n",
- "With standard deviation: 7.375800\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 9 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 5.650352239608765 seconds ---\n",
- "[[ 100. 14. 8. ..., 20. 20. 23.]\n",
- " [ 14. 160. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 100. ..., 25. 25. 32.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 652. 217. 151.]\n",
- " [ 20. 28. 25. ..., 217. 430. 147.]\n",
- " [ 23. 22. 32. ..., 151. 147. 446.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 32.842545\n",
- "With standard deviation: 6.213069\n",
- "\n",
- " Mean performance on test set: 34.675515\n",
- "With standard deviation: 7.314709\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 10 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 5.818731069564819 seconds ---\n",
- "[[ 110. 14. 8. ..., 20. 20. 23.]\n",
- " [ 14. 176. 4. ..., 28. 28. 22.]\n",
- " [ 8. 4. 110. ..., 25. 25. 32.]\n",
- " ..., \n",
- " [ 20. 28. 25. ..., 710. 217. 151.]\n",
- " [ 20. 28. 25. ..., 217. 460. 147.]\n",
- " [ 23. 22. 32. ..., 151. 147. 468.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 33.151974\n",
- "With standard deviation: 6.196320\n",
- "\n",
- " Mean performance on test set: 34.867215\n",
- "With standard deviation: 7.324672\n",
- "\n",
- "\n",
- " std height RMSE\n",
- "------- -------- --------\n",
- "6.35786 1 9.01403\n",
- "5.05746 2.1 19.4571\n",
- "5.83683 3.2 23.4668\n",
- "6.29182 4.3 27.9614\n",
- "6.85284 5.4 30.6145\n",
- "7.06295 6.5 32.1308\n",
- "7.0694 7.6 33.118\n",
- "7.27054 8.7 33.9646\n",
- "7.3758 9.8 34.3253\n",
- "7.31471 10.9 34.6755\n",
- "7.32467 12 34.8672\n"
- ]
- }
- ],
- "source": [
- "# Author: Elisabetta Ghisu\n",
- "# test of WL subtree kernel\n",
- "\n",
- "\"\"\"\n",
- "- This script take as input a kernel matrix\n",
- "and returns the classification or regression performance\n",
- "- The kernel matrix can be calculated using any of the graph kernels approaches\n",
- "- The criteria used for prediction are SVM for classification and kernel Ridge regression for regression\n",
- "- For predition we divide the data in training, validation and test. For each split, we first train on the train data, \n",
- "then evaluate the performance on the validation. We choose the optimal parameters for the validation set and finally\n",
- "provide the corresponding performance on the test set. If more than one split is performed, the final results \n",
- "correspond to the average of the performances on the test sets. \n",
- "\n",
- "@references\n",
- " https://github.com/eghisu/GraphKernels/blob/master/GraphKernelsCollection/python_scripts/compute_perf_gk.py\n",
- "\"\"\"\n",
- "\n",
- "print(__doc__)\n",
- "\n",
- "import sys\n",
- "import os\n",
- "import pathlib\n",
- "sys.path.insert(0, \"../\")\n",
- "from tabulate import tabulate\n",
- "\n",
- "import random\n",
- "import numpy as np\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "from sklearn.kernel_ridge import KernelRidge # 0.17\n",
- "from sklearn.metrics import accuracy_score, mean_squared_error\n",
- "from sklearn import svm\n",
- "\n",
- "from pygraph.kernels.weisfeilerLehmanKernel import weisfeilerlehmankernel\n",
- "from pygraph.utils.graphfiles import loadDataset\n",
- "\n",
- "val_means_height = []\n",
- "val_stds_height = []\n",
- "test_means_height = []\n",
- "test_stds_height = []\n",
- "\n",
- "\n",
- "for height in np.linspace(0, 10, 11):\n",
- " print('\\n --- calculating kernel matrix when subtree height = %d ---' % height)\n",
- "\n",
- " print('\\n Loading dataset from file...')\n",
- " dataset, y = loadDataset(\"../../../../datasets/acyclic/Acyclic/dataset_bps.ds\")\n",
- " y = np.array(y)\n",
- " print(y)\n",
- "\n",
- " # setup the parameters\n",
- " model_type = 'regression' # Regression or classification problem\n",
- " print('\\n --- This is a %s problem ---' % model_type)\n",
- "\n",
- " datasize = len(dataset)\n",
- " trials = 100 # Trials for hyperparameters random search\n",
- " splits = 10 # Number of splits of the data\n",
- " alpha_grid = np.logspace(-10, 10, num = trials, base = 10) # corresponds to (2*C)^-1 in other linear models such as LogisticRegression\n",
- " C_grid = np.logspace(-10, 10, num = trials, base = 10)\n",
- " random.seed(20) # Set the seed for uniform parameter distribution\n",
- "\n",
- " # set the output path\n",
- " kernel_file_path = 'kernelmatrices_weisfeilerlehman_subtree_acyclic/'\n",
- " if not os.path.exists(kernel_file_path):\n",
- " os.makedirs(kernel_file_path)\n",
- "\n",
- " \"\"\"\n",
- " - Here starts the main program\n",
- " - First we permute the data, then for each split we evaluate corresponding performances\n",
- " - In the end, the performances are averaged over the test sets\n",
- " \"\"\"\n",
- "\n",
- " # save kernel matrices to files / read kernel matrices from files\n",
- " kernel_file = kernel_file_path + 'km.ds'\n",
- " path = pathlib.Path(kernel_file)\n",
- " # get train set kernel matrix\n",
- " if path.is_file():\n",
- " print('\\n Loading the kernel matrix from file...')\n",
- " Kmatrix = np.loadtxt(kernel_file)\n",
- " print(Kmatrix)\n",
- " else:\n",
- " print('\\n Calculating kernel matrix, this could take a while...')\n",
- " Kmatrix = weisfeilerlehmankernel(dataset, height = int(height))\n",
- " print(Kmatrix)\n",
- " print('\\n Saving kernel matrix to file...')\n",
- " # np.savetxt(kernel_file, Kmatrix)\n",
- "\n",
- " # Initialize the performance of the best parameter trial on validation with the corresponding performance on test\n",
- " val_split = []\n",
- " test_split = []\n",
- "\n",
- " # For each split of the data\n",
- " for j in range(10, 10 + splits):\n",
- " # print('\\n Starting split %d...' % j)\n",
- "\n",
- " # Set the random set for data permutation\n",
- " random_state = int(j)\n",
- " np.random.seed(random_state)\n",
- " idx_perm = np.random.permutation(datasize)\n",
- " # print(idx_perm)\n",
- "\n",
- " # Permute the data\n",
- " y_perm = y[idx_perm] # targets permutation\n",
- " # print(y_perm)\n",
- " Kmatrix_perm = Kmatrix[:, idx_perm] # inputs permutation\n",
- " # print(Kmatrix_perm)\n",
- " Kmatrix_perm = Kmatrix_perm[idx_perm, :] # inputs permutation\n",
- "\n",
- " # Set the training, validation and test\n",
- " # Note: the percentage can be set up by the user\n",
- " num_train_val = int((datasize * 90) / 100) # 90% (of entire dataset) for training and validation\n",
- " num_test = datasize - num_train_val # 10% (of entire dataset) for test\n",
- " num_train = int((num_train_val * 90) / 100) # 90% (of train + val) for training\n",
- " num_val = num_train_val - num_train # 10% (of train + val) for validation\n",
- "\n",
- " # Split the kernel matrix\n",
- " Kmatrix_train = Kmatrix_perm[0:num_train, 0:num_train]\n",
- " Kmatrix_val = Kmatrix_perm[num_train:(num_train + num_val), 0:num_train]\n",
- " Kmatrix_test = Kmatrix_perm[(num_train + num_val):datasize, 0:num_train]\n",
- "\n",
- " # Split the targets\n",
- " y_train = y_perm[0:num_train]\n",
- "\n",
- " # Normalization step (for real valued targets only)\n",
- " if model_type == 'regression':\n",
- " # print('\\n Normalizing output y...')\n",
- " y_train_mean = np.mean(y_train)\n",
- " y_train_std = np.std(y_train)\n",
- " y_train = (y_train - y_train_mean) / float(y_train_std)\n",
- " # print(y)\n",
- "\n",
- " y_val = y_perm[num_train:(num_train + num_val)]\n",
- " y_test = y_perm[(num_train + num_val):datasize]\n",
- "\n",
- " # Record the performance for each parameter trial respectively on validation and test set\n",
- " perf_all_val = []\n",
- " perf_all_test = []\n",
- "\n",
- " # For each parameter trial\n",
- " for i in range(trials):\n",
- " # For regression use the Kernel Ridge method\n",
- " if model_type == 'regression':\n",
- " # print('\\n Starting experiment for trial %d and parameter alpha = %3f\\n ' % (i, alpha_grid[i]))\n",
- "\n",
- " # Fit the kernel ridge model\n",
- " KR = KernelRidge(kernel = 'precomputed', alpha = alpha_grid[i])\n",
- " # KR = svm.SVR(kernel = 'precomputed', C = C_grid[i])\n",
- " KR.fit(Kmatrix_train, y_train)\n",
- "\n",
- " # predict on the validation and test set\n",
- " y_pred = KR.predict(Kmatrix_val)\n",
- " y_pred_test = KR.predict(Kmatrix_test)\n",
- " # print(y_pred)\n",
- "\n",
- " # adjust prediction: needed because the training targets have been normalizaed\n",
- " y_pred = y_pred * float(y_train_std) + y_train_mean\n",
- " # print(y_pred)\n",
- " y_pred_test = y_pred_test * float(y_train_std) + y_train_mean\n",
- " # print(y_pred_test)\n",
- "\n",
- " # root mean squared error on validation\n",
- " rmse = np.sqrt(mean_squared_error(y_val, y_pred))\n",
- " perf_all_val.append(rmse)\n",
- "\n",
- " # root mean squared error in test \n",
- " rmse_test = np.sqrt(mean_squared_error(y_test, y_pred_test))\n",
- " perf_all_test.append(rmse_test)\n",
- "\n",
- " # print('The performance on the validation set is: %3f' % rmse)\n",
- " # print('The performance on the test set is: %3f' % rmse_test)\n",
- "\n",
- " # --- FIND THE OPTIMAL PARAMETERS --- #\n",
- " # For regression: minimise the mean squared error\n",
- " if model_type == 'regression':\n",
- "\n",
- " # get optimal parameter on validation (argmin mean squared error)\n",
- " min_idx = np.argmin(perf_all_test)\n",
- " alpha_opt = alpha_grid[min_idx]\n",
- "\n",
- " # performance corresponding to optimal parameter on val\n",
- " perf_val_opt = perf_all_val[min_idx]\n",
- "\n",
- " # corresponding performance on test for the same parameter\n",
- " perf_test_opt = perf_all_test[min_idx]\n",
- "\n",
- " # print('The best performance is for trial %d with parameter alpha = %3f' % (min_idx, alpha_opt))\n",
- " # print('The best performance on the validation set is: %3f' % perf_val_opt)\n",
- " # print('The corresponding performance on test set is: %3f' % perf_test_opt)\n",
- "\n",
- " # append the best performance on validation\n",
- " # at the current split\n",
- " val_split.append(perf_val_opt)\n",
- "\n",
- " # append the correponding performance on the test set\n",
- " test_split.append(perf_test_opt)\n",
- "\n",
- " # average the results\n",
- " # mean of the validation performances over the splits\n",
- " val_mean = np.mean(np.asarray(val_split))\n",
- " # std deviation of validation over the splits\n",
- " val_std = np.std(np.asarray(val_split))\n",
- "\n",
- " # mean of the test performances over the splits\n",
- " test_mean = np.mean(np.asarray(test_split))\n",
- " # std deviation of the test oer the splits\n",
- " test_std = np.std(np.asarray(test_split))\n",
- "\n",
- " print('\\n Mean performance on val set: %3f' % val_mean)\n",
- " print('With standard deviation: %3f' % val_std)\n",
- " print('\\n Mean performance on test set: %3f' % test_mean)\n",
- " print('With standard deviation: %3f' % test_std)\n",
- " \n",
- " val_means_height.append(val_mean)\n",
- " val_stds_height.append(val_std)\n",
- " test_means_height.append(test_mean)\n",
- " test_stds_height.append(test_std)\n",
- " \n",
- "print('\\n') \n",
- "print(tabulate({'height': np.linspace(1, 12, 11), 'RMSE': test_means_height, 'std': test_stds_height}, headers='keys'))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "scrolled": true
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- "- This script take as input a kernel matrix\n",
- "and returns the classification or regression performance\n",
- "- The kernel matrix can be calculated using any of the graph kernels approaches\n",
- "- The criteria used for prediction are SVM for classification and kernel Ridge regression for regression\n",
- "- For predition we divide the data in training, validation and test. For each split, we first train on the train data, \n",
- "then evaluate the performance on the validation. We choose the optimal parameters for the validation set and finally\n",
- "provide the corresponding performance on the test set. If more than one split is performed, the final results \n",
- "correspond to the average of the performances on the test sets. \n",
- "\n",
- "@references\n",
- " https://github.com/eghisu/GraphKernels/blob/master/GraphKernelsCollection/python_scripts/compute_perf_gk.py\n",
- "\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 0 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman sp kernel matrix of size 185 built in 47.540945053100586 seconds ---\n",
- "[[ 6. 2. 6. ..., 2. 2. 2.]\n",
- " [ 2. 12. 2. ..., 0. 0. 6.]\n",
- " [ 6. 2. 6. ..., 2. 2. 2.]\n",
- " ..., \n",
- " [ 2. 0. 2. ..., 110. 42. 14.]\n",
- " [ 2. 0. 2. ..., 42. 110. 14.]\n",
- " [ 2. 6. 2. ..., 14. 14. 110.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 38.533318\n",
- "With standard deviation: 6.213602\n",
- "\n",
- " Mean performance on test set: 36.055557\n",
- "With standard deviation: 5.386696\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 1 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman sp kernel matrix of size 185 built in 75.94973611831665 seconds ---\n",
- "[[ 9. 3. 9. ..., 3. 3. 3.]\n",
- " [ 3. 18. 3. ..., 0. 0. 9.]\n",
- " [ 9. 3. 9. ..., 3. 3. 3.]\n",
- " ..., \n",
- " [ 3. 0. 3. ..., 165. 63. 21.]\n",
- " [ 3. 0. 3. ..., 63. 165. 21.]\n",
- " [ 3. 9. 3. ..., 21. 21. 165.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 38.464684\n",
- "With standard deviation: 6.299737\n",
- "\n",
- " Mean performance on test set: 36.054735\n",
- "With standard deviation: 5.384130\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 2 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman sp kernel matrix of size 185 built in 98.63305306434631 seconds ---\n",
- "[[ 12. 4. 12. ..., 4. 4. 4.]\n",
- " [ 4. 24. 4. ..., 0. 0. 12.]\n",
- " [ 12. 4. 12. ..., 4. 4. 4.]\n",
- " ..., \n",
- " [ 4. 0. 4. ..., 220. 84. 28.]\n",
- " [ 4. 0. 4. ..., 84. 220. 28.]\n",
- " [ 4. 12. 4. ..., 28. 28. 220.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 38.594816\n",
- "With standard deviation: 6.106887\n",
- "\n",
- " Mean performance on test set: 36.069839\n",
- "With standard deviation: 5.406605\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 3 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n"
- ]
- },
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- " --- Weisfeiler-Lehman sp kernel matrix of size 185 built in 126.40115857124329 seconds ---\n",
- "[[ 15. 5. 15. ..., 5. 5. 5.]\n",
- " [ 5. 30. 5. ..., 0. 0. 15.]\n",
- " [ 15. 5. 15. ..., 5. 5. 5.]\n",
- " ..., \n",
- " [ 5. 0. 5. ..., 275. 105. 35.]\n",
- " [ 5. 0. 5. ..., 105. 275. 35.]\n",
- " [ 5. 15. 5. ..., 35. 35. 275.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on val set: 38.545772\n",
- "With standard deviation: 6.200795\n",
- "\n",
- " Mean performance on test set: 36.055164\n",
- "With standard deviation: 5.385283\n",
- "\n",
- " --- calculating kernel matrix when subtree height = 4 ---\n",
- "\n",
- " Loading dataset from file...\n",
- "[ -23.7 14. 37.3 109.7 10.8 39. 42. 66.6 135. 148.5\n",
- " 40. 34.6 32. 63. 53.5 67. 64.4 84.7 95.5 92.\n",
- " 84.4 154. 156. 166. 183. 70.3 63.6 52.5 59. 59.5\n",
- " 55.2 88. 83. 104.5 102. 92. 107.4 123.2 112.5 118.5\n",
- " 101.5 173.7 165.5 181. 99.5 92.3 90.1 80.2 82. 91.2\n",
- " 91.5 81.2 93. 69. 86.3 82. 103. 103.5 96. 112. 104.\n",
- " 132.5 123.5 120.3 145. 144.2 142.8 132. 134.2 137. 139.\n",
- " 133.6 120.4 120. 137. 195.8 177.2 181. 185.9 175.7 186. 211.\n",
- " 125. 118. 117.1 107. 102.5 112. 97.4 91.5 87.6 106.5\n",
- " 101. 99.3 90. 137. 114. 126. 124. 140.5 157.5 146. 145.\n",
- " 141. 171. 166. 155. 145. 159. 138. 142. 159. 163.5\n",
- " 229.5 142. 125. 132. 130.5 125. 122. 121. 122.2 112. 106.\n",
- " 114.5 151. 128.5 109.5 126. 147. 158. 147. 165. 188.9\n",
- " 170. 178. 148.5 165. 177. 167. 195. 226. 215. 201. 205.\n",
- " 151.5 165.5 157. 139. 163. 153.5 139. 162. 173. 159.5\n",
- " 159.5 155.5 141. 126. 164. 163. 166.5 146. 165. 159. 195.\n",
- " 218. 250. 235. 186.5 156.5 162. 162. 170.2 173.2 186.8\n",
- " 173. 187. 174. 188.5 199. 228. 215. 216. 240. ]\n",
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n"
- ]
- }
- ],
- "source": [
- "# Author: Elisabetta Ghisu\n",
- "# test of WL subtree kernel\n",
- "\n",
- "\"\"\"\n",
- "- This script take as input a kernel matrix\n",
- "and returns the classification or regression performance\n",
- "- The kernel matrix can be calculated using any of the graph kernels approaches\n",
- "- The criteria used for prediction are SVM for classification and kernel Ridge regression for regression\n",
- "- For predition we divide the data in training, validation and test. For each split, we first train on the train data, \n",
- "then evaluate the performance on the validation. We choose the optimal parameters for the validation set and finally\n",
- "provide the corresponding performance on the test set. If more than one split is performed, the final results \n",
- "correspond to the average of the performances on the test sets. \n",
- "\n",
- "@references\n",
- " https://github.com/eghisu/GraphKernels/blob/master/GraphKernelsCollection/python_scripts/compute_perf_gk.py\n",
- "\"\"\"\n",
- "\n",
- "print(__doc__)\n",
- "\n",
- "import sys\n",
- "import os\n",
- "import pathlib\n",
- "sys.path.insert(0, \"../\")\n",
- "from tabulate import tabulate\n",
- "\n",
- "import random\n",
- "import numpy as np\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "from sklearn.kernel_ridge import KernelRidge # 0.17\n",
- "from sklearn.metrics import accuracy_score, mean_squared_error\n",
- "from sklearn import svm\n",
- "\n",
- "from pygraph.kernels.weisfeilerLehmanKernel import weisfeilerlehmankernel\n",
- "from pygraph.utils.graphfiles import loadDataset\n",
- "\n",
- "val_means_height = []\n",
- "val_stds_height = []\n",
- "test_means_height = []\n",
- "test_stds_height = []\n",
- "\n",
- "\n",
- "for height in np.linspace(0, 10, 11):\n",
- " print('\\n --- calculating kernel matrix when subtree height = %d ---' % height)\n",
- "\n",
- " print('\\n Loading dataset from file...')\n",
- " dataset, y = loadDataset(\"../../../../datasets/acyclic/Acyclic/dataset_bps.ds\")\n",
- " y = np.array(y)\n",
- " print(y)\n",
- "\n",
- " # setup the parameters\n",
- " model_type = 'regression' # Regression or classification problem\n",
- " print('\\n --- This is a %s problem ---' % model_type)\n",
- "\n",
- " datasize = len(dataset)\n",
- " trials = 100 # Trials for hyperparameters random search\n",
- " splits = 10 # Number of splits of the data\n",
- " alpha_grid = np.logspace(-10, 10, num = trials, base = 10) # corresponds to (2*C)^-1 in other linear models such as LogisticRegression\n",
- " C_grid = np.logspace(-10, 10, num = trials, base = 10)\n",
- " random.seed(20) # Set the seed for uniform parameter distribution\n",
- "\n",
- " # set the output path\n",
- " kernel_file_path = 'kernelmatrices_weisfeilerlehman_acyclic/'\n",
- " if not os.path.exists(kernel_file_path):\n",
- " os.makedirs(kernel_file_path)\n",
- "\n",
- "\n",
- " \"\"\"\n",
- " - Here starts the main program\n",
- " - First we permute the data, then for each split we evaluate corresponding performances\n",
- " - In the end, the performances are averaged over the test sets\n",
- " \"\"\"\n",
- "\n",
- " # save kernel matrices to files / read kernel matrices from files\n",
- " kernel_file = kernel_file_path + 'km.ds'\n",
- " path = pathlib.Path(kernel_file)\n",
- " # get train set kernel matrix\n",
- " if path.is_file():\n",
- " print('\\n Loading the kernel matrix from file...')\n",
- " Kmatrix = np.loadtxt(kernel_file)\n",
- " print(Kmatrix)\n",
- " else:\n",
- " print('\\n Calculating kernel matrix, this could take a while...')\n",
- " Kmatrix = weisfeilerlehmankernel(dataset, height = int(height), base_kernel = 'sp')\n",
- " print(Kmatrix)\n",
- " print('\\n Saving kernel matrix to file...')\n",
- "# np.savetxt(kernel_file, Kmatrix)\n",
- "\n",
- " # Initialize the performance of the best parameter trial on validation with the corresponding performance on test\n",
- " val_split = []\n",
- " test_split = []\n",
- "\n",
- " # For each split of the data\n",
- " for j in range(10, 10 + splits):\n",
- " # print('\\n Starting split %d...' % j)\n",
- "\n",
- " # Set the random set for data permutation\n",
- " random_state = int(j)\n",
- " np.random.seed(random_state)\n",
- " idx_perm = np.random.permutation(datasize)\n",
- " # print(idx_perm)\n",
- "\n",
- " # Permute the data\n",
- " y_perm = y[idx_perm] # targets permutation\n",
- " # print(y_perm)\n",
- " Kmatrix_perm = Kmatrix[:, idx_perm] # inputs permutation\n",
- " # print(Kmatrix_perm)\n",
- " Kmatrix_perm = Kmatrix_perm[idx_perm, :] # inputs permutation\n",
- "\n",
- " # Set the training, validation and test\n",
- " # Note: the percentage can be set up by the user\n",
- " num_train_val = int((datasize * 90) / 100) # 90% (of entire dataset) for training and validation\n",
- " num_test = datasize - num_train_val # 10% (of entire dataset) for test\n",
- " num_train = int((num_train_val * 90) / 100) # 90% (of train + val) for training\n",
- " num_val = num_train_val - num_train # 10% (of train + val) for validation\n",
- "\n",
- " # Split the kernel matrix\n",
- " Kmatrix_train = Kmatrix_perm[0:num_train, 0:num_train]\n",
- " Kmatrix_val = Kmatrix_perm[num_train:(num_train + num_val), 0:num_train]\n",
- " Kmatrix_test = Kmatrix_perm[(num_train + num_val):datasize, 0:num_train]\n",
- "\n",
- " # Split the targets\n",
- " y_train = y_perm[0:num_train]\n",
- "\n",
- " # Normalization step (for real valued targets only)\n",
- " if model_type == 'regression':\n",
- " # print('\\n Normalizing output y...')\n",
- " y_train_mean = np.mean(y_train)\n",
- " y_train_std = np.std(y_train)\n",
- " y_train = (y_train - y_train_mean) / float(y_train_std)\n",
- " # print(y)\n",
- "\n",
- " y_val = y_perm[num_train:(num_train + num_val)]\n",
- " y_test = y_perm[(num_train + num_val):datasize]\n",
- "\n",
- " # Record the performance for each parameter trial respectively on validation and test set\n",
- " perf_all_val = []\n",
- " perf_all_test = []\n",
- "\n",
- " # For each parameter trial\n",
- " for i in range(trials):\n",
- " # For regression use the Kernel Ridge method\n",
- " if model_type == 'regression':\n",
- " # print('\\n Starting experiment for trial %d and parameter alpha = %3f\\n ' % (i, alpha_grid[i]))\n",
- "\n",
- " # Fit the kernel ridge model\n",
- " KR = KernelRidge(kernel = 'precomputed', alpha = alpha_grid[i])\n",
- " # KR = svm.SVR(kernel = 'precomputed', C = C_grid[i])\n",
- " KR.fit(Kmatrix_train, y_train)\n",
- "\n",
- " # predict on the validation and test set\n",
- " y_pred = KR.predict(Kmatrix_val)\n",
- " y_pred_test = KR.predict(Kmatrix_test)\n",
- " # print(y_pred)\n",
- "\n",
- " # adjust prediction: needed because the training targets have been normalizaed\n",
- " y_pred = y_pred * float(y_train_std) + y_train_mean\n",
- " # print(y_pred)\n",
- " y_pred_test = y_pred_test * float(y_train_std) + y_train_mean\n",
- " # print(y_pred_test)\n",
- "\n",
- " # root mean squared error on validation\n",
- " rmse = np.sqrt(mean_squared_error(y_val, y_pred))\n",
- " perf_all_val.append(rmse)\n",
- "\n",
- " # root mean squared error in test \n",
- " rmse_test = np.sqrt(mean_squared_error(y_test, y_pred_test))\n",
- " perf_all_test.append(rmse_test)\n",
- "\n",
- " # print('The performance on the validation set is: %3f' % rmse)\n",
- " # print('The performance on the test set is: %3f' % rmse_test)\n",
- "\n",
- " # --- FIND THE OPTIMAL PARAMETERS --- #\n",
- " # For regression: minimise the mean squared error\n",
- " if model_type == 'regression':\n",
- "\n",
- " # get optimal parameter on validation (argmin mean squared error)\n",
- " min_idx = np.argmin(perf_all_test)\n",
- " alpha_opt = alpha_grid[min_idx]\n",
- "\n",
- " # performance corresponding to optimal parameter on val\n",
- " perf_val_opt = perf_all_val[min_idx]\n",
- "\n",
- " # corresponding performance on test for the same parameter\n",
- " perf_test_opt = perf_all_test[min_idx]\n",
- "\n",
- " # print('The best performance is for trial %d with parameter alpha = %3f' % (min_idx, alpha_opt))\n",
- " # print('The best performance on the validation set is: %3f' % perf_val_opt)\n",
- " # print('The corresponding performance on test set is: %3f' % perf_test_opt)\n",
- "\n",
- " # append the best performance on validation\n",
- " # at the current split\n",
- " val_split.append(perf_val_opt)\n",
- "\n",
- " # append the correponding performance on the test set\n",
- " test_split.append(perf_test_opt)\n",
- "\n",
- " # average the results\n",
- " # mean of the validation performances over the splits\n",
- " val_mean = np.mean(np.asarray(val_split))\n",
- " # std deviation of validation over the splits\n",
- " val_std = np.std(np.asarray(val_split))\n",
- "\n",
- " # mean of the test performances over the splits\n",
- " test_mean = np.mean(np.asarray(test_split))\n",
- " # std deviation of the test oer the splits\n",
- " test_std = np.std(np.asarray(test_split))\n",
- "\n",
- " print('\\n Mean performance on val set: %3f' % val_mean)\n",
- " print('With standard deviation: %3f' % val_std)\n",
- " print('\\n Mean performance on test set: %3f' % test_mean)\n",
- " print('With standard deviation: %3f' % test_std)\n",
- " \n",
- " val_means_height.append(val_mean)\n",
- " val_stds_height.append(val_std)\n",
- " test_means_height.append(test_mean)\n",
- " test_stds_height.append(test_std)\n",
- " \n",
- "print('\\n') \n",
- "print(tabulate({'height': np.linspace(1, 12, 11), 'RMSE': test_means_height, 'std': test_stds_height}, headers='keys'))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "{0: 'C', 1: 'C', 2: 'C', 3: 'C', 4: 'C', 5: 'O', 6: 'O'}"
- ]
- },
- "execution_count": 15,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# a = [0, 1, 3, 2]\n",
- "# b = [3, 2, 1, 0]\n",
- "# print(1 if a == b else 0)\n",
- "\n",
- "# max(1 ,2)\n",
- "\n",
- "# x = [ 'r', 'a', 's' ]\n",
- "# x.sort()\n",
- "# print(x)\n",
- "\n",
- "# def test1(*args, base = 'subtree'):\n",
- "# if base == 'subtree':\n",
- "# print('subtree')\n",
- "# elif base == 'edge':\n",
- "# print('edge')\n",
- "# else:\n",
- "# print('sp')\n",
- "\n",
- "# # function parameter usage test\n",
- "# test1('hello', 'hi', base = 'edge')\n",
- "\n",
- "# # python matrix calculation speed test\n",
- "# import numpy as np\n",
- "# import time\n",
- "\n",
- "# size = 100\n",
- "# m1 = np.random.random((size, size))\n",
- "# m2 = np.random.random((size, size))\n",
- "# itr = 1\n",
- "\n",
- "# start_time = time.time()\n",
- "# for i in range(itr):\n",
- "# np.dot(m1, m2)\n",
- "# print(time.time() - start_time)\n",
- "\n",
- "# start_time = time.time()\n",
- "# for j in range(itr):\n",
- "# result = np.zeros((size, size))\n",
- "# for i1 in range(size):\n",
- "# for i2 in range(size):\n",
- "# for i3 in range(size):\n",
- "# result[i1][i2] += m1[i1][i3] * m2[i3][i2]\n",
- "# print(time.time() - start_time)\n",
- "\n",
- "# start_time = time.time()\n",
- "# for i in range(itr):\n",
- "# print(np.dot(m1, m2))\n",
- "# print(time.time() - start_time)\n",
- "\n",
- "# start_time = time.time()\n",
- "# for j in range(itr):\n",
- "# result = np.zeros((size, size))\n",
- "# for i1 in range(size):\n",
- "# for i2 in range(size):\n",
- "# for i3 in range(size):\n",
- "# result[i1][i2] += m1[i1][i3] * m2[i3][i2]\n",
- "# print(result)\n",
- "# print(time.time() - start_time)\n",
- "\n",
- "# help(np.sum)\n",
- "\n",
- "# test dict\n",
- "import sys\n",
- "from collections import Counter\n",
- "import networkx as nx\n",
- "sys.path.insert(0, \"../\")\n",
- "from pygraph.utils.graphfiles import loadDataset\n",
- "from pygraph.kernels.spkernel import spkernel\n",
- "\n",
- "dataset, y = loadDataset(\"../../../../datasets/acyclic/Acyclic/dataset_bps.ds\")\n",
- "G1 = dataset[15]\n",
- "nx.get_node_attributes(G1, 'label')\n",
- "listhqhq = list(nx.get_node_attributes(G1, 'label').values())\n",
- "dicthaha = dict(Counter(listhqhq))\n",
- "len(dicthaha)"
- ]
- }
- ],
- "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.5.2"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 2
- }
|