You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

dataset.py 27 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. Created on Thu Mar 26 18:48:27 2020
  5. @author: ljia
  6. """
  7. import numpy as np
  8. import networkx as nx
  9. from gklearn.utils.graph_files import load_dataset
  10. import os
  11. class Dataset(object):
  12. def __init__(self, filename=None, filename_targets=None, **kwargs):
  13. if filename is None:
  14. self.__graphs = None
  15. self.__targets = None
  16. self.__node_labels = None
  17. self.__edge_labels = None
  18. self.__node_attrs = None
  19. self.__edge_attrs = None
  20. else:
  21. self.load_dataset(filename, filename_targets=filename_targets, **kwargs)
  22. self.__substructures = None
  23. self.__node_label_dim = None
  24. self.__edge_label_dim = None
  25. self.__directed = None
  26. self.__dataset_size = None
  27. self.__total_node_num = None
  28. self.__ave_node_num = None
  29. self.__min_node_num = None
  30. self.__max_node_num = None
  31. self.__total_edge_num = None
  32. self.__ave_edge_num = None
  33. self.__min_edge_num = None
  34. self.__max_edge_num = None
  35. self.__ave_node_degree = None
  36. self.__min_node_degree = None
  37. self.__max_node_degree = None
  38. self.__ave_fill_factor = None
  39. self.__min_fill_factor = None
  40. self.__max_fill_factor = None
  41. self.__node_label_nums = None
  42. self.__edge_label_nums = None
  43. self.__node_attr_dim = None
  44. self.__edge_attr_dim = None
  45. self.__class_number = None
  46. def load_dataset(self, filename, filename_targets=None, **kwargs):
  47. self.__graphs, self.__targets, label_names = load_dataset(filename, filename_targets=filename_targets, **kwargs)
  48. self.__node_labels = label_names['node_labels']
  49. self.__node_attrs = label_names['node_attrs']
  50. self.__edge_labels = label_names['edge_labels']
  51. self.__edge_attrs = label_names['edge_attrs']
  52. self.clean_labels()
  53. def load_graphs(self, graphs, targets=None):
  54. # this has to be followed by set_labels().
  55. self.__graphs = graphs
  56. self.__targets = targets
  57. # self.set_labels_attrs() # @todo
  58. def load_predefined_dataset(self, ds_name):
  59. current_path = os.path.dirname(os.path.realpath(__file__)) + '/'
  60. if ds_name == 'Acyclic':
  61. ds_file = current_path + '../../datasets/Acyclic/dataset_bps.ds'
  62. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  63. elif ds_name == 'AIDS':
  64. ds_file = current_path + '../../datasets/AIDS/AIDS_A.txt'
  65. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  66. elif ds_name == 'Alkane':
  67. ds_file = current_path + '../../datasets/Alkane/dataset.ds'
  68. fn_targets = current_path + '../../datasets/Alkane/dataset_boiling_point_names.txt'
  69. self.__graphs, self.__targets, label_names = load_dataset(ds_file, filename_targets=fn_targets)
  70. elif ds_name == 'COIL-DEL':
  71. ds_file = current_path + '../../datasets/COIL-DEL/COIL-DEL_A.txt'
  72. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  73. elif ds_name == 'COIL-RAG':
  74. ds_file = current_path + '../../datasets/COIL-RAG/COIL-RAG_A.txt'
  75. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  76. elif ds_name == 'COLORS-3':
  77. ds_file = current_path + '../../datasets/COLORS-3/COLORS-3_A.txt'
  78. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  79. elif ds_name == 'Cuneiform':
  80. ds_file = current_path + '../../datasets/Cuneiform/Cuneiform_A.txt'
  81. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  82. elif ds_name == 'DD':
  83. ds_file = current_path + '../../datasets/DD/DD_A.txt'
  84. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  85. elif ds_name == 'ENZYMES':
  86. ds_file = current_path + '../../datasets/ENZYMES_txt/ENZYMES_A_sparse.txt'
  87. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  88. elif ds_name == 'Fingerprint':
  89. ds_file = current_path + '../../datasets/Fingerprint/Fingerprint_A.txt'
  90. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  91. elif ds_name == 'FRANKENSTEIN':
  92. ds_file = current_path + '../../datasets/FRANKENSTEIN/FRANKENSTEIN_A.txt'
  93. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  94. elif ds_name == 'Letter-high': # node non-symb
  95. ds_file = current_path + '../../datasets/Letter-high/Letter-high_A.txt'
  96. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  97. elif ds_name == 'Letter-low': # node non-symb
  98. ds_file = current_path + '../../datasets/Letter-low/Letter-low_A.txt'
  99. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  100. elif ds_name == 'Letter-med': # node non-symb
  101. ds_file = current_path + '../../datasets/Letter-med/Letter-med_A.txt'
  102. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  103. elif ds_name == 'MAO':
  104. ds_file = current_path + '../../datasets/MAO/dataset.ds'
  105. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  106. elif ds_name == 'Monoterpenoides':
  107. ds_file = current_path + '../../datasets/Monoterpenoides/dataset_10+.ds'
  108. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  109. elif ds_name == 'MUTAG':
  110. ds_file = current_path + '../../datasets/MUTAG/MUTAG_A.txt'
  111. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  112. elif ds_name == 'NCI1':
  113. ds_file = current_path + '../../datasets/NCI1/NCI1_A.txt'
  114. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  115. elif ds_name == 'NCI109':
  116. ds_file = current_path + '../../datasets/NCI109/NCI109_A.txt'
  117. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  118. elif ds_name == 'PAH':
  119. ds_file = current_path + '../../datasets/PAH/dataset.ds'
  120. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  121. elif ds_name == 'SYNTHETIC':
  122. pass
  123. elif ds_name == 'SYNTHETICnew':
  124. ds_file = current_path + '../../datasets/SYNTHETICnew/SYNTHETICnew_A.txt'
  125. self.__graphs, self.__targets, label_names = load_dataset(ds_file)
  126. elif ds_name == 'Synthie':
  127. pass
  128. else:
  129. raise Exception('The dataset name "', ds_name, '" is not pre-defined.')
  130. self.__node_labels = label_names['node_labels']
  131. self.__node_attrs = label_names['node_attrs']
  132. self.__edge_labels = label_names['edge_labels']
  133. self.__edge_attrs = label_names['edge_attrs']
  134. self.clean_labels()
  135. def set_labels(self, node_labels=[], node_attrs=[], edge_labels=[], edge_attrs=[]):
  136. self.__node_labels = node_labels
  137. self.__node_attrs = node_attrs
  138. self.__edge_labels = edge_labels
  139. self.__edge_attrs = edge_attrs
  140. def set_labels_attrs(self, node_labels=None, node_attrs=None, edge_labels=None, edge_attrs=None):
  141. # @todo: remove labels which have only one possible values.
  142. if node_labels is None:
  143. self.__node_labels = self.__graphs[0].graph['node_labels']
  144. # # graphs are considered node unlabeled if all nodes have the same label.
  145. # infos.update({'node_labeled': is_nl if node_label_num > 1 else False})
  146. if node_attrs is None:
  147. self.__node_attrs = self.__graphs[0].graph['node_attrs']
  148. # for G in Gn:
  149. # for n in G.nodes(data=True):
  150. # if 'attributes' in n[1]:
  151. # return len(n[1]['attributes'])
  152. # return 0
  153. if edge_labels is None:
  154. self.__edge_labels = self.__graphs[0].graph['edge_labels']
  155. # # graphs are considered edge unlabeled if all edges have the same label.
  156. # infos.update({'edge_labeled': is_el if edge_label_num > 1 else False})
  157. if edge_attrs is None:
  158. self.__edge_attrs = self.__graphs[0].graph['edge_attrs']
  159. # for G in Gn:
  160. # if nx.number_of_edges(G) > 0:
  161. # for e in G.edges(data=True):
  162. # if 'attributes' in e[2]:
  163. # return len(e[2]['attributes'])
  164. # return 0
  165. def get_dataset_infos(self, keys=None, params=None):
  166. """Computes and returns the structure and property information of the graph dataset.
  167. Parameters
  168. ----------
  169. keys : list, optional
  170. A list of strings which indicate which informations will be returned. The
  171. possible choices includes:
  172. 'substructures': sub-structures graphs contains, including 'linear', 'non
  173. linear' and 'cyclic'.
  174. 'node_label_dim': whether vertices have symbolic labels.
  175. 'edge_label_dim': whether egdes have symbolic labels.
  176. 'directed': whether graphs in dataset are directed.
  177. 'dataset_size': number of graphs in dataset.
  178. 'total_node_num': total number of vertices of all graphs in dataset.
  179. 'ave_node_num': average number of vertices of graphs in dataset.
  180. 'min_node_num': minimum number of vertices of graphs in dataset.
  181. 'max_node_num': maximum number of vertices of graphs in dataset.
  182. 'total_edge_num': total number of edges of all graphs in dataset.
  183. 'ave_edge_num': average number of edges of graphs in dataset.
  184. 'min_edge_num': minimum number of edges of graphs in dataset.
  185. 'max_edge_num': maximum number of edges of graphs in dataset.
  186. 'ave_node_degree': average vertex degree of graphs in dataset.
  187. 'min_node_degree': minimum vertex degree of graphs in dataset.
  188. 'max_node_degree': maximum vertex degree of graphs in dataset.
  189. 'ave_fill_factor': average fill factor (number_of_edges /
  190. (number_of_nodes ** 2)) of graphs in dataset.
  191. 'min_fill_factor': minimum fill factor of graphs in dataset.
  192. 'max_fill_factor': maximum fill factor of graphs in dataset.
  193. 'node_label_nums': list of numbers of symbolic vertex labels of graphs in dataset.
  194. 'edge_label_nums': list number of symbolic edge labels of graphs in dataset.
  195. 'node_attr_dim': number of dimensions of non-symbolic vertex labels.
  196. Extracted from the 'attributes' attribute of graph nodes.
  197. 'edge_attr_dim': number of dimensions of non-symbolic edge labels.
  198. Extracted from the 'attributes' attribute of graph edges.
  199. 'class_number': number of classes. Only available for classification problems.
  200. 'all_degree_entropy': the entropy of degree distribution of each graph.
  201. 'ave_degree_entropy': the average entropy of degree distribution of all graphs.
  202. All informations above will be returned if `keys` is not given.
  203. params: dict of dict, optional
  204. A dictinary which contains extra parameters for each possible
  205. element in ``keys``.
  206. Return
  207. ------
  208. dict
  209. Information of the graph dataset keyed by `keys`.
  210. """
  211. infos = {}
  212. if keys == None:
  213. keys = [
  214. 'substructures',
  215. 'node_label_dim',
  216. 'edge_label_dim',
  217. 'directed',
  218. 'dataset_size',
  219. 'total_node_num',
  220. 'ave_node_num',
  221. 'min_node_num',
  222. 'max_node_num',
  223. 'total_edge_num',
  224. 'ave_edge_num',
  225. 'min_edge_num',
  226. 'max_edge_num',
  227. 'ave_node_degree',
  228. 'min_node_degree',
  229. 'max_node_degree',
  230. 'ave_fill_factor',
  231. 'min_fill_factor',
  232. 'max_fill_factor',
  233. 'node_label_nums',
  234. 'edge_label_nums',
  235. 'node_attr_dim',
  236. 'edge_attr_dim',
  237. 'class_number',
  238. 'all_degree_entropy',
  239. 'ave_degree_entropy'
  240. ]
  241. # dataset size
  242. if 'dataset_size' in keys:
  243. if self.__dataset_size is None:
  244. self.__dataset_size = self.__get_dataset_size()
  245. infos['dataset_size'] = self.__dataset_size
  246. # graph node number
  247. if any(i in keys for i in ['total_node_num', 'ave_node_num', 'min_node_num', 'max_node_num']):
  248. all_node_nums = self.__get_all_node_nums()
  249. if 'total_node_num' in keys:
  250. if self.__total_node_num is None:
  251. self.__total_node_num = self.__get_total_node_num(all_node_nums)
  252. infos['total_node_num'] = self.__total_node_num
  253. if 'ave_node_num' in keys:
  254. if self.__ave_node_num is None:
  255. self.__ave_node_num = self.__get_ave_node_num(all_node_nums)
  256. infos['ave_node_num'] = self.__ave_node_num
  257. if 'min_node_num' in keys:
  258. if self.__min_node_num is None:
  259. self.__min_node_num = self.__get_min_node_num(all_node_nums)
  260. infos['min_node_num'] = self.__min_node_num
  261. if 'max_node_num' in keys:
  262. if self.__max_node_num is None:
  263. self.__max_node_num = self.__get_max_node_num(all_node_nums)
  264. infos['max_node_num'] = self.__max_node_num
  265. # graph edge number
  266. if any(i in keys for i in ['total_edge_num', 'ave_edge_num', 'min_edge_num', 'max_edge_num']):
  267. all_edge_nums = self.__get_all_edge_nums()
  268. if 'total_edge_num' in keys:
  269. if self.__total_edge_num is None:
  270. self.__total_edge_num = self.__get_total_edge_num(all_edge_nums)
  271. infos['total_edge_num'] = self.__total_edge_num
  272. if 'ave_edge_num' in keys:
  273. if self.__ave_edge_num is None:
  274. self.__ave_edge_num = self.__get_ave_edge_num(all_edge_nums)
  275. infos['ave_edge_num'] = self.__ave_edge_num
  276. if 'max_edge_num' in keys:
  277. if self.__max_edge_num is None:
  278. self.__max_edge_num = self.__get_max_edge_num(all_edge_nums)
  279. infos['max_edge_num'] = self.__max_edge_num
  280. if 'min_edge_num' in keys:
  281. if self.__min_edge_num is None:
  282. self.__min_edge_num = self.__get_min_edge_num(all_edge_nums)
  283. infos['min_edge_num'] = self.__min_edge_num
  284. # label number
  285. if 'node_label_dim' in keys:
  286. if self.__node_label_dim is None:
  287. self.__node_label_dim = self.__get_node_label_dim()
  288. infos['node_label_dim'] = self.__node_label_dim
  289. if 'node_label_nums' in keys:
  290. if self.__node_label_nums is None:
  291. self.__node_label_nums = {}
  292. for node_label in self.__node_labels:
  293. self.__node_label_nums[node_label] = self.__get_node_label_num(node_label)
  294. infos['node_label_nums'] = self.__node_label_nums
  295. if 'edge_label_dim' in keys:
  296. if self.__edge_label_dim is None:
  297. self.__edge_label_dim = self.__get_edge_label_dim()
  298. infos['edge_label_dim'] = self.__edge_label_dim
  299. if 'edge_label_nums' in keys:
  300. if self.__edge_label_nums is None:
  301. self.__edge_label_nums = {}
  302. for edge_label in self.__edge_labels:
  303. self.__edge_label_nums[edge_label] = self.__get_edge_label_num(edge_label)
  304. infos['edge_label_nums'] = self.__edge_label_nums
  305. if 'directed' in keys or 'substructures' in keys:
  306. if self.__directed is None:
  307. self.__directed = self.__is_directed()
  308. infos['directed'] = self.__directed
  309. # node degree
  310. if any(i in keys for i in ['ave_node_degree', 'max_node_degree', 'min_node_degree']):
  311. all_node_degrees = self.__get_all_node_degrees()
  312. if 'ave_node_degree' in keys:
  313. if self.__ave_node_degree is None:
  314. self.__ave_node_degree = self.__get_ave_node_degree(all_node_degrees)
  315. infos['ave_node_degree'] = self.__ave_node_degree
  316. if 'max_node_degree' in keys:
  317. if self.__max_node_degree is None:
  318. self.__max_node_degree = self.__get_max_node_degree(all_node_degrees)
  319. infos['max_node_degree'] = self.__max_node_degree
  320. if 'min_node_degree' in keys:
  321. if self.__min_node_degree is None:
  322. self.__min_node_degree = self.__get_min_node_degree(all_node_degrees)
  323. infos['min_node_degree'] = self.__min_node_degree
  324. # fill factor
  325. if any(i in keys for i in ['ave_fill_factor', 'max_fill_factor', 'min_fill_factor']):
  326. all_fill_factors = self.__get_all_fill_factors()
  327. if 'ave_fill_factor' in keys:
  328. if self.__ave_fill_factor is None:
  329. self.__ave_fill_factor = self.__get_ave_fill_factor(all_fill_factors)
  330. infos['ave_fill_factor'] = self.__ave_fill_factor
  331. if 'max_fill_factor' in keys:
  332. if self.__max_fill_factor is None:
  333. self.__max_fill_factor = self.__get_max_fill_factor(all_fill_factors)
  334. infos['max_fill_factor'] = self.__max_fill_factor
  335. if 'min_fill_factor' in keys:
  336. if self.__min_fill_factor is None:
  337. self.__min_fill_factor = self.__get_min_fill_factor(all_fill_factors)
  338. infos['min_fill_factor'] = self.__min_fill_factor
  339. if 'substructures' in keys:
  340. if self.__substructures is None:
  341. self.__substructures = self.__get_substructures()
  342. infos['substructures'] = self.__substructures
  343. if 'class_number' in keys:
  344. if self.__class_number is None:
  345. self.__class_number = self.__get_class_number()
  346. infos['class_number'] = self.__class_number
  347. if 'node_attr_dim' in keys:
  348. if self.__node_attr_dim is None:
  349. self.__node_attr_dim = self.__get_node_attr_dim()
  350. infos['node_attr_dim'] = self.__node_attr_dim
  351. if 'edge_attr_dim' in keys:
  352. if self.__edge_attr_dim is None:
  353. self.__edge_attr_dim = self.__get_edge_attr_dim()
  354. infos['edge_attr_dim'] = self.__edge_attr_dim
  355. # entropy of degree distribution.
  356. if 'all_degree_entropy' in keys:
  357. if params is not None and ('all_degree_entropy' in params) and ('base' in params['all_degree_entropy']):
  358. base = params['all_degree_entropy']['base']
  359. else:
  360. base = None
  361. infos['all_degree_entropy'] = self.__compute_all_degree_entropy(base=base)
  362. if 'ave_degree_entropy' in keys:
  363. if params is not None and ('ave_degree_entropy' in params) and ('base' in params['ave_degree_entropy']):
  364. base = params['ave_degree_entropy']['base']
  365. else:
  366. base = None
  367. infos['ave_degree_entropy'] = np.mean(self.__compute_all_degree_entropy(base=base))
  368. return infos
  369. def print_graph_infos(self, infos):
  370. from collections import OrderedDict
  371. keys = list(infos.keys())
  372. print(OrderedDict(sorted(infos.items(), key=lambda i: keys.index(i[0]))))
  373. def remove_labels(self, node_labels=[], edge_labels=[], node_attrs=[], edge_attrs=[]):
  374. node_labels = [item for item in node_labels if item in self.__node_labels]
  375. edge_labels = [item for item in edge_labels if item in self.__edge_labels]
  376. node_attrs = [item for item in node_attrs if item in self.__node_attrs]
  377. edge_attrs = [item for item in edge_attrs if item in self.__edge_attrs]
  378. for g in self.__graphs:
  379. for nd in g.nodes():
  380. for nl in node_labels:
  381. del g.nodes[nd][nl]
  382. for na in node_attrs:
  383. del g.nodes[nd][na]
  384. for ed in g.edges():
  385. for el in edge_labels:
  386. del g.edges[ed][el]
  387. for ea in edge_attrs:
  388. del g.edges[ed][ea]
  389. if len(node_labels) > 0:
  390. self.__node_labels = [nl for nl in self.__node_labels if nl not in node_labels]
  391. if len(edge_labels) > 0:
  392. self.__edge_labels = [el for el in self.__edge_labels if el not in edge_labels]
  393. if len(node_attrs) > 0:
  394. self.__node_attrs = [na for na in self.__node_attrs if na not in node_attrs]
  395. if len(edge_attrs) > 0:
  396. self.__edge_attrs = [ea for ea in self.__edge_attrs if ea not in edge_attrs]
  397. def clean_labels(self):
  398. labels = []
  399. for name in self.__node_labels:
  400. label = set()
  401. for G in self.__graphs:
  402. label = label | set(nx.get_node_attributes(G, name).values())
  403. if len(label) > 1:
  404. labels.append(name)
  405. break
  406. if len(label) < 2:
  407. for G in self.__graphs:
  408. for nd in G.nodes():
  409. del G.nodes[nd][name]
  410. self.__node_labels = labels
  411. labels = []
  412. for name in self.__edge_labels:
  413. label = set()
  414. for G in self.__graphs:
  415. label = label | set(nx.get_edge_attributes(G, name).values())
  416. if len(label) > 1:
  417. labels.append(name)
  418. break
  419. if len(label) < 2:
  420. for G in self.__graphs:
  421. for ed in G.edges():
  422. del G.edges[ed][name]
  423. self.__edge_labels = labels
  424. labels = []
  425. for name in self.__node_attrs:
  426. label = set()
  427. for G in self.__graphs:
  428. label = label | set(nx.get_node_attributes(G, name).values())
  429. if len(label) > 1:
  430. labels.append(name)
  431. break
  432. if len(label) < 2:
  433. for G in self.__graphs:
  434. for nd in G.nodes():
  435. del G.nodes[nd][name]
  436. self.__node_attrs = labels
  437. labels = []
  438. for name in self.__edge_attrs:
  439. label = set()
  440. for G in self.__graphs:
  441. label = label | set(nx.get_edge_attributes(G, name).values())
  442. if len(label) > 1:
  443. labels.append(name)
  444. break
  445. if len(label) < 2:
  446. for G in self.__graphs:
  447. for ed in G.edges():
  448. del G.edges[ed][name]
  449. self.__edge_attrs = labels
  450. def cut_graphs(self, range_):
  451. self.__graphs = [self.__graphs[i] for i in range_]
  452. if self.__targets is not None:
  453. self.__targets = [self.__targets[i] for i in range_]
  454. self.clean_labels()
  455. def trim_dataset(self, edge_required=False):
  456. if edge_required:
  457. trimed_pairs = [(idx, g) for idx, g in enumerate(self.__graphs) if (nx.number_of_nodes(g) != 0 and nx.number_of_edges(g) != 0)]
  458. else:
  459. trimed_pairs = [(idx, g) for idx, g in enumerate(self.__graphs) if nx.number_of_nodes(g) != 0]
  460. idx = [p[0] for p in trimed_pairs]
  461. self.__graphs = [p[1] for p in trimed_pairs]
  462. self.__targets = [self.__targets[i] for i in idx]
  463. self.clean_labels()
  464. def copy(self):
  465. dataset = Dataset()
  466. graphs = [g.copy() for g in self.__graphs] if self.__graphs is not None else None
  467. target = self.__targets.copy() if self.__targets is not None else None
  468. node_labels = self.__node_labels.copy() if self.__node_labels is not None else None
  469. node_attrs = self.__node_attrs.copy() if self.__node_attrs is not None else None
  470. edge_labels = self.__edge_labels.copy() if self.__edge_labels is not None else None
  471. edge_attrs = self.__edge_attrs.copy() if self.__edge_attrs is not None else None
  472. dataset.load_graphs(graphs, target)
  473. dataset.set_labels(node_labels=node_labels, node_attrs=node_attrs, edge_labels=edge_labels, edge_attrs=edge_attrs)
  474. # @todo: clean_labels and add other class members?
  475. return dataset
  476. def get_all_node_labels(self):
  477. node_labels = []
  478. for g in self.__graphs:
  479. for n in g.nodes():
  480. nl = tuple(g.nodes[n].items())
  481. if nl not in node_labels:
  482. node_labels.append(nl)
  483. return node_labels
  484. def get_all_edge_labels(self):
  485. edge_labels = []
  486. for g in self.__graphs:
  487. for e in g.edges():
  488. el = tuple(g.edges[e].items())
  489. if el not in edge_labels:
  490. edge_labels.append(el)
  491. return edge_labels
  492. def __get_dataset_size(self):
  493. return len(self.__graphs)
  494. def __get_all_node_nums(self):
  495. return [nx.number_of_nodes(G) for G in self.__graphs]
  496. def __get_total_node_nums(self, all_node_nums):
  497. return np.sum(all_node_nums)
  498. def __get_ave_node_num(self, all_node_nums):
  499. return np.mean(all_node_nums)
  500. def __get_min_node_num(self, all_node_nums):
  501. return np.amin(all_node_nums)
  502. def __get_max_node_num(self, all_node_nums):
  503. return np.amax(all_node_nums)
  504. def __get_all_edge_nums(self):
  505. return [nx.number_of_edges(G) for G in self.__graphs]
  506. def __get_total_edge_nums(self, all_edge_nums):
  507. return np.sum(all_edge_nums)
  508. def __get_ave_edge_num(self, all_edge_nums):
  509. return np.mean(all_edge_nums)
  510. def __get_min_edge_num(self, all_edge_nums):
  511. return np.amin(all_edge_nums)
  512. def __get_max_edge_num(self, all_edge_nums):
  513. return np.amax(all_edge_nums)
  514. def __get_node_label_dim(self):
  515. return len(self.__node_labels)
  516. def __get_node_label_num(self, node_label):
  517. nl = set()
  518. for G in self.__graphs:
  519. nl = nl | set(nx.get_node_attributes(G, node_label).values())
  520. return len(nl)
  521. def __get_edge_label_dim(self):
  522. return len(self.__edge_labels)
  523. def __get_edge_label_num(self, edge_label):
  524. el = set()
  525. for G in self.__graphs:
  526. el = el | set(nx.get_edge_attributes(G, edge_label).values())
  527. return len(el)
  528. def __is_directed(self):
  529. return nx.is_directed(self.__graphs[0])
  530. def __get_all_node_degrees(self):
  531. return [np.mean(list(dict(G.degree()).values())) for G in self.__graphs]
  532. def __get_ave_node_degree(self, all_node_degrees):
  533. return np.mean(all_node_degrees)
  534. def __get_max_node_degree(self, all_node_degrees):
  535. return np.amax(all_node_degrees)
  536. def __get_min_node_degree(self, all_node_degrees):
  537. return np.amin(all_node_degrees)
  538. def __get_all_fill_factors(self):
  539. """Get fill factor, the number of non-zero entries in the adjacency matrix.
  540. Returns
  541. -------
  542. list[float]
  543. List of fill factors for all graphs.
  544. """
  545. return [nx.number_of_edges(G) / (nx.number_of_nodes(G) ** 2) for G in self.__graphs]
  546. def __get_ave_fill_factor(self, all_fill_factors):
  547. return np.mean(all_fill_factors)
  548. def __get_max_fill_factor(self, all_fill_factors):
  549. return np.amax(all_fill_factors)
  550. def __get_min_fill_factor(self, all_fill_factors):
  551. return np.amin(all_fill_factors)
  552. def __get_substructures(self):
  553. subs = set()
  554. for G in self.__graphs:
  555. degrees = list(dict(G.degree()).values())
  556. if any(i == 2 for i in degrees):
  557. subs.add('linear')
  558. if np.amax(degrees) >= 3:
  559. subs.add('non linear')
  560. if 'linear' in subs and 'non linear' in subs:
  561. break
  562. if self.__directed:
  563. for G in self.__graphs:
  564. if len(list(nx.find_cycle(G))) > 0:
  565. subs.add('cyclic')
  566. break
  567. # else:
  568. # # @todo: this method does not work for big graph with large amount of edges like D&D, try a better way.
  569. # upper = np.amin([nx.number_of_edges(G) for G in Gn]) * 2 + 10
  570. # for G in Gn:
  571. # if (nx.number_of_edges(G) < upper):
  572. # cyc = list(nx.simple_cycles(G.to_directed()))
  573. # if any(len(i) > 2 for i in cyc):
  574. # subs.add('cyclic')
  575. # break
  576. # if 'cyclic' not in subs:
  577. # for G in Gn:
  578. # cyc = list(nx.simple_cycles(G.to_directed()))
  579. # if any(len(i) > 2 for i in cyc):
  580. # subs.add('cyclic')
  581. # break
  582. return subs
  583. def __get_class_num(self):
  584. return len(set(self.__targets))
  585. def __get_node_attr_dim(self):
  586. return len(self.__node_attrs)
  587. def __get_edge_attr_dim(self):
  588. return len(self.__edge_attrs)
  589. def __compute_all_degree_entropy(self, base=None):
  590. """Compute the entropy of degree distribution of each graph.
  591. Parameters
  592. ----------
  593. base : float, optional
  594. The logarithmic base to use. The default is ``e`` (natural logarithm).
  595. Returns
  596. -------
  597. degree_entropy : float
  598. The calculated entropy.
  599. """
  600. from gklearn.utils.stats import entropy
  601. degree_entropy = []
  602. for g in self.__graphs:
  603. degrees = list(dict(g.degree()).values())
  604. en = entropy(degrees, base=base)
  605. degree_entropy.append(en)
  606. return degree_entropy
  607. @property
  608. def graphs(self):
  609. return self.__graphs
  610. @property
  611. def targets(self):
  612. return self.__targets
  613. @property
  614. def node_labels(self):
  615. return self.__node_labels
  616. @property
  617. def edge_labels(self):
  618. return self.__edge_labels
  619. @property
  620. def node_attrs(self):
  621. return self.__node_attrs
  622. @property
  623. def edge_attrs(self):
  624. return self.__edge_attrs
  625. def split_dataset_by_target(dataset):
  626. from gklearn.preimage.utils import get_same_item_indices
  627. graphs = dataset.graphs
  628. targets = dataset.targets
  629. datasets = []
  630. idx_targets = get_same_item_indices(targets)
  631. for key, val in idx_targets.items():
  632. sub_graphs = [graphs[i] for i in val]
  633. sub_dataset = Dataset()
  634. sub_dataset.load_graphs(sub_graphs, [key] * len(val))
  635. node_labels = dataset.node_labels.copy() if dataset.node_labels is not None else None
  636. node_attrs = dataset.node_attrs.copy() if dataset.node_attrs is not None else None
  637. edge_labels = dataset.edge_labels.copy() if dataset.edge_labels is not None else None
  638. edge_attrs = dataset.edge_attrs.copy() if dataset.edge_attrs is not None else None
  639. sub_dataset.set_labels(node_labels=node_labels, node_attrs=node_attrs, edge_labels=edge_labels, edge_attrs=edge_attrs)
  640. datasets.append(sub_dataset)
  641. # @todo: clean_labels?
  642. return datasets

A Python package for graph kernels, graph edit distances and graph pre-image problem.