|
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015 |
- {
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "\n",
- " --- This is a regression problem ---\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 0.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 0.38979601860046387 seconds ---\n",
- "[[ 5. 6. 4. ..., 20. 20. 20.]\n",
- " [ 6. 8. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 5. ..., 21. 21. 21.]\n",
- " ..., \n",
- " [ 20. 20. 21. ..., 101. 101. 101.]\n",
- " [ 20. 20. 21. ..., 101. 101. 101.]\n",
- " [ 20. 20. 21. ..., 101. 101. 101.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 17.681582\n",
- "With standard deviation: 0.713183\n",
- "\n",
- " Mean performance on test set: 15.685879\n",
- "With standard deviation: 4.139197\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 1.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 0.8205692768096924 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 train set: 6.270014\n",
- "With standard deviation: 0.654734\n",
- "\n",
- " Mean performance on test set: 7.550458\n",
- "With standard deviation: 2.331786\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 2.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 1.375309705734253 seconds ---\n",
- "[[ 15. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 24. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 15. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 159. 151. 124.]\n",
- " [ 20. 20. 22. ..., 151. 153. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 185.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 4.450682\n",
- "With standard deviation: 0.882129\n",
- "\n",
- " Mean performance on test set: 9.728466\n",
- "With standard deviation: 2.057669\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 3.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 1.8636789321899414 seconds ---\n",
- "[[ 20. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 32. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 20. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 188. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 168. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 202.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 2.270586\n",
- "With standard deviation: 0.481516\n",
- "\n",
- " Mean performance on test set: 11.296110\n",
- "With standard deviation: 2.799944\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 4.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 2.5077457427978516 seconds ---\n",
- "[[ 25. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 40. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 25. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 217. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 183. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 213.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 1.074035\n",
- "With standard deviation: 0.637823\n",
- "\n",
- " Mean performance on test set: 12.808303\n",
- "With standard deviation: 3.446939\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 5.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 2.8235607147216797 seconds ---\n",
- "[[ 30. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 48. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 30. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 246. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 198. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 224.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.700602\n",
- "With standard deviation: 0.572640\n",
- "\n",
- " Mean performance on test set: 14.017923\n",
- "With standard deviation: 3.675042\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 6.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 3.458494186401367 seconds ---\n",
- "[[ 35. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 56. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 35. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 275. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 213. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 235.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691515\n",
- "With standard deviation: 0.564620\n",
- "\n",
- " Mean performance on test set: 14.918434\n",
- "With standard deviation: 3.805352\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 7.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 3.861224889755249 seconds ---\n",
- "[[ 40. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 64. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 40. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 304. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 228. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 246.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691516\n",
- "With standard deviation: 0.564620\n",
- "\n",
- " Mean performance on test set: 15.629476\n",
- "With standard deviation: 3.865387\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 8.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 4.295838117599487 seconds ---\n",
- "[[ 45. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 72. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 45. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 333. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 243. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 257.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691515\n",
- "With standard deviation: 0.564620\n",
- "\n",
- " Mean performance on test set: 16.214369\n",
- "With standard deviation: 3.928756\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 9.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 5.008287668228149 seconds ---\n",
- "[[ 50. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 80. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 50. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 362. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 258. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 268.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691515\n",
- "With standard deviation: 0.564620\n",
- "\n",
- " Mean performance on test set: 16.725744\n",
- "With standard deviation: 3.993095\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when height = 10.0 ---#\n",
- "\n",
- " Loading dataset from file...\n",
- "\n",
- " Calculating kernel matrix, this could take a while...\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel matrix of size 185 built in 5.347799301147461 seconds ---\n",
- "[[ 55. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 88. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 55. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 391. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 273. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 279.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691516\n",
- "With standard deviation: 0.564621\n",
- "\n",
- " Mean performance on test set: 17.186401\n",
- "With standard deviation: 4.056724\n",
- "\n",
- "\n",
- " height RMSE_test std_test RMSE_train std_train k_time\n",
- "-------- ----------- ---------- ------------ ----------- --------\n",
- " 0 15.6859 4.1392 17.6816 0.713183 0.389796\n",
- " 1 7.55046 2.33179 6.27001 0.654734 0.820569\n",
- " 2 9.72847 2.05767 4.45068 0.882129 1.37531\n",
- " 3 11.2961 2.79994 2.27059 0.481516 1.86368\n",
- " 4 12.8083 3.44694 1.07403 0.637823 2.50775\n",
- " 5 14.0179 3.67504 0.700602 0.57264 2.82356\n",
- " 6 14.9184 3.80535 0.691515 0.56462 3.45849\n",
- " 7 15.6295 3.86539 0.691516 0.56462 3.86122\n",
- " 8 16.2144 3.92876 0.691515 0.56462 4.29584\n",
- " 9 16.7257 3.9931 0.691515 0.56462 5.00829\n",
- " 10 17.1864 4.05672 0.691516 0.564621 5.3478\n"
- ]
- }
- ],
- "source": [
- "# wl subtree kernel\n",
- "%load_ext line_profiler\n",
- "\n",
- "import numpy as np\n",
- "import sys\n",
- "sys.path.insert(0, \"../\")\n",
- "from pygraph.utils.utils import kernel_train_test\n",
- "from pygraph.kernels.weisfeilerLehmanKernel import weisfeilerlehmankernel, _wl_subtreekernel_do\n",
- "\n",
- "datafile = '../../../../datasets/acyclic/Acyclic/dataset_bps.ds'\n",
- "kernel_file_path = 'kernelmatrices_weisfeilerlehman_subtree_acyclic/'\n",
- "\n",
- "kernel_para = dict(node_label = 'atom', edge_label = 'bond_type')\n",
- "\n",
- "kernel_train_test(datafile, kernel_file_path, weisfeilerlehmankernel, kernel_para, \\\n",
- " hyper_name = 'height', hyper_range = np.linspace(0, 10, 11), normalize = False)\n",
- "\n",
- "# %lprun -f _wl_subtreekernel_do \\\n",
- "# kernel_train_test(datafile, kernel_file_path, weisfeilerlehmankernel, kernel_para, \\\n",
- "# hyper_name = 'height', hyper_range = np.linspace(0, 10, 11), normalize = False)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
- {
- "ename": "ImportError",
- "evalue": "cannot import name 'NUMPY_MKL'",
- "output_type": "error",
- "traceback": [
- "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[1;31mImportError\u001b[0m Traceback (most recent call last)",
- "\u001b[1;32m<ipython-input-1-e7b9d5ef03e3>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[0msys\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpath\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minsert\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"../\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mpygraph\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mutils\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mutils\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mkernel_train_test\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 8\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mpygraph\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mkernels\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mweisfeilerLehmanKernel\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mweisfeilerlehmankernel\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0m_wl_subtreekernel_do\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
- "\u001b[1;32mE:\\课程及课件\\Doctorant\\py-graph\\pygraph\\utils\\utils.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 183\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 184\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mrandom\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 185\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0msklearn\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mkernel_ridge\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mKernelRidge\u001b[0m \u001b[1;31m# 0.17\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 186\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0msklearn\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmetrics\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0maccuracy_score\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmean_squared_error\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 187\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0msklearn\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0msvm\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
- "\u001b[1;32md:\\python\\python36\\lib\\site-packages\\sklearn\\__init__.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 132\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 133\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0m__check_build\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 134\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m\u001b[0mbase\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mclone\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 135\u001b[0m \u001b[0m__check_build\u001b[0m \u001b[1;31m# avoid flakes unused variable error\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 136\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
- "\u001b[1;32md:\\python\\python36\\lib\\site-packages\\sklearn\\base.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mscipy\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0msparse\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 12\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m\u001b[0mexternals\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0msix\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 13\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m\u001b[0mutils\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfixes\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0msignature\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
- "\u001b[1;32md:\\python\\python36\\lib\\site-packages\\scipy\\__init__.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 59\u001b[0m \u001b[0m__all__\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;34m'test'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 60\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 61\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[0mnumpy\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_distributor_init\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mNUMPY_MKL\u001b[0m \u001b[1;31m# requires numpy+mkl\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 62\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 63\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mshow_config\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mshow_numpy_config\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
- "\u001b[1;31mImportError\u001b[0m: cannot import name 'NUMPY_MKL'"
- ]
- }
- ],
- "source": [
- "# WL sp kernel\n",
- "%load_ext line_profiler\n",
- "\n",
- "import numpy as np\n",
- "import sys\n",
- "sys.path.insert(0, \"../\")\n",
- "from pygraph.utils.utils import kernel_train_test\n",
- "from pygraph.kernels.weisfeilerLehmanKernel import weisfeilerlehmankernel, _wl_subtreekernel_do\n",
- "\n",
- "datafile = '../../../../datasets/acyclic/Acyclic/dataset_bps.ds'\n",
- "kernel_file_path = 'kernelmatrices_weisfeilerlehman_subtree_acyclic/'\n",
- "\n",
- "kernel_para = dict(node_label = 'atom', edge_label = 'bond_type', base_kernel = 'sp')\n",
- "\n",
- "kernel_train_test(datafile, kernel_file_path, weisfeilerlehmankernel, kernel_para, \\\n",
- " hyper_name = 'height', hyper_range = np.linspace(0, 10, 11), normalize = False)\n",
- "\n",
- "# %lprun -f _wl_subtreekernel_do \\\n",
- "# kernel_train_test(datafile, kernel_file_path, weisfeilerlehmankernel, kernel_para, \\\n",
- "# hyper_name = 'height', hyper_range = np.linspace(0, 10, 11), normalize = False)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "# results\n",
- "\n",
- "# with y normalization\n",
- " height RMSE_test std_test RMSE_train std_train k_time\n",
- "-------- ----------- ---------- ------------ ----------- --------\n",
- " 0 36.2108 7.33179 38.6059 1.57064 0.379475\n",
- " 1 9.00098 6.37145 6.76379 1.96568 0.844898\n",
- " 2 19.8113 4.04911 5.28757 1.81899 1.35308\n",
- " 3 25.0455 4.94276 2.3274 0.805733 1.81136\n",
- " 4 28.2255 6.5212 0.85156 0.423465 2.23098\n",
- " 5 30.6354 6.73647 3.35947 8.17561 2.71575\n",
- " 6 32.1027 6.85601 3.54105 8.71922 3.11459\n",
- " 7 32.9709 6.89606 6.94372 9.94045 3.55571\n",
- " 8 33.5112 6.90753 6.97339 9.76975 3.79657\n",
- " 9 33.8502 6.91427 11.8345 11.6213 4.41555\n",
- " 10 34.0963 6.93115 11.4257 11.2624 4.94888\n",
- "\n",
- "# without y normalization\n",
- " height RMSE_test std_test RMSE_train std_train k_time\n",
- "-------- ----------- ---------- ------------ ----------- --------\n",
- " 0 15.6859 4.1392 17.6816 0.713183 0.360443\n",
- " 1 7.55046 2.33179 6.27001 0.654734 0.837389\n",
- " 2 9.72847 2.05767 4.45068 0.882129 1.25317\n",
- " 3 11.2961 2.79994 2.27059 0.481516 1.79971\n",
- " 4 12.8083 3.44694 1.07403 0.637823 2.35346\n",
- " 5 14.0179 3.67504 0.700602 0.57264 2.78285\n",
- " 6 14.9184 3.80535 0.691515 0.56462 3.20764\n",
- " 7 15.6295 3.86539 0.691516 0.56462 3.71648\n",
- " 8 16.2144 3.92876 0.691515 0.56462 3.99213\n",
- " 9 16.7257 3.9931 0.691515 0.56462 4.26315\n",
- " 10 17.1864 4.05672 0.691516 0.564621 5.00918"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "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",
- " Elisabetta Ghisu, https://github.com/eghisu/GraphKernels/blob/master/GraphKernelsCollection/python_scripts/compute_perf_gk.py\n",
- "\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 0 ---#\n",
- "\n",
- " Loading dataset from file...\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.3920705318450928 seconds ---\n",
- "[[ 5. 6. 4. ..., 20. 20. 20.]\n",
- " [ 6. 8. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 5. ..., 21. 21. 21.]\n",
- " ..., \n",
- " [ 20. 20. 21. ..., 101. 101. 101.]\n",
- " [ 20. 20. 21. ..., 101. 101. 101.]\n",
- " [ 20. 20. 21. ..., 101. 101. 101.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 17.681582\n",
- "With standard deviation: 0.713183\n",
- "\n",
- " Mean performance on test set: 15.685879\n",
- "With standard deviation: 4.139197\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 1 ---#\n",
- "\n",
- " Loading dataset from file...\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.8578901290893555 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 train set: 6.270014\n",
- "With standard deviation: 0.654734\n",
- "\n",
- " Mean performance on test set: 7.550458\n",
- "With standard deviation: 2.331786\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 2 ---#\n",
- "\n",
- " Loading dataset from file...\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.264050006866455 seconds ---\n",
- "[[ 15. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 24. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 15. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 159. 151. 124.]\n",
- " [ 20. 20. 22. ..., 151. 153. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 185.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 4.450682\n",
- "With standard deviation: 0.882129\n",
- "\n",
- " Mean performance on test set: 9.728466\n",
- "With standard deviation: 2.057669\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 3 ---#\n",
- "\n",
- " Loading dataset from file...\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.731236219406128 seconds ---\n",
- "[[ 20. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 32. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 20. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 188. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 168. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 202.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 2.270586\n",
- "With standard deviation: 0.481516\n",
- "\n",
- " Mean performance on test set: 11.296110\n",
- "With standard deviation: 2.799944\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 4 ---#\n",
- "\n",
- " Loading dataset from file...\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.1112847328186035 seconds ---\n",
- "[[ 25. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 40. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 25. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 217. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 183. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 213.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 1.074035\n",
- "With standard deviation: 0.637823\n",
- "\n",
- " Mean performance on test set: 12.808303\n",
- "With standard deviation: 3.446939\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 5 ---#\n",
- "\n",
- " Loading dataset from file...\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.4751319885253906 seconds ---\n",
- "[[ 30. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 48. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 30. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 246. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 198. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 224.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.700602\n",
- "With standard deviation: 0.572640\n",
- "\n",
- " Mean performance on test set: 14.017923\n",
- "With standard deviation: 3.675042\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 6 ---#\n",
- "\n",
- " Loading dataset from file...\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.8712213039398193 seconds ---\n",
- "[[ 35. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 56. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 35. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 275. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 213. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 235.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691515\n",
- "With standard deviation: 0.564620\n",
- "\n",
- " Mean performance on test set: 14.918434\n",
- "With standard deviation: 3.805352\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 7 ---#\n",
- "\n",
- " Loading dataset from file...\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.554422378540039 seconds ---\n",
- "[[ 40. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 64. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 40. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 304. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 228. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 246.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691516\n",
- "With standard deviation: 0.564620\n",
- "\n",
- " Mean performance on test set: 15.629476\n",
- "With standard deviation: 3.865387\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 8 ---#\n",
- "\n",
- " Loading dataset from file...\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.8757314682006836 seconds ---\n",
- "[[ 45. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 72. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 45. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 333. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 243. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 257.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691515\n",
- "With standard deviation: 0.564620\n",
- "\n",
- " Mean performance on test set: 16.214369\n",
- "With standard deviation: 3.928756\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 9 ---#\n",
- "\n",
- " Loading dataset from file...\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.205373764038086 seconds ---\n",
- "[[ 50. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 80. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 50. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 362. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 258. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 268.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691515\n",
- "With standard deviation: 0.564620\n",
- "\n",
- " Mean performance on test set: 16.725744\n",
- "With standard deviation: 3.993095\n",
- "\n",
- "\n",
- " #--- calculating kernel matrix when subtree height = 10 ---#\n",
- "\n",
- " Loading dataset from file...\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 4.737298250198364 seconds ---\n",
- "[[ 55. 10. 4. ..., 20. 20. 20.]\n",
- " [ 10. 88. 4. ..., 20. 20. 20.]\n",
- " [ 4. 4. 55. ..., 22. 22. 26.]\n",
- " ..., \n",
- " [ 20. 20. 22. ..., 391. 159. 124.]\n",
- " [ 20. 20. 22. ..., 159. 273. 124.]\n",
- " [ 20. 20. 26. ..., 124. 124. 279.]]\n",
- "\n",
- " Saving kernel matrix to file...\n",
- "\n",
- " Mean performance on train set: 0.691516\n",
- "With standard deviation: 0.564621\n",
- "\n",
- " Mean performance on test set: 17.186401\n",
- "With standard deviation: 4.056724\n",
- "\n",
- "\n",
- " height RMSE_test std_test RMSE_train std_train k_time\n",
- "-------- ----------- ---------- ------------ ----------- --------\n",
- " 0 15.6859 4.1392 17.6816 0.713183 0.392071\n",
- " 1 7.55046 2.33179 6.27001 0.654734 0.85789\n",
- " 2 9.72847 2.05767 4.45068 0.882129 1.26405\n",
- " 3 11.2961 2.79994 2.27059 0.481516 1.73124\n",
- " 4 12.8083 3.44694 1.07403 0.637823 2.11128\n",
- " 5 14.0179 3.67504 0.700602 0.57264 2.47513\n",
- " 6 14.9184 3.80535 0.691515 0.56462 2.87122\n",
- " 7 15.6295 3.86539 0.691516 0.56462 3.55442\n",
- " 8 16.2144 3.92876 0.691515 0.56462 3.87573\n",
- " 9 16.7257 3.9931 0.691515 0.56462 4.20537\n",
- " 10 17.1864 4.05672 0.691516 0.564621 4.7373\n"
- ]
- }
- ],
- "source": [
- "# 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",
- " Elisabetta Ghisu, 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",
- "from collections import OrderedDict\n",
- "sys.path.insert(0, \"../\")\n",
- "from tabulate import tabulate\n",
- "\n",
- "import numpy as np\n",
- "import matplotlib.pyplot as plt\n",
- "\n",
- "from pygraph.kernels.weisfeilerLehmanKernel import weisfeilerlehmankernel\n",
- "from pygraph.utils.graphfiles import loadDataset\n",
- "from pygraph.utils.utils import split_train_test\n",
- "\n",
- "train_means_list = []\n",
- "train_stds_list = []\n",
- "test_means_list = []\n",
- "test_stds_list = []\n",
- "kernel_time_list = []\n",
- "\n",
- "for height in np.linspace(0, 10, 11):\n",
- " print('\\n\\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",
- "\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)# results\n",
- " print(Kmatrix)\n",
- " else:\n",
- " print('\\n Calculating kernel matrix, this could take a while...')\n",
- " Kmatrix, run_time = weisfeilerlehmankernel(dataset, node_label = 'atom', height = int(height))\n",
- " kernel_time_list.append(run_time)\n",
- " print(Kmatrix)\n",
- " print('\\n Saving kernel matrix to file...')\n",
- " # np.savetxt(kernel_file, Kmatrix)\n",
- "\n",
- " train_mean, train_std, test_mean, test_std = \\\n",
- " split_train_test(Kmatrix, y, alpha_grid, C_grid, splits, trials, model_type, normalize = False)\n",
- " \n",
- " train_means_list.append(train_mean)\n",
- " train_stds_list.append(train_std)\n",
- " test_means_list.append(test_mean)\n",
- " test_stds_list.append(test_std)\n",
- " \n",
- "print('\\n') \n",
- "table_dict = {'height': np.linspace(0, 10, 11), 'RMSE_test': test_means_list, 'std_test': test_stds_list, \\\n",
- " 'RMSE_train': train_means_list, 'std_train': train_stds_list, 'k_time': kernel_time_list}\n",
- "keyorder = ['height', 'RMSE_test', 'std_test', 'RMSE_train', 'std_train', 'k_time']\n",
- "print(tabulate(OrderedDict(sorted(table_dict.items(), key = lambda i:keyorder.index(i[0]))), headers='keys'))"
- ]
- },
- {
- "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": "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\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": "iVBORw0KGgoAAAANSUhEUgAAAX8AAAD8CAYAAACfF6SlAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzt3Xt8VPWd//HXh1tIAJGG+02wgi0WHrgGW9Zqcb2BpSJspXTRiq2lpa7bfWxBRa13C953f72AaBVRXLxQA90lIFrU1kUJKIJSgQCKICWAEKEESODz++NMcEhmkkxmJpOZeT8fj3lkzjnfc84nJ5PPOfM93/P9mrsjIiLZpVmqAxARkcan5C8ikoWU/EVEspCSv4hIFlLyFxHJQkr+IiJZSMlfRCQLKfmLiGQhJX8RkSzUIhEbMbPhwH8BzYHH3X16hDJjgTsAB95z93+pbZsdO3b0Pn36JCI8EZGssWrVqt3u3qmucnEnfzNrDvwWuAjYBhSb2UJ3XxdWph8wFTjH3feaWee6ttunTx9WrlwZb3giIlnFzD6uT7lEVPucDZS4+2Z3PwLMA0ZVK/Nj4LfuvhfA3UsTsF8REWmgRCT/HsAnYdPbQvPC9Qf6m9mbZvZWqJpIRERSJCF1/vXcTz9gGNATeMPMBrr7vvBCZjYRmAjQu3fvRgpNRCT7JOLKfzvQK2y6Z2heuG3AQnevcPctwAaCk8EJ3H2Wuxe4e0GnTnXerxARkQZKRPIvBvqZWV8zawWMAxZWK1NIcNWPmXUkqAbanIB9i4hIA8Sd/N29EvhXYAnwV+B5d//AzO4ys8tCxZYAe8xsHbAMmOLue+Ldt4iINIw11ZG8CgoKXE09RURiY2ar3L2grnJ6wldEJAs1VmsfEZHkKS2F2bNhzRooK4P27WHQILjmGlDjkYiU/EUkfRUXw7RpUFQUTB869MWyP/wBbr8dRoyAqVNhyJDUxNhEqdpHRNLTjBkwbBgUFgZJPzzxA5SXB/MKC4NyM2akIsomS1f+IpJ+ZsyAyZPh4MG6y7oH5SZPDqYnTUpubGlCV/4ikl6Ki2sk/t8ABUAOMCHaelUnALUiBJT8RSTdTJsWVOmE6Q7cCvywrnXLy4P1RclfRNJIaWlwc7fa80ljgMuB/LrWd4dFi2DXriQFmD6U/EUkfcyeHf82zBKznTSn5C8i6WPNmpqtemJVXg5r1yYmnjSm5C8i6aOsLDHb2bs3MdtJY0r+IpI+2rdPzHY6dEjMdtKYkr+IpI9Bg6B16xqzK4FDwNHQ61BoXkS5uTBwYLIiTBtK/iKSPiZMiDj7HiAXmA48E3p/T7RtuEfdTjZR8heR9NG5c9BXj9kJs+8AvNrrjkjrm8Gll6qzN5T8RSTdTJ0aVN00RG5usL4o+YtImhkyBB58EPLyYlsvLy9Yr6DOcU6ygpK/iKSfSZOOnwCO1VXW7IvEX61Tt2effZaCggLatm1Lt27dGDFiBH/5y1+SFnZTouQvIulp0iR2vfgi/9OyJZ6TU7MqKDc3aBk0ejS8/nqNxP/www/z7//+79x8883s3LmTrVu38rOf/YwFCxY04i+ROhrDV0TS1t1338327duZeffdQZcNa9cGD3B16BA055wwIeLN3bKyMnr06MGTTz7JFVdc0ehxJ1N9x/BVf/4ikpYqKyt57LHHWLhwYZDgp0yp97rLly/n0KFDjB49OokRNm2q9hGRtLRo0SJ69OjB4MGDY153z549dOzYkRYtsvf6V8lfRNLSzJkz+elPf9qgdfPz89m9ezeVlVGfA854Sv4ikna2bNnCihUrGDt2bIPWHzp0KDk5ORQWFiY4svSh5C8iaWfWrFn84Ac/ILeBD3u1b9+eu+66i+uuu47CwkIOHjxIRUUFRUVF3HDDDQmOtmnK3govEUlLhw8f5oknnuCNN96Iazu/+MUv6Nq1K/fccw/jx4+nXbt2nHXWWdxyyy0JirRpS0jyN7PhwH8BzYHH3X16lHL/DLwIDHF3teMUkZi99NJLfO1rX+P000+Pe1vjx49n/PjxCYgq/cRd7WNmzYHfAiOAAcD3zWxAhHLtgJ8Db8e7TxHJXjNmzGBStQe2JHaJqPM/Gyhx983ufgSYB4yKUO5u4D6CrrZFRGK2bt06NmzYwKhRkVKMxCIRyb8H8EnY9LbQvOPM7B+AXu7+vwnYn4hkqZkzZ3LttdfSsmXLVIeS9pJ+w9fMmgEPAxPqUXYiMBGgd+/eyQ1MRNLK3//+d+bOncu7776b6lAyQiKu/LcDvcKme4bmVWkHfA14zcw+Ar4BLDSzGn1PuPssdy9w94JOGmxBJKnSrUfLefPmcc455+jCMEESkfyLgX5m1tfMWgHjgIVVC929zN07unsfd+8DvAVcptY+IqmTjj1axvNEr9QUd7WPu1ea2b8CSwiaej7h7h+Y2V3ASndfWPsWRKQxlZWVcdttt/Hkk08yZsyY4/O/853v8J3vfCeFkUW3cuVKdu/ezSWXXJLqUDJGQur83X0RsKjavNuilB2WiH2KSMOkY4+WM2fOZOLEiTRv3jzVoWQMPeErkmXSrUfLffv2MX/+fNavX5/qUDKK+vYRyTLp1qPlnDlzGD58OJ07d051KBlFyV8ky6RTj5burhu9SaLkL5Jl0qlHy6rO284777wUR5J50qPST0QSKl16tKy66jezVIeScTSAu4g0STt37uQrX/kKW7Zs4eSTT051OGmjvgO4q9pHRJqkqucQlPiTQ9U+ItLkHD16lEcffZQXXngh1aFkLF35i0iT8/LLL5Ofn09BQZ21F9JASv4i0uRowJbkU/IXkSZl69atvPnmm4wbNy7VoWQ0JX8RaVIee+wxxo8fT5s2bVIdSkbTDV8RaTIqKir4/e9/z9KlS1MdSsbTlb+INBkLFiygX79+nHHGGakOJeMp+YtIk6F+fBqPkr+INAkbNmxg7dq1JwwwI8mj5C8iTcKjjz7KNddcQ05OTqpDyQq64SsiKVdeXs6cOXNYsWJFqkPJGrryF5GUe+GFFxgyZAh9+/ZNdShZQ8lfRFJuxowZutHbyJT8RSSlVq9ezfbt2/n2t7+d6lCyipK/iKTUzJkz+fGPf0zz5s1THUpW0Q1fEUmZ/fv389xzz7Fu3bpUh5J1dOUvIinzzDPPcMEFF9CtW7dUh5J1lPxFJCXcXV03p5CSv4ikxPLlyzl06BDnn39+qkPJSglJ/mY23MzWm1mJmd0UYfl/mNk6M1tjZq+a2SmJ2K+IpK+q5p3NmukaNBXiPupm1hz4LTACGAB838wGVCv2LlDg7oOAF4H7492viKSv3bt388c//pGrr7461aFkrUSccs8GStx9s7sfAeYBo8ILuPsydz8YmnwL6JmA/YpImpo9ezajRo0iPz8/1aFkrUQ09ewBfBI2vQ34ei3lfwQUJWC/IpKGjh07xqOPPsqcOXNSHUpWa9R2/mZ2JVAAfCvK8onARIDevXs3YmQi0lheffVV2rRpwze+8Y1Uh5LVElHtsx3oFTbdMzTvBGZ2IXALcJm7H460IXef5e4F7l7QqVOnBIQmIk1N1YAtZpbqULJaIpJ/MdDPzPqaWStgHLAwvICZnQk8SpD4SxOwTxFJQ9u3b2fZsmWMHz8+1aFkvbirfdy90sz+FVgCNAeecPcPzOwuYKW7LwQeANoCL4TO9lvd/bJ49y0iTVhpKcyeDWvWQFkZtG/PutJSfnTZZbRr1y7V0WW9hNT5u/siYFG1ebeFvb8wEfsRkTRQXAzTpkFRqF3HoUPHF30TuKBVK/j8c5g6FYYMSU2Moid8RSSBZsyAYcOgsDBI+mGJHyAXaHbkSLB82LCgvKSEevUUkcSYMQMmT4aDB+su6x6Umzw5mFb/Po1OV/4iEr/i4qiJfyPQGrgy0npVJ4CVK5McoFSn5C8i8Zs2DcrLIy66Dqi1Zr+8PFhfGpWSv4jEp7Q0uLnrXmPRPOBk4ILa1neHRYtg164kBSiRKPmLSHxmz444+3PgNuDh+mzDLOp2JDmU/EUkPmvW1GjVA/BLgo686tWLY3k5rF2b4MCkNmrtIyLxKSurMWs18ApBX+71tndvggKS+lDyF5H4tG9fY9ZrwEdAVfeMB4CjwDrgnSibOdq+Pc0TH51EoWofEYnPoEF469YnzJoIbCL4BrAa+CnwbYI+YCI5ZMYdL77ImDFjeOyxx9i2bVsyIxaU/EUkDu5OUZcuHDl8Yke9eUDXsFdbgrb+0frqbZ2Tw7+98w6jR49m2bJlDB48mIEDB3LDDTewbNkyjhw5ksxfIyuZR2ie1RQUFBT4Sj34IdJkFRcXM3nyZPbs2cMrJ51El7fewhqST8xg9GiYP//4rKNHj1JcXExRURFFRUVs2LCB888/nxEjRjBixAh69epVywazm5mtcveCOssp+YtILLZs2cLNN9/MG2+8wZ133smECRNo8e67QV899enaobq8PHj9dSiInq927drFkiVLKCoq4uWXX6Zz587HTwTnnnsurVq1avgvlGHqm/xV7SMi9bJ3714mT55MQUEBX/3qV9mwYQPXXnstLVq0CHrnfPDBIJHHIi8vWK+WxA/QqVMnrrzySubOncvf/vY3nnjiCdq2bcvNN99Mp06dGDVqFDNnzuTjjz+O4zfMLkr+IlKrw4cP8/DDD3P66aezf/9+PvjgA2677TbatGlzYsFJk744AdQ1SpfZF4k/xk7dmjdvzte//nXuuOMO3n77bUpKShg7dixvvvkmQ4YMYcCAAfziF7/glVde4fDhiIMGCqr2EZEo3J3nn3+eqVOncsYZZ3DfffcxYMCAuldcuTLoq2fRoiDJh/f5k5sbdOdw6aVBf/51XPHH6tixY6xater4vYJ169bxrW9963gVUZ8+fRK6v6ZIdf4i0mB//vOfmTx5MpWVlTz44IOcf/75sW9k166gy4a1a4MHuDp0gIEDYcIEaKQxuvfs2cPLL79MUVERixcvJj8///iJ4LzzziMnJyfxO40wghmDBsE11zTK763kLyIxW79+PTfeeCOrV6/m3nvv5fvf/z7NmmVG7fCxY8d45513jn8reP/990/4VtC3b9/4dlDLCGbHv/GMGJH0EcyU/EWk3kpLS7nzzjt5/vnnueGGG7j++utpXe3BrUyzZ88eli5devxbQYcOHU74VhDT7181kE15ecTeTY8zC04EDbjXUV9q7SMJ8eyzz1JQUEDbtm3p1q0bI0aM4C9/+Uuqw5IEOXjwIPfeey8DBgygZcuWfPjhh0yZMiXjEz9Afn4+48aN46mnnmLHjh3MnTuX/Px87rzzTjp37szIkSP57W9/y+bNm2vfUPgIZqHE/xkwGmgDnAI8W1U2fASzVA9h6e5N8nXWWWe5pNZDDz3knTp18vnz5/uBAwf8yJEjvnDhQp88eXKqQ5M4VVZW+pNPPuk9e/b0K664wktKSlIdUpOyZ88enzdvnl999dXepUsX79+/v//85z/3xYsXe3l5+RcFV6xwz8tzD9L68dc48LHg+8H/DH4S+PvVynhenntxccJjB1Z6PXKsqn0g5TdomqKysjJ69OjBk08+yRVXXJHqcCSBXn75ZaZMmULbtm158MEHGTp0aKpDatKOHTvG6tWrj98rWLNmDeeeey4jRoxgwsKFtH3llROqev4OdADeB/qH5l0F9ACmh284wpPNiVDfap+UX+FHezXKlf+KFe6jR7u3bh28ws/KubnBvNGjg3JZpqioyJs3b+4VFRWpDkUS5L333vOLL77YTzvtNJ8/f74fO3Ys1SGlpc8++8yfe+45v/573/Py6lfz4O+A51ab9wD4yAhlvXVr99LShMZHPa/8s7fOf8aM4HH0wsLgrnz1wSjKy4N5hYVBuVTXzzWyPXv20LFjx+DpTUlr27dv54c//CEXXXQRI0eO5IMPPmDMmDFYXQ9iSUQdOnRg7Nix/L9/+AdyItwbOQCcVG1ee2B/pI2lcASz7Ez+EW7QRNWUbtA0ovz8fHbv3k1lZWWqQ5EG2r9/P7feeiuDBg2iS5cubNiwgeuvv1794CTKmjVYhBHM2hIMYRnuc6BdpG2kcASz7Ev+xcVfJP4wVwLdCM7Y/YHHq69XdQLIkuanQ4cOJScnh8LCwlSHIjGqqKhgxowZ9O/fn61bt/Luu+8ybdo02kcYdEXiEGEEMwjyRyWwMWzee8AZ0baTohHMEpL8zWy4ma03sxIzuynC8hwzey60/G0z65OI/TbItGknPm4eMpVg5KHPgYXArcCq6oXKy4P1s0D79u256667uO666ygsLOTgwYNUVFRQVFTEDTfckOrwJAJ3Z8GCBQwcOJD58+ezaNEi5syZQ+/eveteWWIX5WTaBhhDMHj934E3gQUEN30j6tAhCcHVQ31uDNT2ApoTDNpzKtCK4CQ3oFqZnwEzQ+/HAc/Vtd2k3PDdubPmjd0Irw/Bu4I/10g3aJqyZ555xs866yzPy8vzLl26+KWXXupvvvlmqsOSalasWOHnnXeen3HGGb5o0SLdzG0M990XNZ/sAR8FngfeC3xutHyTm+t+//0JDYt63vBNRPIfCiwJm54KTK1WZgkwNPS+BbCb0NPF0V5JSf61/LEcfFLoLj3gZ4ba6DbGHyuldu4Mjsv48e4jRwY/77svq05w6Wzz5s0+btw47969uz/22GNqndWY6nkxWesrzVv79AA+CZveFpoXsYy7VwJlQH4C9h2bNWtqtuoJ8zuCO/J/JvjaFrHLpxTeoEmo4mIYMwZOOQVuvx3mzoX/+Z/g5x13QO/ewfLi4lRHKhHU2re+NI7OnYO+ehraasos6N00Rc8SNakbvmY20cxWmtnKXbt2JX4HUW7QhGsOfJPgDBatbc++jz5i586dHDt2LIHBNSI1c01b4X3rHzhwIHrf+tI4pk4N+uppiNzcYP0UScRlwnYgfEDNnqF5kcpsM7MWBM1e91TfkLvPAmZB8IRvAmI7UQytHSoJbmRE8pf33+ear32N/fv306NHD3r37k2vXr1OeFXNa9++fdNqTx3ezLUu4c1cIWkdUUnd3E/sW/+1116rX9/6klxVI5jV93+qSj1HMEumRCT/YqCfmfUlSPLjgH+pVmYhcDWwHPgu8KdQ3VTjGjQoeJS62pVuKfAnYCSQC7wC/HfoVUNuLiOnTmXXlCkcPHiQbdu28cknnxx/vfPOOxQWFh6fdvcaJ4Tw6Z49e5IX69B3DRWlmSvAPOBOYCvQFZgNnFu1sOoEMGRISj+s2aqqb/2jR4/yxBNPMGzYsFSHJOGqLoqaSK+e9ZWQvn3M7FLgPwlqTZ5w93vN7C6CGw8Lzaw18DRwJkGHd+Pcvdau8pLSt09paVDHXS357yI4I70HHCPohe/fgB9H2kbr1rB1a73r6crKyti6desJJ4jw6W3bttG2bdtaTxDdu3enZcuW8fzmgTFjgqqcan/zpcC1wHPA2cCO0PwTbtwkqR8SiS68b/1f/epXjBs3LmP61s9IKRzBLJz6848mSgKslyQkQHdn165dtZ4gdu7cSadOnaKeIHr16kWXLl1qTwxRTnwA/wj8KPSqVYwnPmmYbOxbP6OkeASz+ib/7GsaMHUqLFkSW/1clSTcoDEzOnfuTOfOnSmIcjVQWVnJp59+esLJYfPmzbz22mvHp6t64Yx036FXr170e+klcoHqdx+OAiuBy4DTgEPA5cADBFVg1YINPtRTpiTwCDRdzz77LA8//DAffvgh7dq1Y/Dgwdxyyy1885vfTMr+Dh48yCOPPMIjjzzCVVddxYcffkh+fuM3ipM4deqUFv8j2Zf80/AGTYsWLejdu3etT2qWl5fXuP/w7rvvsnDhQj755BNuXb+ecRH66dkJVAAvEjRxbQmMAu4B7q25k8xo5loPDz/8MNOnT2fmzJlccskltGrVisWLF7NgwYKEJ/+jR4/y9NNP88tf/pKhQ4fy9ttv8+Uvfzmh+xCpoT4PA6TilfQunX/3u2AwBbPaH8IwC8r97nfJjSfZRo6M+Pt9FnqobXbYvBfBB0c7HiNHpvo3Sbp9+/Z5mzZt/Pnnn0/6vpYsWeKDBg3yc845x5cvX570/Unmo54PeWXflX+VSZOCbwFN4AZNo4jSzLUDQdvc8Oqg2hqmLlmxgheuvZbTTjvt+OvLX/4y7dpF7LMwLS1fvpxDhw4xevTopO1jzZo1TJkyhS1btjB9+nRGjx7dtJoES8bL3uQPQUKfPz/lN2gaRZRmrgDXAL8GhhNU+zxC0Oy1umOtW3PqqFEMOessSkpKePvttykpKWHTpk2cdNJJJ5wQwl8nn3xyUn+1RKt1LIM4R33bvn07v/zlL1m0aBG33norP/nJTxLTkkskRtnX2idb1dLapwL4OcEg062BscD9ofcniNLax93ZsWMHJSUlNV4bN24kJycn6okhPz+/yV3xLl68mJEjR3Lo0KEvTgDFxcG3xKKiYDr8OFZ9SxwxIviWOGRIjW3u37+f++67jxkzZjBx4kRuuukmdbEsSaGmnlJTCpq5eqgpa7QTg7tHPTF06dIlJSeGsrIyunfvzlNPPcV3v/vdL56KbsADPBUVFTz++OPcddddXHzxxdxzzz306tUr+jZE4qTkLzUVFwd99TSkmWteHrz+esLvfXz22WcRTwwlJSUcPHgw6omhe/fuSX3g6aGHHuL+++/n0csv5+Knn6ZleTmvAMsIvhXVKi8Pf/BBFnbvzo033kjPnj154IEHOPPMM5MWr0gVJX+JLJa+fapUNXNt5MfRy8rK2LRpU8QTw759+zj11FMjnhh69epF8+bN497/3Lvv5pE77uCvx47RDjgLuAW4GXiLL26Y9QDWV1v3ULNmXN23LxN+/WuGDx/e5Kq2JHMp+Ut0cVRjNBUHDhxg8+bNEU8MpaWl9OnTJ+KJ4ZRTTqn/DdYo1WTDCIb9vLaWVY+ZweWX0+wPf2jgbyjSMEr+Ursm0g9JMpSXl7Nly5aIJ4ZPP/2Unj17Rjwx9O3bl5yc0CgOtdwgH0bdyR9QdxiSEkr+Uj/Z0Mw1zJEjR/joo48inhi2bt1K165dOe2005h04ACXrVpFywhPRQ8DPiB4Ou50giehh0XaWW4u3HlnWjzqL5lDfftI/aRJPySJ0qpVK/r370///v1rLKusrGTr1q2UlJRwyq23Rkz8APcBAwgGrJ4HfAdYDdTokCGLusOQ9KP+YUVCWrRowamnnsrFF1/M6V26RC33daAdwTCfVwPnAIuiFd67N9FhiiSEkr9IJDE8gGUEVUARdeiQiGhEEk7JXySSQYOCG7bV7AOWEHR9XQnMBd4g6Bqjhtzc4P6JSBOk5C8SyYQJEWdXALcCnYCOBH0iFQI17yAQtJiKsh2RVFPyF4mkc+egr55qD2d1Ihi0ej/Bt4C3gIsirW8WNJXNwBZTkhmU/EWimTo1qLppiCSM+iaSSEr+ItFUjfqWlxfbeikc9U2kvtTOX6Q2Vd1apHl3GCLV6cpfpC6TJgU9mo4eHbQAql4VlJsbzB89OiinxC9pQFf+IvVRbdS3ebfeypjzz6dV584Z3R2GZC717SPSAG3btmXnzp20adMm1aGInKC+ffuo2kekAY4cOUKrVq1SHYZIgyn5i8TI3amsrIw8wLtImogr+ZvZl8xsqZltDP2s0ZGJmQ02s+Vm9oGZrTGz78WzT5FUq6iooEWLFhqdS9JavFf+NwGvuns/4NXQdHUHgR+4+xkEXaD8p5mdHOd+RVJGVT6SCeJN/qOAp0LvnwIur17A3Te4+8bQ+0+BUoKn5EXSkpK/ZIJ4k38Xd98Rev83IHon6ICZnU0wBsamOPcrkjJK/pIJ6rxjZWavAF0jLLolfMLd3cyiths1s27A08DV7n4sSpmJwESA3r171xWaSEpUVFQo+UvaqzP5u/uF0ZaZ2U4z6+buO0LJvTRKuZOA/wVucfe3atnXLGAWBO3864pNJBV05S+ZIN5qn4UEI9kR+rmgegEzawW8BMxx9xfj3J9Iyin5SyaIN/lPBy4ys43AhaFpzKzAzB4PlRkLnAdMMLPVodfgOPcrkjJK/pIJ4npKxd33ABdEmL8SuDb0/hngmXj2I9KUKPlLJtATviIxOnLkCC1btkx1GCJxUfIXiZGu/CUTKPmLxEjJXzKBkr9IjJT8JRMo+YvESMlfMoGSv0iM9ISvZAIlf5EY6cpfMoGSv0iMlPwlEyj5i8RI7fwlEyj5i8RIV/6SCZT8RWKk5C+ZQMlfJEZK/pIJlPxFYqTkL5lAyV8kRkr+kgmU/EVipOQvmUDJXyRGesJXMoGSv0iMdOUvmUDJXyRGeshLMoGSv0iMdOUvmUDJXyRGSv6SCZT8RWKk5C+ZQMlfJEZK/pIJlPxFYqTkL5lAyV8kRkr+kgmU/EVipOQvmUDJXyRGesJXMkFcyd/MvmRmS81sY+hnh1rKnmRm28zsN/HsUyTV9JCXZIJ4r/xvAl51937Aq6HpaO4G3ohzfyIpp2ofyQTxJv9RwFOh908Bl0cqZGZnAV2Al+Pcn0jKKflLJog3+Xdx9x2h938jSPAnMLNmwEPA5Lo2ZmYTzWylma3ctWtXnKGJJIeSv2SCFnUVMLNXgK4RFt0SPuHubmYeodzPgEXuvs3Mat2Xu88CZgEUFBRE2pZIyin5SyaoM/m7+4XRlpnZTjPr5u47zKwbUBqh2FDgXDP7GdAWaGVmB9y9tvsDIk2Wkr9kgjqTfx0WAlcD00M/F1Qv4O7jq96b2QSgQIlf0pmSv2SCeOv8pwMXmdlG4MLQNGZWYGaPxxucSFPj7mrqKRkhrit/d98DXBBh/krg2gjzZwOz49mnSCodPXqUZs2a0bx581SHIhIXPeErEoOKigpd9UtGUPIXiYHq+yVTKPmLxEDJXzKFkr9IDJT8JVMo+YvEQMlfMoWSv0gMlPwlU8T7kJdIdigthdmz6fzGGzz66adw5ZUwaBBccw106pTq6ERiZu5NswudgoICX7lyZarDkGxXXAzTpkFRUTB96NAXy3JzwR1GjICpU2HIkNTEKBLGzFa5e0Fd5VTtIxLNjBkwbBgUFgZJPzzxA5SXB/MKC4NyM2akIkqRBlG1j0gkM2bA5Mlw8GDdZd2DcpNDvZZPmpSE88wLAAAJnUlEQVTc2EQSQFf+ItUVF9dI/IeBHwGnAO2AwUBR9fWqTgCqrpQ0oOQvUt20aUGVTphKoBfwOlAG3AOMBT6qvm55ebC+SBOn5C8SrrQ0uLlbrSFEG+AOoA/BP81IoC+wqvr67rBoEWgkOmnilPxFws2eXa9iO4ENwBmRFprVezsiqaLkLxJuzZqarXqqqQDGE4xe9JVIBcrLYe3axMcmkkBK/iLhyspqXXwMuApoBfymtoJ79yYuJpEkUFNPkXDt20dd5AQtfnYCi4Bae/Xv0CGhYYkkmq78RcINGgStW0dcNAn4K/BHILe2beTmwsCBiY9NJIGU/EXCTZgQcfbHwKPAaqAr0Db0mhupsHvU7Yg0FUr+IuE6dw766jE7YfYpBNU+h4ADYa/x1dc3g0svVWdv0uQp+UvWmT17NgMHDiQvL4+uXbsyadIk9u3b90WBqVODqpuGyM0N1hdp4pT8Jas89NBD3HjjjTzwwAOUlZXx1ltv8fHHH3PRRRdx5MiRoNCQIfDgg5CXF9vG8/KC9Qrq7FBRJOWU/CVrfP7559x+++38+te/Zvjw4bRs2ZI+ffrw/PPP89FHH/HMM898UXjSpC9OANWqgGow+yLxq1M3SRNK/pI1/u///o9Dhw4xZsyYE+a3bduWSy+9lKVLl564wqRJ8PrrMHp00AKoelVQbm4wf/TooJwSv6QRtfOXrLF79246duxIixY1P/bdunVj1aoaPfUEVTjz5wd99cyeHTy5u3dv0I5/4MCgVY9u7koaUvKXrNGxY0d2795NZWVljRPAjh076NixY/SVO3WCKVOSHKFI44mr2sfMvmRmS81sY+hnxMcazay3mb1sZn81s3Vm1iee/Yo0xNChQ8nJyeEPf/jDCfMPHDhAUVERF1xwQYoiE2l88db53wS86u79gFdD05HMAR5w968CZwOlce5XJGbt27fn9ttv5/rrr2fx4sVUVFTw0UcfMXbsWHr27MlVV12V6hBFGk281T6jgGGh908BrwE3hhcwswFAC3dfCuDuB+Lcp0iD3XDDDeTn5zN58mQ2bdrESSedxOWXX87cuXPJyclJdXgijca82qAVMa1sts/dTw69N2Bv1XRYmcuBa4EjBONfvALc5O5HI2xvIjARoHfv3md9/PHHDY5NRCQbmdkqd6/zYZM6r/zN7BWC7kyquyV8wt3dzCKdSVoA5wJnAluB54AJwO+rF3T3WcAsgIKCgoaflUREpFZ1Jn93vzDaMjPbaWbd3H2HmXUjcl3+NmC1u28OrVMIfIMIyV9ERBpHvDd8FxIMaETo54IIZYqBk82sqjH0PwHr4tyviIjEId7kPx24yMw2AheGpjGzAjN7HCBUtz8ZeNXM1gIGPBbnfkVEJA5x3fBNJjPbRdCNemPrCOxOwX7rorhi01TjgqYbm+KKXVOM7RR3r/Ox8yab/FPFzFbW5055Y1NcsWmqcUHTjU1xxa4px1YXdewmIpKFlPxFRLKQkn9Ns1IdQBSKKzZNNS5ourEprtg15dhqpTp/EZEspCt/EZEslHXJ38yuMLMPzOyYmUW9S29mw81svZmVmNlNYfP7mtnbofnPmVmrBMZWZxfZZna+ma0Oex0K9Z+Emc02sy1hywY3VlyhckfD9r0wbH5Sjlk9j9dgM1se+puvMbPvhS1L6PGK9pkJW54T+v1LQsejT9iyqaH5683sknjiaEBc/xHqan2Nmb1qZqeELYv4N23E2CaY2a6wGK4NW3Z16G+/0cyurr5ukuN6JCymDWa2L2xZUo9Zwrh7Vr2ArwKnE/RAWhClTHNgE3Aq0Ap4DxgQWvY8MC70fiYwKYGx3U/Q6R0E3WPfV0f5LwGfAXmh6dnAd5NwzOoVF3AgyvykHLP6xAX0B/qF3ncHdgAnJ/p41faZCSvzM2Bm6P044LnQ+wGh8jkEnR9uApo3Ylznh32GJlXFVdvftBFjmwD8JsK6XwI2h352CL3v0FhxVSt/PfBEYxyzRL6y7srf3f/q7uvrKHY2UOLum939CDAPGGVmRtA9xYuhck8BlycwvFGhbdZ3298Fitz9YAJjiCTWuI5L8jGrMy533+DuG0PvPyXofyoZ4y5G/MzUEu+LwAWh4zMKmOfuh919C1AS2l6jxOXuy8I+Q28BPRO077hjq8UlwFJ3/8zd9wJLgeEpiuv7wH8naN+NJuuSfz31AD4Jm94WmpcP7HP3ymrzE6WLu+8Ivf8b0KWO8uOo+aG7N/T1/REzS1QH9fWNq7WZrTSzt6qqokjuMYvpeJnZ2QRXcpvCZifqeEX7zEQsEzoeZQTHpz7rJjOucD8CisKmI/1NE6W+sf1z6G/0opn1inHdZMZFqIqsL/CnsNnJPGYJk5Fj+Fot3VC7e6TO5xpNbbGFT7hH7SK7ajvdgIHAkrDZUwmSYCuCJmg3Anc1YlynuPt2MzsV+JMFfTmV1Wf/SY6r6ng9DVzt7sdCsxt8vDKRmV0JFADfCptd42/q7psibyEp/gj8t7sfNrOfEHxz+qdG3H9dxgEv+onjk6T6mNVLRiZ/r6Ub6nraDvQKm+4ZmreHoIfSFqErt6r5CYnN6tdFdpWxwEvuXhG27aqr4MNm9iRBh3qNFpe7bw/93GxmrxGM4TCfOI5ZIuIys5OA/yU4+b8Vtu0GH68Ion1mIpXZZmYtgPYEn6n6rJvMuDCzCwlOqN9y98NV86P8TROVyOqMzd33hE0+TnCfp2rdYdXWfa2x4gozDrgufEaSj1nCqNonsmKgnwWtVFoR/IEXenA3ZxlBXTtE78a6oerTRXaVGvWMoQRYVc9+OfB+Y8VlZh2qqk3MrCNwDrAuycesPnG1Al4C5rj7i9WWJfJ4RfzM1BLvd4E/hY7PQmBcqDVQX6AfsCKOWGKKy8zOBB4FLnP30rD5Ef+mCYqrvrF1C5u8DPhr6P0S4OJQjB2AiznxW3BS4wrF9hWCm83Lw+Yl+5glTqrvODf2CxhNUId3GNgJLAnN7w4sCit3KbCB4Ix9S9j8Uwn+MUuAF4CcBMaWD7wKbCQY7vJLofkFwONh5foQXIk0q7b+n4C1BEnsGaBtY8UF/GNo3++Ffv4o2cesnnFdCVQAq8Neg5NxvCJ9ZgiqkS4LvW8d+v1LQsfj1LB1bwmttx4YkeDPfF1xvRL6X6g6Pgvr+ps2YmzTgA9CMSwDvhK27g9Dx7IEuKYx4wpN3wFMr7Ze0o9Zol56wldEJAup2kdEJAsp+YuIZCElfxGRLKTkLyKShZT8RUSykJK/iEgWUvIXEclCSv4iIlno/wNHn92ZBgkRVQAAAABJRU5ErkJggg==\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": 20,
- "metadata": {
- "scrolled": false
- },
- "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",
- "all_labels_ori: {'C', 'O'}\n",
- "num_of_each_label: {'C': 5, 'O': 2}\n",
- "all_num_of_each_label: [{'C': 5, 'O': 2}]\n",
- "num_of_labels: 2\n",
- "all_labels_ori: {'C', 'O'}\n",
- "\n",
- " --- for graph 1 --- \n",
- "\n",
- "labels_ori: ['C', 'C', 'C', 'C', 'C', 'C', 'S', 'S']\n",
- "all_labels_ori: {'C', 'O', 'S'}\n",
- "num_of_each_label: {'C': 6, 'S': 2}\n",
- "all_num_of_each_label: [{'C': 5, 'O': 2}, {'C': 6, 'S': 2}]\n",
- "num_of_labels: 2\n",
- "all_labels_ori: {'C', 'O', 'S'}\n",
- "\n",
- " all_num_of_labels_occured: 3\n",
- "\n",
- " --- calculating kernel matrix ---\n",
- "\n",
- " labels: {'C', 'O'}\n",
- "vector1: [[5 2]]\n",
- "vector2: [[5 2]]\n",
- "Kmatrix: [[ 29. 0.]\n",
- " [ 0. 0.]]\n",
- "\n",
- " labels: {'C', 'O', 'S'}\n",
- "vector1: [[5 2 0]]\n",
- "vector2: [[6 0 2]]\n",
- "Kmatrix: [[ 29. 30.]\n",
- " [ 30. 0.]]\n",
- "\n",
- " labels: {'C', 'S'}\n",
- "vector1: [[6 2]]\n",
- "vector2: [[6 2]]\n",
- "Kmatrix: [[ 29. 30.]\n",
- " [ 30. 40.]]\n",
- "\n",
- " --- height = 1 --- \n",
- "\n",
- " --- for graph 0 --- \n",
- "\n",
- "multiset: ['CC', 'CC', 'CCO', 'CCO', 'COO', 'OCC', 'OCC']\n",
- "set_unique: ['OCC', 'COO', 'CCO', 'CC']\n",
- "set_compressed: {'OCC': '4', 'COO': '5', 'CCO': '6', 'CC': '7'}\n",
- "all_set_compressed: {'OCC': '4', 'COO': '5', 'CCO': '6', 'CC': '7'}\n",
- "num_of_labels_occured: 7\n",
- "\n",
- " compressed labels: {0: '7', 1: '7', 2: '6', 3: '6', 4: '5', 5: '4', 6: '4'}\n",
- "labels_comp: ['7', '7', '6', '6', '5', '4', '4']\n",
- "all_labels_ori: {'5', '4', '6', '7'}\n",
- "num_of_each_label: {'5': 1, '4': 2, '6': 2, '7': 2}\n",
- "all_num_of_each_label: [{'5': 1, '4': 2, '6': 2, '7': 2}]\n",
- "\n",
- " --- for graph 1 --- \n",
- "\n",
- "multiset: ['CC', 'CC', 'CC', 'CCS', 'CCS', 'CCSS', 'SCC', 'SCC']\n",
- "set_unique: ['SCC', 'CC', 'CCS', 'CCSS']\n",
- "set_compressed: {'SCC': '8', 'CC': '7', 'CCS': '9', 'CCSS': '10'}\n",
- "all_set_compressed: {'SCC': '8', 'COO': '5', 'CCS': '9', 'OCC': '4', 'CCO': '6', 'CCSS': '10', 'CC': '7'}\n",
- "num_of_labels_occured: 10\n",
- "\n",
- " compressed labels: {0: '7', 1: '7', 2: '7', 3: '9', 4: '9', 5: '10', 6: '8', 7: '8'}\n",
- "labels_comp: ['7', '7', '7', '9', '9', '10', '8', '8']\n",
- "all_labels_ori: {'10', '4', '7', '9', '6', '5', '8'}\n",
- "num_of_each_label: {'10': 1, '9': 2, '7': 3, '8': 2}\n",
- "all_num_of_each_label: [{'5': 1, '4': 2, '6': 2, '7': 2}, {'10': 1, '9': 2, '7': 3, '8': 2}]\n",
- "\n",
- " all_num_of_labels_occured: 10\n",
- "\n",
- " --- calculating kernel matrix ---\n",
- "\n",
- " labels: {'5', '4', '6', '7'}\n",
- "vector1: [[1 2 2 2]]\n",
- "vector2: [[1 2 2 2]]\n",
- "\n",
- " labels: {'10', '4', '7', '9', '6', '5', '8'}\n",
- "vector1: [[0 2 2 0 2 1 0]]\n",
- "vector2: [[1 0 3 2 0 0 2]]\n",
- "\n",
- " labels: {'8', '10', '7', '9'}\n",
- "vector1: [[2 1 3 2]]\n",
- "vector2: [[2 1 3 2]]\n",
- "\n",
- " Kmatrix: [[ 42. 36.]\n",
- " [ 36. 58.]]\n",
- "\n",
- " --- height = 2 --- \n",
- "\n",
- " --- for graph 0 --- \n",
- "\n",
- "multiset: ['76', '76', '647', '647', '544', '456', '456']\n",
- "set_unique: ['647', '76', '456', '544']\n",
- "set_compressed: {'647': '11', '76': '12', '544': '14', '456': '13'}\n",
- "all_set_compressed: {'647': '11', '76': '12', '456': '13', '544': '14'}\n",
- "num_of_labels_occured: 14\n",
- "\n",
- " compressed labels: {0: '12', 1: '12', 2: '11', 3: '11', 4: '14', 5: '13', 6: '13'}\n",
- "labels_comp: ['12', '12', '11', '11', '14', '13', '13']\n",
- "all_labels_ori: {'14', '12', '11', '13'}\n",
- "num_of_each_label: {'14': 1, '13': 2, '12': 2, '11': 2}\n",
- "all_num_of_each_label: [{'14': 1, '13': 2, '12': 2, '11': 2}]\n",
- "\n",
- " --- for graph 1 --- \n",
- "\n",
- "multiset: ['79', '79', '710', '978', '978', '10788', '8109', '8109']\n",
- "set_unique: ['710', '8109', '79', '10788', '978']\n",
- "set_compressed: {'710': '15', '79': '17', '8109': '16', '978': '19', '10788': '18'}\n",
- "all_set_compressed: {'710': '15', '79': '17', '978': '19', '10788': '18', '8109': '16', '456': '13', '544': '14', '647': '11', '76': '12'}\n",
- "num_of_labels_occured: 19\n",
- "\n",
- " compressed labels: {0: '17', 1: '17', 2: '15', 3: '19', 4: '19', 5: '18', 6: '16', 7: '16'}\n",
- "labels_comp: ['17', '17', '15', '19', '19', '18', '16', '16']\n",
- "all_labels_ori: {'18', '19', '12', '13', '17', '11', '14', '16', '15'}\n",
- "num_of_each_label: {'15': 1, '17': 2, '19': 2, '16': 2, '18': 1}\n",
- "all_num_of_each_label: [{'14': 1, '13': 2, '12': 2, '11': 2}, {'15': 1, '17': 2, '19': 2, '16': 2, '18': 1}]\n",
- "\n",
- " all_num_of_labels_occured: 19\n",
- "\n",
- " --- calculating kernel matrix ---\n",
- "\n",
- " labels: {'14', '12', '11', '13'}\n",
- "vector1: [[1 2 2 2]]\n",
- "vector2: [[1 2 2 2]]\n",
- "\n",
- " labels: {'18', '19', '12', '13', '17', '11', '14', '16', '15'}\n",
- "vector1: [[0 0 2 2 0 2 1 0 0]]\n",
- "vector2: [[1 2 0 0 2 0 0 2 1]]\n",
- "\n",
- " labels: {'18', '17', '15', '16', '19'}\n",
- "vector1: [[1 2 1 2 2]]\n",
- "vector2: [[1 2 1 2 2]]\n",
- "\n",
- " Kmatrix: [[ 55. 36.]\n",
- " [ 36. 72.]]\n",
- "\n",
- " --- Weisfeiler-Lehman subtree kernel built in 0.0034377574920654297 seconds ---\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- "array([[ 55., 36.],\n",
- " [ 36., 72.]])"
- ]
- },
- "execution_count": 20,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "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",
- " all_labels_ori.update(labels_ori)\n",
- " print('all_labels_ori: %s' % (all_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",
- " all_num_of_labels_occured += len(all_labels_ori)\n",
- " print('\\n all_num_of_labels_occured: %s' % (all_num_of_labels_occured))\n",
- " \n",
- " # calculate subtree kernel with the 0th iteration and add it to the final kernel\n",
- " print('\\n --- calculating kernel matrix ---')\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('vector1: %s' % (vector1))\n",
- " print('vector2: %s' % (vector2))\n",
- " Kmatrix[i][j] += np.dot(vector1, vector2.transpose())\n",
- " Kmatrix[j][i] = Kmatrix[i][j]\n",
- " print('Kmatrix: %s' % (Kmatrix))\n",
- "\n",
- " \n",
- " # iterate each height\n",
- " for h in range(1, height + 1):\n",
- " print('\\n --- height = %d --- ' % (h))\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",
- " all_labels_ori = set()\n",
- " all_num_of_each_label = []\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",
- " # 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",
- " all_labels_ori.update(labels_comp)\n",
- " print('all_labels_ori: %s' % (all_labels_ori))\n",
- " num_of_each_label = 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",
- " all_num_of_labels_occured += len(all_labels_ori)\n",
- " print('\\n all_num_of_labels_occured: %s' % (all_num_of_labels_occured))\n",
- " \n",
- " # calculate subtree kernel with h iterations and add it to the final kernel\n",
- " print('\\n --- calculating kernel matrix ---')\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('vector1: %s' % (vector1))\n",
- " print('vector2: %s' % (vector2))\n",
- " Kmatrix[i][j] += np.dot(vector1, vector2.transpose())\n",
- " Kmatrix[j][i] = Kmatrix[i][j]\n",
- " \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 = 2)\n",
- "# Kmatrix = weisfeilerlehmankernel(G1, G2)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "185"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "\n",
- "len(dataset)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "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"
- ]
- },
- {
- "ename": "KeyboardInterrupt",
- "evalue": "",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)",
- "\u001b[0;32m<ipython-input-1-2ce8cff340bc>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 82\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 83\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'\\n Calculating kernel matrix, this could take a while...'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 84\u001b[0;31m \u001b[0mKmatrix\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mweisfeilerlehmankernel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdataset\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mheight\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mheight\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbase_kernel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'sp'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 85\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mKmatrix\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 86\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'\\n Saving kernel matrix to file...'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m/media/ljia/DATA/research-repo/codes/Linlin/py-graph/pygraph/kernels/weisfeilerLehmanKernel.py\u001b[0m in \u001b[0;36mweisfeilerlehmankernel\u001b[0;34m(height, base_kernel, *args)\u001b[0m\n\u001b[1;32m 71\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mGn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 72\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mGn\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 73\u001b[0;31m \u001b[0mKmatrix\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_weisfeilerlehmankernel_do\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mGn\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mGn\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\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[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 74\u001b[0m \u001b[0mKmatrix\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mKmatrix\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 75\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m/media/ljia/DATA/research-repo/codes/Linlin/py-graph/pygraph/kernels/weisfeilerLehmanKernel.py\u001b[0m in \u001b[0;36m_weisfeilerlehmankernel_do\u001b[0;34m(G1, G2, height)\u001b[0m\n\u001b[1;32m 241\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 242\u001b[0m \u001b[0;31m# calculate kernel\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 243\u001b[0;31m \u001b[0mkernel\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mspkernel\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[0;31m# change your base kernel here (and one more before)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 244\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 245\u001b[0m \u001b[0;31m# get label sets of both graphs\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;32m/media/ljia/DATA/research-repo/codes/Linlin/py-graph/pygraph/kernels/spkernel.py\u001b[0m in \u001b[0;36mspkernel\u001b[0;34m(*args)\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0me1\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mG1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0medges\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0me2\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mG2\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0medges\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 64\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0me1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'cost'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0;36m0\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0me1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'cost'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0me2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'cost'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0me2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0me1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0me2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0me1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0me2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0me1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0me2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 65\u001b[0m \u001b[0mkernel\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 66\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
- "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
- ]
- }
- ],
- "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, node_label = 'atom', 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_train = []\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
- }
|