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.

graphdataset.py 13 kB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. """ Obtain all kinds of attributes of a graph dataset.
  2. This file is for old version of graphkit-learn.
  3. """
  4. def get_dataset_attributes(Gn,
  5. target=None,
  6. attr_names=[],
  7. node_label=None,
  8. edge_label=None):
  9. """Returns the structure and property information of the graph dataset Gn.
  10. Parameters
  11. ----------
  12. Gn : List of NetworkX graph
  13. List of graphs whose information will be returned.
  14. target : list
  15. The list of classification targets corresponding to Gn. Only works for
  16. classification problems.
  17. attr_names : list
  18. List of strings which indicate which informations will be returned. The
  19. possible choices includes:
  20. 'substructures': sub-structures Gn contains, including 'linear', 'non
  21. linear' and 'cyclic'.
  22. 'node_labeled': whether vertices have symbolic labels.
  23. 'edge_labeled': whether egdes have symbolic labels.
  24. 'is_directed': whether graphs in Gn are directed.
  25. 'dataset_size': number of graphs in Gn.
  26. 'ave_node_num': average number of vertices of graphs in Gn.
  27. 'min_node_num': minimum number of vertices of graphs in Gn.
  28. 'max_node_num': maximum number of vertices of graphs in Gn.
  29. 'ave_edge_num': average number of edges of graphs in Gn.
  30. 'min_edge_num': minimum number of edges of graphs in Gn.
  31. 'max_edge_num': maximum number of edges of graphs in Gn.
  32. 'ave_node_degree': average vertex degree of graphs in Gn.
  33. 'min_node_degree': minimum vertex degree of graphs in Gn.
  34. 'max_node_degree': maximum vertex degree of graphs in Gn.
  35. 'ave_fill_factor': average fill factor (number_of_edges /
  36. (number_of_nodes ** 2)) of graphs in Gn.
  37. 'min_fill_factor': minimum fill factor of graphs in Gn.
  38. 'max_fill_factor': maximum fill factor of graphs in Gn.
  39. 'node_label_num': number of symbolic vertex labels.
  40. 'edge_label_num': number of symbolic edge labels.
  41. 'node_attr_dim': number of dimensions of non-symbolic vertex labels.
  42. Extracted from the 'attributes' attribute of graph nodes.
  43. 'edge_attr_dim': number of dimensions of non-symbolic edge labels.
  44. Extracted from the 'attributes' attribute of graph edges.
  45. 'class_number': number of classes. Only available for classification problems.
  46. node_label : string
  47. Node attribute used as label. The default node label is atom. Mandatory
  48. when 'node_labeled' or 'node_label_num' is required.
  49. edge_label : string
  50. Edge attribute used as label. The default edge label is bond_type.
  51. Mandatory when 'edge_labeled' or 'edge_label_num' is required.
  52. Return
  53. ------
  54. attrs : dict
  55. Value for each property.
  56. """
  57. import networkx as nx
  58. import numpy as np
  59. attrs = {}
  60. def get_dataset_size(Gn):
  61. return len(Gn)
  62. def get_all_node_num(Gn):
  63. return [nx.number_of_nodes(G) for G in Gn]
  64. def get_ave_node_num(all_node_num):
  65. return np.mean(all_node_num)
  66. def get_min_node_num(all_node_num):
  67. return np.amin(all_node_num)
  68. def get_max_node_num(all_node_num):
  69. return np.amax(all_node_num)
  70. def get_all_edge_num(Gn):
  71. return [nx.number_of_edges(G) for G in Gn]
  72. def get_ave_edge_num(all_edge_num):
  73. return np.mean(all_edge_num)
  74. def get_min_edge_num(all_edge_num):
  75. return np.amin(all_edge_num)
  76. def get_max_edge_num(all_edge_num):
  77. return np.amax(all_edge_num)
  78. def is_node_labeled(Gn):
  79. return False if node_label is None else True
  80. def get_node_label_num(Gn):
  81. nl = set()
  82. for G in Gn:
  83. nl = nl | set(nx.get_node_attributes(G, node_label).values())
  84. return len(nl)
  85. def is_edge_labeled(Gn):
  86. return False if edge_label is None else True
  87. def get_edge_label_num(Gn):
  88. el = set()
  89. for G in Gn:
  90. el = el | set(nx.get_edge_attributes(G, edge_label).values())
  91. return len(el)
  92. def is_directed(Gn):
  93. return nx.is_directed(Gn[0])
  94. def get_ave_node_degree(Gn):
  95. return np.mean([np.mean(list(dict(G.degree()).values())) for G in Gn])
  96. def get_max_node_degree(Gn):
  97. return np.amax([np.mean(list(dict(G.degree()).values())) for G in Gn])
  98. def get_min_node_degree(Gn):
  99. return np.amin([np.mean(list(dict(G.degree()).values())) for G in Gn])
  100. # get fill factor, the number of non-zero entries in the adjacency matrix.
  101. def get_ave_fill_factor(Gn):
  102. return np.mean([nx.number_of_edges(G) / (nx.number_of_nodes(G)
  103. * nx.number_of_nodes(G)) for G in Gn])
  104. def get_max_fill_factor(Gn):
  105. return np.amax([nx.number_of_edges(G) / (nx.number_of_nodes(G)
  106. * nx.number_of_nodes(G)) for G in Gn])
  107. def get_min_fill_factor(Gn):
  108. return np.amin([nx.number_of_edges(G) / (nx.number_of_nodes(G)
  109. * nx.number_of_nodes(G)) for G in Gn])
  110. def get_substructures(Gn):
  111. subs = set()
  112. for G in Gn:
  113. degrees = list(dict(G.degree()).values())
  114. if any(i == 2 for i in degrees):
  115. subs.add('linear')
  116. if np.amax(degrees) >= 3:
  117. subs.add('non linear')
  118. if 'linear' in subs and 'non linear' in subs:
  119. break
  120. if is_directed(Gn):
  121. for G in Gn:
  122. if len(list(nx.find_cycle(G))) > 0:
  123. subs.add('cyclic')
  124. break
  125. # else:
  126. # # @todo: this method does not work for big graph with large amount of edges like D&D, try a better way.
  127. # upper = np.amin([nx.number_of_edges(G) for G in Gn]) * 2 + 10
  128. # for G in Gn:
  129. # if (nx.number_of_edges(G) < upper):
  130. # cyc = list(nx.simple_cycles(G.to_directed()))
  131. # if any(len(i) > 2 for i in cyc):
  132. # subs.add('cyclic')
  133. # break
  134. # if 'cyclic' not in subs:
  135. # for G in Gn:
  136. # cyc = list(nx.simple_cycles(G.to_directed()))
  137. # if any(len(i) > 2 for i in cyc):
  138. # subs.add('cyclic')
  139. # break
  140. return subs
  141. def get_class_num(target):
  142. return len(set(target))
  143. def get_node_attr_dim(Gn):
  144. for G in Gn:
  145. for n in G.nodes(data=True):
  146. if 'attributes' in n[1]:
  147. return len(n[1]['attributes'])
  148. return 0
  149. def get_edge_attr_dim(Gn):
  150. for G in Gn:
  151. if nx.number_of_edges(G) > 0:
  152. for e in G.edges(data=True):
  153. if 'attributes' in e[2]:
  154. return len(e[2]['attributes'])
  155. return 0
  156. if attr_names == []:
  157. attr_names = [
  158. 'substructures',
  159. 'node_labeled',
  160. 'edge_labeled',
  161. 'is_directed',
  162. 'dataset_size',
  163. 'ave_node_num',
  164. 'min_node_num',
  165. 'max_node_num',
  166. 'ave_edge_num',
  167. 'min_edge_num',
  168. 'max_edge_num',
  169. 'ave_node_degree',
  170. 'min_node_degree',
  171. 'max_node_degree',
  172. 'ave_fill_factor',
  173. 'min_fill_factor',
  174. 'max_fill_factor',
  175. 'node_label_num',
  176. 'edge_label_num',
  177. 'node_attr_dim',
  178. 'edge_attr_dim',
  179. 'class_number',
  180. ]
  181. # dataset size
  182. if 'dataset_size' in attr_names:
  183. attrs.update({'dataset_size': get_dataset_size(Gn)})
  184. # graph node number
  185. if any(i in attr_names
  186. for i in ['ave_node_num', 'min_node_num', 'max_node_num']):
  187. all_node_num = get_all_node_num(Gn)
  188. if 'ave_node_num' in attr_names:
  189. attrs.update({'ave_node_num': get_ave_node_num(all_node_num)})
  190. if 'min_node_num' in attr_names:
  191. attrs.update({'min_node_num': get_min_node_num(all_node_num)})
  192. if 'max_node_num' in attr_names:
  193. attrs.update({'max_node_num': get_max_node_num(all_node_num)})
  194. # graph edge number
  195. if any(i in attr_names for i in
  196. ['ave_edge_num', 'min_edge_num', 'max_edge_num']):
  197. all_edge_num = get_all_edge_num(Gn)
  198. if 'ave_edge_num' in attr_names:
  199. attrs.update({'ave_edge_num': get_ave_edge_num(all_edge_num)})
  200. if 'max_edge_num' in attr_names:
  201. attrs.update({'max_edge_num': get_max_edge_num(all_edge_num)})
  202. if 'min_edge_num' in attr_names:
  203. attrs.update({'min_edge_num': get_min_edge_num(all_edge_num)})
  204. # label number
  205. if any(i in attr_names for i in ['node_labeled', 'node_label_num']):
  206. is_nl = is_node_labeled(Gn)
  207. node_label_num = get_node_label_num(Gn)
  208. if 'node_labeled' in attr_names:
  209. # graphs are considered node unlabeled if all nodes have the same label.
  210. attrs.update({'node_labeled': is_nl if node_label_num > 1 else False})
  211. if 'node_label_num' in attr_names:
  212. attrs.update({'node_label_num': node_label_num})
  213. if any(i in attr_names for i in ['edge_labeled', 'edge_label_num']):
  214. is_el = is_edge_labeled(Gn)
  215. edge_label_num = get_edge_label_num(Gn)
  216. if 'edge_labeled' in attr_names:
  217. # graphs are considered edge unlabeled if all edges have the same label.
  218. attrs.update({'edge_labeled': is_el if edge_label_num > 1 else False})
  219. if 'edge_label_num' in attr_names:
  220. attrs.update({'edge_label_num': edge_label_num})
  221. if 'is_directed' in attr_names:
  222. attrs.update({'is_directed': is_directed(Gn)})
  223. if 'ave_node_degree' in attr_names:
  224. attrs.update({'ave_node_degree': get_ave_node_degree(Gn)})
  225. if 'max_node_degree' in attr_names:
  226. attrs.update({'max_node_degree': get_max_node_degree(Gn)})
  227. if 'min_node_degree' in attr_names:
  228. attrs.update({'min_node_degree': get_min_node_degree(Gn)})
  229. if 'ave_fill_factor' in attr_names:
  230. attrs.update({'ave_fill_factor': get_ave_fill_factor(Gn)})
  231. if 'max_fill_factor' in attr_names:
  232. attrs.update({'max_fill_factor': get_max_fill_factor(Gn)})
  233. if 'min_fill_factor' in attr_names:
  234. attrs.update({'min_fill_factor': get_min_fill_factor(Gn)})
  235. if 'substructures' in attr_names:
  236. attrs.update({'substructures': get_substructures(Gn)})
  237. if 'class_number' in attr_names:
  238. attrs.update({'class_number': get_class_num(target)})
  239. if 'node_attr_dim' in attr_names:
  240. attrs['node_attr_dim'] = get_node_attr_dim(Gn)
  241. if 'edge_attr_dim' in attr_names:
  242. attrs['edge_attr_dim'] = get_edge_attr_dim(Gn)
  243. from collections import OrderedDict
  244. return OrderedDict(
  245. sorted(attrs.items(), key=lambda i: attr_names.index(i[0])))
  246. def load_predefined_dataset(ds_name):
  247. import os
  248. from gklearn.utils.graphfiles import loadDataset
  249. current_path = os.path.dirname(os.path.realpath(__file__)) + '/'
  250. if ds_name == 'Acyclic':
  251. ds_file = current_path + '../../datasets/Acyclic/dataset_bps.ds'
  252. graphs, targets = loadDataset(ds_file)
  253. elif ds_name == 'AIDS':
  254. ds_file = current_path + '../../datasets/AIDS/AIDS_A.txt'
  255. graphs, targets = loadDataset(ds_file)
  256. elif ds_name == 'Alkane':
  257. ds_file = current_path + '../../datasets/Alkane/dataset.ds'
  258. fn_targets = current_path + '../../datasets/Alkane/dataset_boiling_point_names.txt'
  259. graphs, targets = loadDataset(ds_file, filename_y=fn_targets)
  260. elif ds_name == 'COIL-DEL':
  261. ds_file = current_path + '../../datasets/COIL-DEL/COIL-DEL_A.txt'
  262. graphs, targets = loadDataset(ds_file)
  263. elif ds_name == 'COIL-RAG':
  264. ds_file = current_path + '../../datasets/COIL-RAG/COIL-RAG_A.txt'
  265. graphs, targets = loadDataset(ds_file)
  266. elif ds_name == 'COLORS-3':
  267. ds_file = current_path + '../../datasets/COLORS-3/COLORS-3_A.txt'
  268. graphs, targets = loadDataset(ds_file)
  269. elif ds_name == 'Cuneiform':
  270. ds_file = current_path + '../../datasets/Cuneiform/Cuneiform_A.txt'
  271. graphs, targets = loadDataset(ds_file)
  272. elif ds_name == 'DD':
  273. ds_file = current_path + '../../datasets/DD/DD_A.txt'
  274. graphs, targets = loadDataset(ds_file)
  275. elif ds_name == 'ENZYMES':
  276. ds_file = current_path + '../../datasets/ENZYMES_txt/ENZYMES_A_sparse.txt'
  277. graphs, targets = loadDataset(ds_file)
  278. elif ds_name == 'Fingerprint':
  279. ds_file = current_path + '../../datasets/Fingerprint/Fingerprint_A.txt'
  280. graphs, targets = loadDataset(ds_file)
  281. elif ds_name == 'FRANKENSTEIN':
  282. ds_file = current_path + '../../datasets/FRANKENSTEIN/FRANKENSTEIN_A.txt'
  283. graphs, targets = loadDataset(ds_file)
  284. elif ds_name == 'Letter-high': # node non-symb
  285. ds_file = current_path + '../../datasets/Letter-high/Letter-high_A.txt'
  286. graphs, targets = loadDataset(ds_file)
  287. elif ds_name == 'Letter-low': # node non-symb
  288. ds_file = current_path + '../../datasets/Letter-low/Letter-low_A.txt'
  289. graphs, targets = loadDataset(ds_file)
  290. elif ds_name == 'Letter-med': # node non-symb
  291. ds_file = current_path + '../../datasets/Letter-med/Letter-med_A.txt'
  292. graphs, targets = loadDataset(ds_file)
  293. elif ds_name == 'MAO':
  294. ds_file = current_path + '../../datasets/MAO/dataset.ds'
  295. graphs, targets = loadDataset(ds_file)
  296. elif ds_name == 'Monoterpenoides':
  297. ds_file = current_path + '../../datasets/Monoterpenoides/dataset_10+.ds'
  298. graphs, targets = loadDataset(ds_file)
  299. elif ds_name == 'MUTAG':
  300. ds_file = current_path + '../../datasets/MUTAG/MUTAG_A.txt'
  301. graphs, targets = loadDataset(ds_file)
  302. elif ds_name == 'NCI1':
  303. ds_file = current_path + '../../datasets/NCI1/NCI1_A.txt'
  304. graphs, targets = loadDataset(ds_file)
  305. elif ds_name == 'NCI109':
  306. ds_file = current_path + '../../datasets/NCI109/NCI109_A.txt'
  307. graphs, targets = loadDataset(ds_file)
  308. elif ds_name == 'PAH':
  309. ds_file = current_path + '../../datasets/PAH/dataset.ds'
  310. graphs, targets = loadDataset(ds_file)
  311. elif ds_name == 'SYNTHETIC':
  312. pass
  313. elif ds_name == 'SYNTHETICnew':
  314. ds_file = current_path + '../../datasets/SYNTHETICnew/SYNTHETICnew_A.txt'
  315. graphs, targets = loadDataset(ds_file)
  316. elif ds_name == 'Synthie':
  317. pass
  318. else:
  319. raise Exception('The dataset name "', ds_name, '" is not pre-defined.')
  320. return graphs, targets

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