FranKGraphBench 0.0.1a0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. FranKGraphBench-0.0.1a0.dist-info/LICENSE +201 -0
  2. FranKGraphBench-0.0.1a0.dist-info/METADATA +189 -0
  3. FranKGraphBench-0.0.1a0.dist-info/RECORD +70 -0
  4. FranKGraphBench-0.0.1a0.dist-info/WHEEL +6 -0
  5. FranKGraphBench-0.0.1a0.dist-info/entry_points.txt +3 -0
  6. FranKGraphBench-0.0.1a0.dist-info/top_level.txt +2 -0
  7. data_integration/__init__.py +47 -0
  8. data_integration/__main__.py +4 -0
  9. data_integration/dataset.py +270 -0
  10. data_integration/dataset2class.py +34 -0
  11. data_integration/datasets/__init__.py +0 -0
  12. data_integration/datasets/amazon.py +140 -0
  13. data_integration/datasets/book-crossing.py +98 -0
  14. data_integration/datasets/douban-movie.py +75 -0
  15. data_integration/datasets/lastfm.py +215 -0
  16. data_integration/datasets/movielens.py +375 -0
  17. data_integration/datasets/steam.py +98 -0
  18. data_integration/datasets/worker.py +31 -0
  19. data_integration/datasets/yelp.py +156 -0
  20. framework/__init__.py +17 -0
  21. framework/__main__.py +4 -0
  22. framework/dataloader/__init__.py +0 -0
  23. framework/dataloader/dataloader.py +52 -0
  24. framework/dataloader/dataset/__init__.py +0 -0
  25. framework/dataloader/dataset/dataset.py +38 -0
  26. framework/dataloader/edge_splitter/__init__.py +0 -0
  27. framework/dataloader/edge_splitter/edge_splitter.py +163 -0
  28. framework/dataloader/graph/__init__.py +0 -0
  29. framework/dataloader/graph/graph.py +314 -0
  30. framework/dataloader/graph/node.py +80 -0
  31. framework/dataloader/preprocess/__init__.py +0 -0
  32. framework/dataloader/preprocess/methods.py +47 -0
  33. framework/evaluator/__init__.py +0 -0
  34. framework/evaluator/metric.py +39 -0
  35. framework/evaluator/metric2class.py +10 -0
  36. framework/evaluator/metrics/__init__.py +0 -0
  37. framework/evaluator/metrics/map.py +33 -0
  38. framework/evaluator/metrics/ndcg.py +49 -0
  39. framework/experiment.py +120 -0
  40. framework/recommender/__init__.py +0 -0
  41. framework/recommender/model2class.py +46 -0
  42. framework/recommender/models/__init__.py +0 -0
  43. framework/recommender/models/complEx/__init__.py +0 -0
  44. framework/recommender/models/complEx/model.py +193 -0
  45. framework/recommender/models/deep_walk_based/__init__.py +0 -0
  46. framework/recommender/models/deep_walk_based/model.py +149 -0
  47. framework/recommender/models/distMult/__init__.py +0 -0
  48. framework/recommender/models/distMult/model.py +187 -0
  49. framework/recommender/models/ePHEN/__init__.py +0 -0
  50. framework/recommender/models/ePHEN/model.py +159 -0
  51. framework/recommender/models/rESCAL/__init__.py +0 -0
  52. framework/recommender/models/rESCAL/model.py +184 -0
  53. framework/recommender/models/rotatE/__init__.py +0 -0
  54. framework/recommender/models/rotatE/model.py +195 -0
  55. framework/recommender/models/transD/__init__.py +0 -0
  56. framework/recommender/models/transD/model.py +190 -0
  57. framework/recommender/models/transE/__init__.py +0 -0
  58. framework/recommender/models/transE/model.py +194 -0
  59. framework/recommender/models/transH/__init__.py +0 -0
  60. framework/recommender/models/transH/model.py +193 -0
  61. framework/recommender/models/transR/__init__.py +0 -0
  62. framework/recommender/models/transR/model.py +190 -0
  63. framework/recommender/models/tuckER/__init__.py +0 -0
  64. framework/recommender/models/tuckER/model.py +199 -0
  65. framework/recommender/recommender.py +32 -0
  66. framework/recommender/utils/__init__.py +0 -0
  67. framework/recommender/utils/walker.py +185 -0
  68. framework/reporter/__init__.py +0 -0
  69. framework/reporter/report.py +101 -0
  70. framework/utils.py +10 -0
@@ -0,0 +1,185 @@
1
+ # Code extracted from: https://raw.githubusercontent.com/benedekrozemberczki/karateclub/master/karateclub/utils/walker.py
2
+
3
+ import random
4
+ from functools import partial
5
+ from typing import List, Callable
6
+
7
+ import numpy as np
8
+ import networkx as nx
9
+ from tqdm import tqdm
10
+
11
+
12
+ class RandomWalker:
13
+ """
14
+ Class to do fast first-order random walks.
15
+
16
+ Args:
17
+ walk_length (int): Number of random walks.
18
+ walk_number (int): Number of nodes in truncated walk.
19
+ """
20
+
21
+ def __init__(self, walk_length: int, walk_number: int):
22
+ self.walk_length = walk_length
23
+ self.walk_number = walk_number
24
+
25
+ def do_walk(self, node: int) -> List[str]:
26
+ """
27
+ Doing a single truncated random walk from a source node.
28
+
29
+ Arg types:
30
+ * **node** *(int)* - The source node of the random walk.
31
+
32
+ Return types:
33
+ * **walk** *(list of strings)* - A single truncated random walk.
34
+ """
35
+ walk: List[int] = [node]
36
+ for _ in range(self.walk_length - 1):
37
+ nebs = [node for node in self.graph.neighbors(walk[-1])]
38
+ if len(nebs) > 0:
39
+ walk = walk + random.sample(nebs, 1)
40
+ walk = [str(w) for w in walk]
41
+ return walk
42
+
43
+ def do_walks(self, graph):
44
+ """
45
+ Doing a fixed number of truncated random walk from every node in the graph.
46
+
47
+ Arg types:
48
+ * **graph** *(NetworkX graph)* - The graph to run the random walks on.
49
+ """
50
+ self.walks: List[List[str]] = []
51
+ self.graph = graph
52
+ for node in tqdm(self.graph.nodes()):
53
+ for _ in range(self.walk_number):
54
+ walk_from_node = self.do_walk(node)
55
+ self.walks.append(walk_from_node)
56
+
57
+
58
+ def _check_value(value, name):
59
+ try:
60
+ _ = 1 / value
61
+
62
+ except ZeroDivisionError:
63
+ raise ValueError(
64
+ f"The value of {name} is too small " f"or zero to be used in 1/{name}."
65
+ )
66
+
67
+
68
+ def _undirected(node, graph) -> List[tuple]:
69
+ edges = graph.edges(node)
70
+
71
+ return edges
72
+
73
+
74
+ def _directed(node, graph) -> List[tuple]:
75
+ edges = graph.out_edges(node, data=True)
76
+
77
+ return edges
78
+
79
+
80
+ def _get_edge_fn(graph) -> Callable:
81
+ fn = _directed if nx.classes.function.is_directed(graph) else _undirected
82
+
83
+ fn = partial(fn, graph=graph)
84
+ return fn
85
+
86
+
87
+ def _unweighted(edges: List[tuple]) -> np.ndarray:
88
+ return np.ones(len(edges))
89
+
90
+
91
+ def _weighted(edges: List[tuple]) -> np.ndarray:
92
+ weights = map(lambda edge: edge[-1]["weight"], edges)
93
+
94
+ return np.array([*weights])
95
+
96
+
97
+ def _get_weight_fn(graph) -> Callable:
98
+ fn = _weighted if nx.classes.function.is_weighted(graph) else _unweighted
99
+
100
+ return fn
101
+
102
+
103
+ class BiasedRandomWalker:
104
+ """
105
+ Class to do biased second order random walks.
106
+
107
+ Args:
108
+ walk_length (int): Number of random walks.
109
+ walk_number (int): Number of nodes in truncated walk.
110
+ p (float): Return parameter (1/p transition probability) to move towards previous node.
111
+ q (float): In-out parameter (1/q transition probability) to move away from previous node.
112
+ """
113
+
114
+ walks: list
115
+ graph: nx.classes.graph.Graph
116
+ edge_fn: Callable
117
+ weight_fn: Callable
118
+
119
+ def __init__(self, walk_length: int, walk_number: int, p: float, q: float):
120
+ self.walk_length = walk_length
121
+ self.walk_number = walk_number
122
+
123
+ _check_value(p, "p")
124
+ self.p = p
125
+
126
+ _check_value(q, "q")
127
+ self.q = q
128
+
129
+ def do_walk(self, node: int) -> List[str]:
130
+ """
131
+ Doing a single truncated second order random walk from a source node.
132
+
133
+ Arg types:
134
+ * **node** *(int)* - The source node of the random walk.
135
+
136
+ Return types:
137
+ * **walk** *(list of strings)* - A single truncated random walk.
138
+ """
139
+ walk = [node]
140
+ previous_node = None
141
+ previous_node_neighbors = []
142
+ for _ in range(self.walk_length - 1):
143
+ current_node = walk[-1]
144
+ edges = self.edge_fn(current_node)
145
+ current_node_neighbors = np.array([edge[1] for edge in edges])
146
+
147
+ weights = self.weight_fn(edges)
148
+ probability = np.piecewise(
149
+ weights,
150
+ [
151
+ current_node_neighbors == previous_node,
152
+ np.isin(current_node_neighbors, previous_node_neighbors),
153
+ ],
154
+ [lambda w: w / self.p, lambda w: w / 1, lambda w: w / self.q],
155
+ )
156
+
157
+ norm_probability = probability / sum(probability)
158
+ selected = np.random.choice(current_node_neighbors, 1, p=norm_probability)[
159
+ 0
160
+ ]
161
+ walk.append(selected)
162
+
163
+ previous_node_neighbors = current_node_neighbors
164
+ previous_node = current_node
165
+
166
+ walk = [str(w) for w in walk]
167
+ return walk
168
+
169
+ def do_walks(self, graph) -> None:
170
+ """
171
+ Doing a fixed number of truncated random walk from every node in the graph.
172
+
173
+ Arg types:
174
+ * **graph** *(NetworkX graph)* - The graph to run the random walks on.
175
+ """
176
+ self.walks = []
177
+ self.graph = graph
178
+
179
+ self.edge_fn = _get_edge_fn(graph)
180
+ self.weight_fn = _get_weight_fn(graph)
181
+
182
+ for node in tqdm(self.graph.nodes()):
183
+ for _ in range(self.walk_number):
184
+ walk_from_node = self.do_walk(node)
185
+ self.walks.append(walk_from_node)
File without changes
@@ -0,0 +1,101 @@
1
+ import pandas as pd
2
+ import numpy as np
3
+ import typing as t
4
+ import os
5
+ import cpuinfo
6
+ import psutil
7
+ import GPUtil
8
+
9
+ class Reporter:
10
+ def __init__(self, output_file, eval_metrics):
11
+ self.filename = output_file
12
+ self.eval_metrics = eval_metrics
13
+
14
+ def report(self, results) -> None:
15
+ """
16
+ Creates the .csv file with experiment results
17
+ """
18
+ results = self.__process(results)
19
+ df = pd.DataFrame.from_dict(results, orient='index')
20
+ df['model'] = df.index
21
+ df = df.set_index('model')
22
+
23
+ self.__to_csv(df)
24
+
25
+ def __to_csv(self, df):
26
+ folder = os.path.dirname(self.filename)
27
+ if not os.path.isdir(folder):
28
+ os.makedirs(folder)
29
+ df.to_csv(self.filename)
30
+
31
+ def __process(self, results) -> t.Dict[str, t.Dict[str, float]]:
32
+ """
33
+ returns
34
+ For k-fold:
35
+ {model_name: {fold-1_metric: value, fold-1_metric2: value, ..., metric_mean:value, metric_std}}
36
+ For hold-out:
37
+ {model_name: {metric1: value, metric2: value}}
38
+ """
39
+ results_processed = {}
40
+ for model, metrics in results.items():
41
+ report = {}
42
+ if len(metrics) > 1:
43
+ for fold, fold_metrics in enumerate(metrics):
44
+ for i, metric in enumerate(fold_metrics):
45
+ col = f'fold-{fold+1}_{self.eval_metrics[i].name()}'
46
+ report[col] = metric
47
+ metrics_mean = np.array(metrics).mean(axis=0)
48
+ metrics_std = np.array(metrics).std(axis=0)
49
+
50
+ for idx, (metric_mean, metric_std) in enumerate(zip(metrics_mean, metrics_std)):
51
+ col_mean = f'{self.eval_metrics[idx].name()}_mean'
52
+ col_std = f'{self.eval_metrics[idx].name()}_std'
53
+ report[col_mean] = metric_mean
54
+ report[col_std] = metric_std
55
+ else:
56
+ metrics = metrics[0]
57
+ for i, metric in enumerate(metrics):
58
+ report[self.eval_metrics[i].name()] = metric
59
+
60
+
61
+ results_processed[model] = report
62
+
63
+ return results_processed
64
+
65
+ class ExecutionTimesReporter:
66
+ def __init__(self, output_file):
67
+ self.filename = output_file
68
+
69
+ def report(self, results):
70
+ """
71
+ Creates the .csv file with experiment results
72
+ """
73
+ results = self.__process(results)
74
+ df = pd.DataFrame.from_dict(results, orient='index')
75
+ df['model'] = df.index
76
+ df = df.set_index('model')
77
+
78
+ self.__to_csv(df)
79
+
80
+ def __to_csv(self, df):
81
+ folder = os.path.dirname(self.filename)
82
+ if not os.path.isdir(folder):
83
+ os.makedirs(folder)
84
+ df.to_csv(self.filename)
85
+
86
+ def __process(self, results) -> t.Dict[str, float]:
87
+ """
88
+ returns
89
+ {model_name (machine_specs): {fold-1_execution_time: value, fold-2_execution_time: value, ..., execution_time_mean:value,execution_time_std}}
90
+ """
91
+ results_processed = {}
92
+ for model, execution_times in results.items():
93
+ report = {}
94
+ for fold, execution_time in enumerate(execution_times):
95
+ report[f'fold-{fold+1}_execution_time'] = execution_time
96
+ report['execution_time_mean'] = np.array(execution_times).mean(axis=0)
97
+ report['execution_time_std'] = np.array(execution_times).std(axis=0)
98
+
99
+ results_processed[f'{model} (CPU: {cpuinfo.get_cpu_info()["brand_raw"]}; RAM: {round(psutil.virtual_memory().total/(1024**3))}GB; GPUs: {[gpu.name for gpu in GPUtil.getGPUs()]})'] = report
100
+
101
+ return results_processed
framework/utils.py ADDED
@@ -0,0 +1,10 @@
1
+ def get_optional_argument(config, key, default=False):
2
+ try:
3
+ return config[key]
4
+ except KeyError:
5
+ return default
6
+ except TypeError:
7
+ return default
8
+ except Exception as e:
9
+ print(e)
10
+ return default