chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:36:30 +08:00
commit 55ab4e4a73
473 changed files with 72932 additions and 0 deletions
@@ -0,0 +1,216 @@
import requests
from easygraph.utils.exception import EasyGraphError
def request_text_from_url(url):
"""
Requests text data from the specified URL.
Args:
url (str): The URL from which to request the text data.
Returns:
str: The text content of the response if the request is successful.
Raises:
EasyGraphError: If a connection error occurs during the request or if the HTTP response status code
indicates a failure.
"""
try:
r = requests.get(url)
except requests.ConnectionError:
raise EasyGraphError("Connection Error!")
if r.ok:
return r.text
else:
raise EasyGraphError(f"Error: HTTP response {r.status_code}")
class House_Committees:
"""
A class for loading and processing the House Committees hypergraph dataset.
This class fetches hyperedge, node label, node name, and label name data from predefined URLs,
processes the data, and generates a hypergraph representation. It also provides access to various
dataset attributes through properties and indexing.
Attributes:
data_root (str): The root URL for the data. If `data_root` is provided during initialization,
it is set to "https://"; otherwise, it is `None`.
hyperedges_path (str): The URL of the file containing hyperedge information.
node_labels_path (str): The URL of the file containing node label information.
node_names_path (str): The URL of the file containing node name information.
label_names_path (str): The URL of the file containing label name information.
_hyperedges (list): A list of tuples representing hyperedges.
_node_labels (list): A list of node labels.
_label_names (list): A list of label names.
_node_names (list): A list of node names.
_content (dict): A dictionary containing dataset statistics and data, including the number of
classes, vertices, edges, the edge list, and node labels.
"""
def __init__(self, data_root=None):
"""
Initializes a new instance of the `House_Committees` class.
Args:
data_root (str, optional): The root URL for the data. If provided, it is set to "https://";
otherwise, it is `None`. Defaults to `None`.
"""
self.data_root = "https://" if data_root is not None else data_root
self.hyperedges_path = "https://gitlab.com/easy-graph/easygraph-data-house-committees/-/raw/main/hyperedges-house-committees.txt?inline=false"
self.node_labels_path = "https://gitlab.com/easy-graph/easygraph-data-house-committees/-/raw/main/node-labels-house-committees.txt?ref_type=heads&inline=false"
self.node_names_path = "https://gitlab.com/easy-graph/easygraph-data-house-committees/-/raw/main/node-names-house-committees.txt?ref_type=heads&inline=false"
self.label_names_path = "https://gitlab.com/easy-graph/easygraph-data-house-committees/-/raw/main/label-names-house-committees.txt?ref_type=heads&inline=false"
self._hyperedges = []
self._node_labels = []
self._label_names = []
self._node_names = []
self.generate_hypergraph(
hyperedges_path=self.hyperedges_path,
node_labels_path=self.node_labels_path,
node_names_path=self.node_names_path,
label_names_path=self.label_names_path,
)
self._content = {
"num_classes": len(self._label_names),
"num_vertices": len(self._node_labels),
"num_edges": len(self._hyperedges),
"edge_list": self._hyperedges,
"labels": self._node_labels,
}
def process_label_txt(self, data_str, delimiter="\n", transform_fun=str):
"""
Processes a string containing label data into a list of transformed values.
Args:
data_str (str): The input string containing label data.
delimiter (str, optional): The delimiter used to split the input string. Defaults to "\n".
transform_fun (callable, optional): A function used to transform each label value.
Defaults to the `str` function.
Returns:
list: A list of transformed label values.
"""
data_str = data_str.strip()
data_lst = data_str.split(delimiter)
final_lst = []
for data in data_lst:
data = data.strip()
data = transform_fun(data)
final_lst.append(data)
return final_lst
def __getitem__(self, key: str):
"""
Retrieves a value from the `_content` dictionary using the specified key.
Args:
key (str): The key used to access the `_content` dictionary.
Returns:
Any: The value corresponding to the key in the `_content` dictionary.
"""
return self._content[key]
@property
def node_labels(self):
"""
Gets the list of node labels.
Returns:
list: A list of node labels.
"""
return self._node_labels
@property
def node_names(self):
"""
Gets the list of node names.
Returns:
list: A list of node names.
"""
return self._node_names
@property
def label_names(self):
"""
Gets the list of label names.
Returns:
list: A list of label names.
"""
return self._label_names
@property
def hyperedges(self):
"""
Gets the list of hyperedges.
Returns:
list: A list of tuples representing hyperedges.
"""
return self._hyperedges
def generate_hypergraph(
self,
hyperedges_path=None,
node_labels_path=None,
node_names_path=None,
label_names_path=None,
):
"""
Generates a hypergraph by fetching and processing data from the specified URLs.
Args:
hyperedges_path (str, optional): The URL of the file containing hyperedge information.
Defaults to `None`.
node_labels_path (str, optional): The URL of the file containing node label information.
Defaults to `None`.
node_names_path (str, optional): The URL of the file containing node name information.
Defaults to `None`.
label_names_path (str, optional): The URL of the file containing label name information.
Defaults to `None`.
"""
def fun(data):
"""
Converts a string to an integer and subtracts 1.
Args:
data (str): The input string to be converted.
Returns:
int: The converted integer value minus 1.
"""
data = int(data) - 1
return data
hyperedges_info = request_text_from_url(hyperedges_path)
hyperedges_info = hyperedges_info.strip()
hyperedges_lst = hyperedges_info.split("\n")
for hyperedge in hyperedges_lst:
hyperedge = hyperedge.strip()
hyperedge = [int(i) - 1 for i in hyperedge.split(",")]
self._hyperedges.append(tuple(hyperedge))
# print(self.hyperedges)
node_labels_info = request_text_from_url(node_labels_path)
process_node_labels_info = self.process_label_txt(
node_labels_info, transform_fun=fun
)
self._node_labels = process_node_labels_info
# print("process_node_labels_info:", process_node_labels_info)
node_names_info = request_text_from_url(node_names_path)
process_node_names_info = self.process_label_txt(node_names_info)
self._node_names = process_node_names_info
# print("process_node_names_info:", process_node_names_info)
label_names_info = request_text_from_url(label_names_path)
process_label_names_info = self.process_label_txt(label_names_info)
self._label_names = process_label_names_info
+82
View File
@@ -0,0 +1,82 @@
from typing import Optional
from easygraph.datapipe import load_from_pickle
from easygraph.datapipe import to_long_tensor
from easygraph.datapipe import to_tensor
from easygraph.datasets.hypergraph.hypergraph_dataset_base import BaseData
class YelpRestaurant(BaseData):
r"""The Yelp-Restaurant dataset is a restaurant-review network dataset for node classification task.
More details see the DHG or `YOU ARE ALLSET: A MULTISET LEARNING FRAMEWORK FOR HYPERGRAPH NEURAL NETWORKS <https://openreview.net/pdf?id=hpBTIv2uy_E>`_ paper.
The content of the Yelp-Restaurant dataset includes the following:
- ``num_classes``: The number of classes: :math:`11`.
- ``num_vertices``: The number of vertices: :math:`50,758`.
- ``num_edges``: The number of edges: :math:`679,302`.
- ``dim_features``: The dimension of features: :math:`1,862`.
- ``features``: The vertex feature matrix. ``torch.Tensor`` with size :math:`(50,758 \times 1,862)`.
- ``edge_list``: The edge list. ``List`` with length :math:`679,302`.
- ``labels``: The label list. ``torch.LongTensor`` with size :math:`(50,758, )`.
- ``state``: The state list. ``torch.LongTensor`` with size :math:`(50,758, )`.
- ``city``: The city list. ``torch.LongTensor`` with size :math:`(50,758, )`.
Args:
``data_root`` (``str``, optional): The ``data_root`` has stored the data. If set to ``None``, this function will auto-download from server and save into the default direction ``~/.dhg/datasets/``. Defaults to ``None``.
"""
def __init__(self, data_root: Optional[str] = None) -> None:
super().__init__("yelp_restaurant", data_root)
self._content = {
"num_classes": 11,
"num_vertices": 50758,
"num_edges": 679302,
"dim_features": 1862,
"features": {
"upon": [
{
"filename": "features.pkl",
"md5": "cedc4443884477c2e626025411c44cd7",
}
],
"loader": load_from_pickle,
"preprocess": [
to_tensor,
],
},
"edge_list": {
"upon": [
{
"filename": "edge_list.pkl",
"md5": "4b26eecaa22305dd10edcd6372eb49da",
}
],
"loader": load_from_pickle,
},
"labels": {
"upon": [
{
"filename": "labels.pkl",
"md5": "1cdc1ed9fb1f57b2accaa42db214d4ef",
}
],
"loader": load_from_pickle,
"preprocess": [to_long_tensor],
},
"state": {
"upon": [
{"filename": "state.pkl", "md5": "eef3b835fad37409f29ad36539296b57"}
],
"loader": load_from_pickle,
"preprocess": [to_long_tensor],
},
"city": {
"upon": [
{"filename": "city.pkl", "md5": "8302b167262b23067698e865cacd0b17"}
],
"loader": load_from_pickle,
"preprocess": [to_long_tensor],
},
}
+10
View File
@@ -0,0 +1,10 @@
from .cat_edge_Cooking import *
from .coauthorship import *
from .cocitation import *
from .contact_primary_school import *
from .House_Committees import *
from .mathoverflow_answers import *
from .senate_committees import *
from .trivago_clicks import *
from .walmart_trips import *
from .Yelp import *
+14
View File
@@ -0,0 +1,14 @@
from pathlib import Path
def get_eg_cache_root():
root = Path.home() / Path(".easygraph/")
root.mkdir(parents=True, exist_ok=True)
return root
CACHE_ROOT = get_eg_cache_root()
DATASETS_ROOT = CACHE_ROOT / "datasets"
REMOTE_ROOT = "https://download.moon-lab.tech:28501/"
REMOTE_DATASETS_ROOT = REMOTE_ROOT + "datasets/"
@@ -0,0 +1,104 @@
import requests
from easygraph.utils.exception import EasyGraphError
def request_text_from_url(url):
try:
r = requests.get(url)
except requests.ConnectionError:
raise EasyGraphError("Connection Error!")
if r.ok:
return r.text
else:
raise EasyGraphError(f"Error: HTTP response {r.status_code}")
class cat_edge_Cooking:
def __init__(self, data_root=None):
self.data_root = "https://" if data_root is not None else data_root
self.hyperedges_path = "https://gitlab.com/easy-graph/easygraph-data-cat-edge-cooking/-/raw/main/hyperedges.txt?inline=false"
self.edge_labels_path = "https://gitlab.com/easy-graph/easygraph-data-cat-edge-cooking/-/raw/main/hyperedge-labels.txt?ref_type=heads&inline=false"
self.node_names_path = "https://gitlab.com/easy-graph/easygraph-data-cat-edge-cooking/-/raw/main/main/node-labels.txt?ref_type=heads&inline=false"
self.label_names_path = "https://gitlab.com/easy-graph/easygraph-data-cat-edge-cooking/-/raw/main/hyperedge-label-identities.txt?ref_type=heads&inline=false"
# self.hyperedges_path = []
# self.edge_labels_path = []
# self.node_names_path = []
# self.label_names_path = []
self.generate_hypergraph(
hyperedges_path=self.hyperedges_path,
edge_labels_path=self.edge_labels_path,
node_names_path=self.node_names_path,
label_names_path=self.label_names_path,
)
self._content = {
"num_classes": len(self._label_names),
"num_vertices": len(self._node_labels),
"num_edges": len(self._hyperedges),
"edge_list": self._hyperedges,
"labels": self._node_labels,
}
def __getitem__(self, key: str):
return self._content[key]
def process_label_txt(self, data_str, delimiter="\n", transform_fun=str):
data_str = data_str.strip()
data_lst = data_str.split(delimiter)
final_lst = []
for data in data_lst:
data = data.strip()
data = transform_fun(data)
final_lst.append(data)
return final_lst
@property
def edge_labels(self):
return self._edge_labels
@property
def node_names(self):
return self._node_names
@property
def label_names(self):
return self._label_names
@property
def hyperedges(self):
return self._hyperedges
def generate_hypergraph(
self,
hyperedges_path=None,
node_labels_path=None,
node_names_path=None,
label_names_path=None,
):
def fun(data):
data = int(data) - 1
return data
hyperedges_info = request_text_from_url(hyperedges_path)
hyperedges_info = hyperedges_info.strip()
hyperedges_lst = hyperedges_info.split("\n")
for hyperedge in hyperedges_lst:
hyperedge = hyperedge.strip()
hyperedge = [int(i) - 1 for i in hyperedge.split(" ")]
self._hyperedges.append(tuple(hyperedge))
# print(self.hyperedges)
edge_labels_info = request_text_from_url(self.edge_labels_path)
process_node_labels_info = self.process_label_txt(
node_labels_info, transform_fun=fun
)
self._edge_labels = process_edge_labels_info()
node_names_info = request_text_from_url(node_names_path)
process_node_names_info = self.process_label_txt(node_names_info)
self._node_names = process_node_names_info
label_names_info = request_text_from_url(label_names_path)
process_label_names_info = self.process_label_txt(label_names_info)
self._label_names = process_label_names_info
@@ -0,0 +1,192 @@
from functools import partial
from typing import Optional
from easygraph.datapipe import load_from_pickle
from easygraph.datapipe import norm_ft
from easygraph.datapipe import to_bool_tensor
from easygraph.datapipe import to_long_tensor
from easygraph.datapipe import to_tensor
from easygraph.datasets.hypergraph.hypergraph_dataset_base import BaseData
__all__ = ["CoauthorshipCora", "CoauthorshipDBLP"]
class CoauthorshipCora(BaseData):
r"""The Co-authorship Cora dataset is a citation network dataset for vertex classification task.
More details see the `HyperGCN <https://papers.nips.cc/paper/2019/file/1efa39bcaec6f3900149160693694536-Paper.pdf>`_ paper.
The content of the Co-authorship Cora dataset includes the following:
- ``num_classes``: The number of classes: :math:`7`.
- ``num_vertices``: The number of vertices: :math:`2,708`.
- ``num_edges``: The number of edges: :math:`1,072`.
- ``dim_features``: The dimension of features: :math:`1,433`.
- ``features``: The vertex feature matrix. ``torch.Tensor`` with size :math:`(2,708 \times 1,433)`.
- ``edge_list``: The edge list. ``List`` with length :math:`1,072`.
- ``labels``: The label list. ``torch.LongTensor`` with size :math:`(2,708, )`.
- ``train_mask``: The train mask. ``torch.BoolTensor`` with size :math:`(2,708, )`.
- ``val_mask``: The validation mask. ``torch.BoolTensor`` with size :math:`(2,708, )`.
- ``test_mask``: The test mask. ``torch.BoolTensor`` with size :math:`(2,708, )`.
Args:
``data_root`` (``str``, optional): The ``data_root`` has stored the data. If set to ``None``, this function will auto-download from server and save into the default direction ``~/.dhg/datasets/``. Defaults to ``None``.
"""
def __init__(self, data_root: Optional[str] = None) -> None:
super().__init__("coauthorship_cora", data_root)
self._content = {
"num_classes": 7,
"num_vertices": 2708,
"num_edges": 1072,
"dim_features": 1433,
"features": {
"upon": [
{
"filename": "features.pkl",
"md5": "14257c0e24b4eb741b469a351e524785",
}
],
"loader": load_from_pickle,
"preprocess": [to_tensor, partial(norm_ft, ord=1)],
},
"edge_list": {
"upon": [
{
"filename": "edge_list.pkl",
"md5": "a17ff337f1b9099f5a9d4d670674e146",
}
],
"loader": load_from_pickle,
},
"labels": {
"upon": [
{
"filename": "labels.pkl",
"md5": "c8d11c452e0be69f79a47dd839279117",
}
],
"loader": load_from_pickle,
"preprocess": [to_long_tensor],
},
"train_mask": {
"upon": [
{
"filename": "train_mask.pkl",
"md5": "111db6c6f986be2908378df7bdca7a9b",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"val_mask": {
"upon": [
{
"filename": "val_mask.pkl",
"md5": "ffab1055193ffb2fe74822bb575d332a",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"test_mask": {
"upon": [
{
"filename": "test_mask.pkl",
"md5": "ffab1055193ffb2fe74822bb575d332a",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
}
class CoauthorshipDBLP(BaseData):
r"""The Co-authorship DBLP dataset is a citation network dataset for vertex classification task.
More details see the `HyperGCN <https://papers.nips.cc/paper/2019/file/1efa39bcaec6f3900149160693694536-Paper.pdf>`_ paper.
The content of the Co-authorship DBLP dataset includes the following:
- ``num_classes``: The number of classes: :math:`6`.
- ``num_vertices``: The number of vertices: :math:`41,302`.
- ``num_edges``: The number of edges: :math:`22,363`.
- ``dim_features``: The dimension of features: :math:`1,425`.
- ``features``: The vertex feature matrix. ``torch.Tensor`` with size :math:`(41,302 \times 1,425)`.
- ``edge_list``: The edge list. ``List`` with length :math:`22,363`.
- ``labels``: The label list. ``torch.LongTensor`` with size :math:`(41,302, )`.
- ``train_mask``: The train mask. ``torch.BoolTensor`` with size :math:`(41,302, )`.
- ``val_mask``: The validation mask. ``torch.BoolTensor`` with size :math:`(41,302, )`.
- ``test_mask``: The test mask. ``torch.BoolTensor`` with size :math:`(41,302, )`.
Args:
``data_root`` (``str``, optional): The ``data_root`` has stored the data. If set to ``None``, this function will auto-download from server and save into the default direction ``~/.dhg/datasets/``. Defaults to None.
"""
def __init__(self, data_root: Optional[str] = None) -> None:
super().__init__("coauthorship_dblp", data_root)
self._content = {
"num_classes": 6,
"num_vertices": 41302,
"num_edges": 22363,
"dim_features": 1425,
"features": {
"upon": [
{
"filename": "features.pkl",
"md5": "b78fd31b2586d1e19a40b3f6cd9cc2e7",
}
],
"loader": load_from_pickle,
"preprocess": [to_tensor, partial(norm_ft, ord=1)],
},
"edge_list": {
"upon": [
{
"filename": "edge_list.pkl",
"md5": "c6bf5f9f3b9683bcc9b7bcc9eb8707d8",
}
],
"loader": load_from_pickle,
},
"labels": {
"upon": [
{
"filename": "labels.pkl",
"md5": "2e7a792ea018028d582af8f02f2058ca",
}
],
"loader": load_from_pickle,
"preprocess": [to_long_tensor],
},
"train_mask": {
"upon": [
{
"filename": "train_mask.pkl",
"md5": "a842b795c7cac4c2f98a56cf599bc1de",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"val_mask": {
"upon": [
{
"filename": "val_mask.pkl",
"md5": "2ec4b7df7c5e6b355067a22c391ad578",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"test_mask": {
"upon": [
{
"filename": "test_mask.pkl",
"md5": "2ec4b7df7c5e6b355067a22c391ad578",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
}
+279
View File
@@ -0,0 +1,279 @@
from functools import partial
from typing import Optional
from easygraph.datapipe import load_from_pickle
from easygraph.datapipe import norm_ft
from easygraph.datapipe import to_bool_tensor
from easygraph.datapipe import to_long_tensor
from easygraph.datapipe import to_tensor
from easygraph.datasets.hypergraph.hypergraph_dataset_base import BaseData
class CocitationCora(BaseData):
r"""The Co-citation Cora dataset is a citation network dataset for vertex classification task.
More details see the `HyperGCN <https://papers.nips.cc/paper/2019/file/1efa39bcaec6f3900149160693694536-Paper.pdf>`_ paper.
The content of the Co-citation Cora dataset includes the following:
- ``num_classes``: The number of classes: :math:`7`.
- ``num_vertices``: The number of vertices: :math:`2,708`.
- ``num_edges``: The number of edges: :math:`1,579`.
- ``dim_features``: The dimension of features: :math:`1,433`.
- ``features``: The vertex feature matrix. ``torch.Tensor`` with size :math:`(2,708 \times 1,433)`.
- ``edge_list``: The edge list. ``List`` with length :math:`1,579`.
- ``labels``: The label list. ``torch.LongTensor`` with size :math:`(2,708, )`.
- ``train_mask``: The train mask. ``torch.BoolTensor`` with size :math:`(2,708, )`.
- ``val_mask``: The validation mask. ``torch.BoolTensor`` with size :math:`(2,708, )`.
- ``test_mask``: The test mask. ``torch.BoolTensor`` with size :math:`(2,708, )`.
Args:
``data_root`` (``str``, optional): The ``data_root`` has stored the data. If set to ``None``, this function will auto-download from server and save into the default direction ``~/.dhg/datasets/``. Defaults to ``None``.
"""
def __init__(self, data_root: Optional[str] = None) -> None:
super().__init__("cocitation_cora", data_root)
self._content = {
"num_classes": 7,
"num_vertices": 2708,
"num_edges": 1579,
"dim_features": 1433,
"features": {
"upon": [
{
"filename": "features.pkl",
"md5": "14257c0e24b4eb741b469a351e524785",
}
],
"loader": load_from_pickle,
"preprocess": [to_tensor, partial(norm_ft, ord=1)],
},
"edge_list": {
"upon": [
{
"filename": "edge_list.pkl",
"md5": "e43d1321880c8ecb2260d8fb7effd9ea",
}
],
"loader": load_from_pickle,
},
"labels": {
"upon": [
{
"filename": "labels.pkl",
"md5": "c8d11c452e0be69f79a47dd839279117",
}
],
"loader": load_from_pickle,
"preprocess": [to_long_tensor],
},
"train_mask": {
"upon": [
{
"filename": "train_mask.pkl",
"md5": "111db6c6f986be2908378df7bdca7a9b",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"val_mask": {
"upon": [
{
"filename": "val_mask.pkl",
"md5": "ffab1055193ffb2fe74822bb575d332a",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"test_mask": {
"upon": [
{
"filename": "test_mask.pkl",
"md5": "ffab1055193ffb2fe74822bb575d332a",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
}
class CocitationCiteseer(BaseData):
r"""The Co-citation Citeseer dataset is a citation network dataset for vertex classification task.
More details see the `HyperGCN <https://papers.nips.cc/paper/2019/file/1efa39bcaec6f3900149160693694536-Paper.pdf>`_ paper.
The content of the Co-citation Citaseer dataset includes the following:
- ``num_classes``: The number of classes: :math:`6`.
- ``num_vertices``: The number of vertices: :math:`3,312`.
- ``num_edges``: The number of edges: :math:`1,079`.
- ``dim_features``: The dimension of features: :math:`3,703`.
- ``features``: The vertex feature matrix. ``torch.Tensor`` with size :math:`(3,312 \times 3,703)`.
- ``edge_list``: The edge list. ``List`` with length :math:`1,079`.
- ``labels``: The label list. ``torch.LongTensor`` with size :math:`(3,312, )`.
- ``train_mask``: The train mask. ``torch.BoolTensor`` with size :math:`(3,312, )`.
- ``val_mask``: The validation mask. ``torch.BoolTensor`` with size :math:`(3,312, )`.
- ``test_mask``: The test mask. ``torch.BoolTensor`` with size :math:`(3,312, )`.
Args:
``data_root`` (``str``, optional): The ``data_root`` has stored the data. If set to ``None``, this function will auto-download from server and save into the default direction ``~/.dhg/datasets/``. Defaults to ``None``.
"""
def __init__(self, data_root: Optional[str] = None) -> None:
super().__init__("cocitation_citeseer", data_root)
self._content = {
"num_classes": 6,
"num_vertices": 3312,
"num_edges": 1079,
"dim_features": 3703,
"features": {
"upon": [
{
"filename": "features.pkl",
"md5": "1ee0dc89e0d5f5ac9187b55a407683e8",
}
],
"loader": load_from_pickle,
"preprocess": [to_tensor, partial(norm_ft, ord=1)],
},
"edge_list": {
"upon": [
{
"filename": "edge_list.pkl",
"md5": "6687b2e96159c534a424253f536b49ae",
}
],
"loader": load_from_pickle,
},
"labels": {
"upon": [
{
"filename": "labels.pkl",
"md5": "71069f78e83fa85dd6a4b9b6570447c2",
}
],
"loader": load_from_pickle,
"preprocess": [to_long_tensor],
},
"train_mask": {
"upon": [
{
"filename": "train_mask.pkl",
"md5": "3b831318fc3d3e588bead5ba469fe38f",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"val_mask": {
"upon": [
{
"filename": "val_mask.pkl",
"md5": "c22eb5b7493908042c7e039c8bb5a82e",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"test_mask": {
"upon": [
{
"filename": "test_mask.pkl",
"md5": "c22eb5b7493908042c7e039c8bb5a82e",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
}
class CocitationPubmed(BaseData):
r"""The Co-citation PubMed dataset is a citation network dataset for vertex classification task.
More details see the `HyperGCN <https://papers.nips.cc/paper/2019/file/1efa39bcaec6f3900149160693694536-Paper.pdf>`_ paper.
The content of the Co-citation PubMed dataset includes the following:
- ``num_classes``: The number of classes: :math:`3`.
- ``num_vertices``: The number of vertices: :math:`19,717`.
- ``num_edges``: The number of edges: :math:`7,963`.
- ``dim_features``: The dimension of features: :math:`500`.
- ``features``: The vertex feature matrix. ``torch.Tensor`` with size :math:`(19,717 \times 500)`.
- ``edge_list``: The edge list. ``List`` with length :math:`7,963`.
- ``labels``: The label list. ``torch.LongTensor`` with size :math:`(19,717, )`.
- ``train_mask``: The train mask. ``torch.BoolTensor`` with size :math:`(19,717, )`.
- ``val_mask``: The validation mask. ``torch.BoolTensor`` with size :math:`(19,717, )`.
- ``test_mask``: The test mask. ``torch.BoolTensor`` with size :math:`(19,717, )`.
Args:
``data_root`` (``str``, optional): The ``data_root`` has stored the data. If set to ``None``, this function will auto-download from server and save into the default direction ``~/.dhg/datasets/``. Defaults to ``None``.
"""
def __init__(self, data_root: Optional[str] = None) -> None:
super().__init__("cocitation_pubmed", data_root)
self._content = {
"num_classes": 3,
"num_vertices": 19717,
"num_edges": 7963,
"dim_features": 500,
"features": {
"upon": [
{
"filename": "features.pkl",
"md5": "f89502c432ca451156a8235c5efc034e",
}
],
"loader": load_from_pickle,
"preprocess": [to_tensor, partial(norm_ft, ord=1)],
},
"edge_list": {
"upon": [
{
"filename": "edge_list.pkl",
"md5": "c5fbedf63e5be527f200e8c4e0391b00",
}
],
"loader": load_from_pickle,
},
"labels": {
"upon": [
{
"filename": "labels.pkl",
"md5": "c039f778409a15f9b2ceefacad9c2202",
}
],
"loader": load_from_pickle,
"preprocess": [to_long_tensor],
},
"train_mask": {
"upon": [
{
"filename": "train_mask.pkl",
"md5": "81b422937f3adccd89a334d7093b67d7",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"val_mask": {
"upon": [
{
"filename": "val_mask.pkl",
"md5": "10717940ddbfa3e4f6c0b148bb394f79",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"test_mask": {
"upon": [
{
"filename": "test_mask.pkl",
"md5": "10717940ddbfa3e4f6c0b148bb394f79",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
}
@@ -0,0 +1,183 @@
import requests
from easygraph.utils.exception import EasyGraphError
def request_text_from_url(url):
"""Requests text data from the specified URL.
Args:
url (str): The URL from which to request data.
Returns:
str: The text content of the response if the request is successful.
Raises:
EasyGraphError: If a connection error occurs or the HTTP response status code indicates failure.
"""
try:
r = requests.get(url)
except requests.ConnectionError:
raise EasyGraphError("Connection Error!")
if r.ok:
return r.text
else:
raise EasyGraphError(f"Error: HTTP response {r.status_code}")
class contact_primary_school:
"""A class for loading and processing the primary school contact network hypergraph dataset.
This class loads hyperedge, node label, and label name data from specified URLs and generates a hypergraph.
Attributes:
data_root (str): The root URL for the data. If not provided, it is set to None.
hyperedges_path (str): The URL for the hyperedge data.
node_labels_path (str): The URL for the node label data.
label_names_path (str): The URL for the label name data.
_hyperedges (list): A list storing hyperedges.
_node_labels (list): A list storing node labels.
_label_names (list): A list storing label names.
_node_names (list): A list storing node names (currently unused).
_content (dict): A dictionary containing dataset statistics and data.
"""
def __init__(self, data_root=None):
"""Initializes an instance of the contact_primary_school class.
Args:
data_root (str, optional): The root URL for the data. Defaults to None.
"""
self.data_root = "https://" if data_root is not None else data_root
self.hyperedges_path = "https://gitlab.com/easy-graph/easygraph-data-contact-primary-school/-/raw/main/hyperedges-contact-primary-school.txt?inline=false"
self.node_labels_path = "https://gitlab.com/easy-graph/easygraph-data-contact-primary-school/-/raw/main/node-labels-contact-primary-school.txt?ref_type=heads&inline=false"
# self.node_names_path = "https://gitlab.com/easy-graph/easygraph-data-house-committees/-/raw/main/node-names-house-committees.txt?ref_type=heads&inline=false"
self.label_names_path = "https://gitlab.com/easy-graph/easygraph-data-contact-primary-school/-/raw/main/label-names-contact-primary-school.txt?ref_type=heads&inline=false"
self._hyperedges = []
self._node_labels = []
self._label_names = []
self._node_names = []
self.generate_hypergraph(
hyperedges_path=self.hyperedges_path,
node_labels_path=self.node_labels_path,
# node_names_path=self.node_names_path,
label_names_path=self.label_names_path,
)
self._content = {
"num_classes": len(self._label_names),
"num_vertices": len(self._node_labels),
"num_edges": len(self._hyperedges),
"edge_list": self._hyperedges,
"labels": self._node_labels,
}
def __getitem__(self, key: str):
"""Accesses data in the _content dictionary by key.
Args:
key (str): The key of the data to access.
Returns:
Any: The value corresponding to the key in the _content dictionary.
"""
return self._content[key]
def process_label_txt(self, data_str, delimiter="\n", transform_fun=str):
"""Processes label data read from a text file.
Args:
data_str (str): A string containing label data.
delimiter (str, optional): The delimiter used to split the string. Defaults to "\n".
transform_fun (callable, optional): A function used to transform each label. Defaults to str.
Returns:
list: A list of processed labels.
"""
data_str = data_str.strip()
data_lst = data_str.split(delimiter)
final_lst = []
for data in data_lst:
data = data.strip()
data = transform_fun(data)
final_lst.append(data)
return final_lst
@property
def node_labels(self):
"""Gets the list of node labels.
Returns:
list: A list of node labels.
"""
return self._node_labels
"""
@property
def node_names(self):
return self._node_names
"""
@property
def label_names(self):
"""Gets the list of label names.
Returns:
list: A list of label names.
"""
return self._label_names
@property
def hyperedges(self):
"""Gets the list of hyperedges.
Returns:
list: A list of hyperedges.
"""
return self._hyperedges
def generate_hypergraph(
self,
hyperedges_path=None,
node_labels_path=None,
# node_names_path=None,
label_names_path=None,
):
"""Generates hypergraph data from specified URLs.
Args:
hyperedges_path (str, optional): The URL for the hyperedge data. Defaults to None.
node_labels_path (str, optional): The URL for the node label data. Defaults to None.
label_names_path (str, optional): The URL for the label name data. Defaults to None.
"""
def fun(data):
"""Converts the input data to an integer and subtracts 1.
Args:
data (str): The input string data.
Returns:
int: The converted integer data.
"""
data = int(data) - 1
return data
hyperedges_info = request_text_from_url(hyperedges_path)
hyperedges_info = hyperedges_info.strip()
hyperedges_lst = hyperedges_info.split("\n")
for hyperedge in hyperedges_lst:
hyperedge = hyperedge.strip()
hyperedge = [int(i) - 1 for i in hyperedge.split(",")]
self._hyperedges.append(tuple(hyperedge))
# print(self.hyperedges)
node_labels_info = request_text_from_url(node_labels_path)
process_node_labels_info = self.process_label_txt(
node_labels_info, transform_fun=fun
)
self._node_labels = process_node_labels_info
label_names_info = request_text_from_url(label_names_path)
process_label_names_info = self.process_label_txt(label_names_info)
self._label_names = process_label_names_info
@@ -0,0 +1,85 @@
from typing import Optional
from easygraph.datapipe import load_from_pickle
from easygraph.datapipe import to_bool_tensor
from easygraph.datapipe import to_long_tensor
from easygraph.datasets.hypergraph.hypergraph_dataset_base import BaseData
class Cooking200(BaseData):
r"""The Cooking 200 dataset is collected from `Yummly.com <https://www.yummly.com/>`_ for vertex classification task.
It is a hypergraph dataset, in which vertex denotes the dish and hyperedge denotes
the ingredient. Each dish is also associated with category information, which indicates the dish's cuisine like
Chinese, Japanese, French, and Russian.
The content of the Cooking200 dataset includes the following:
- ``num_classes``: The number of classes: :math:`20`.
- ``num_vertices``: The number of vertices: :math:`7,403`.
- ``num_edges``: The number of edges: :math:`2,755`.
- ``edge_list``: The edge list. ``List`` with length :math:`(2,755)`.
- ``labels``: The label list. ``torch.LongTensor`` with size :math:`(7,403)`.
- ``train_mask``: The train mask. ``torch.BoolTensor`` with size :math:`(7,403)`.
- ``val_mask``: The validation mask. ``torch.BoolTensor`` with size :math:`(7,403)`.
- ``test_mask``: The test mask. ``torch.BoolTensor`` with size :math:`(7,403)`.
Args:
``data_root`` (``str``, optional): The ``data_root`` has stored the data. If set to ``None``, this function will auto-download from server and save into the default direction ``~/.dhg/datasets/``. Defaults to ``None``.
"""
def __init__(self, data_root: Optional[str] = None) -> None:
super().__init__("cooking_200", data_root)
self._content = {
"num_classes": 20,
"num_vertices": 7403,
"num_edges": 2755,
"edge_list": {
"upon": [
{
"filename": "edge_list.pkl",
"md5": "2cd32e13dd4e33576c43936542975220",
}
],
"loader": load_from_pickle,
},
"labels": {
"upon": [
{
"filename": "labels.pkl",
"md5": "f1f3c0399c9c28547088f44e0bfd5c81",
}
],
"loader": load_from_pickle,
"preprocess": [to_long_tensor],
},
"train_mask": {
"upon": [
{
"filename": "train_mask.pkl",
"md5": "66ea36bae024aaaed289e1998fe894bd",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"val_mask": {
"upon": [
{
"filename": "val_mask.pkl",
"md5": "6c0d3d8b752e3955c64788cc65dcd018",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
"test_mask": {
"upon": [
{
"filename": "test_mask.pkl",
"md5": "0e1564904551ba493e1f8a09d103461e",
}
],
"loader": load_from_pickle,
"preprocess": [to_bool_tensor],
},
}
@@ -0,0 +1,119 @@
from pathlib import Path
from typing import Any
from typing import Dict
from typing import List
from easygraph.datapipe import compose_pipes
from easygraph.datasets.hypergraph._global import DATASETS_ROOT
from easygraph.datasets.hypergraph._global import REMOTE_DATASETS_ROOT
from easygraph.datasets.utils import download_and_check
class BaseData:
r"""The Base Class of all datasets.
::
self._content = {
'item': {
'upon': [
{'filename': 'part1.pkl', 'md5': 'xxxxx',},
{'filename': 'part2.pkl', 'md5': 'xxxxx',},
],
'loader': loader_function,
'preprocess': [datapipe1, datapipe2],
},
...
}
"""
def __init__(self, name: str, data_root=None):
# configure the data local/remote root
self.name = name
if data_root is None:
self.data_root = DATASETS_ROOT / name
else:
self.data_root = Path(data_root) / name
self.remote_root = REMOTE_DATASETS_ROOT + name + "/"
# init
self._content = {}
self._raw = {}
def __repr__(self) -> str:
return (
f"This is {self.name} dataset:\n"
+ "\n".join(f" -> {k}" for k in self.content)
+ "\nPlease try `data['name']` to get the specified data."
)
@property
def content(self):
r"""Return the content of the dataset."""
return list(self._content.keys())
def needs_to_load(self, item_name: str) -> bool:
r"""Return whether the ``item_name`` of the dataset needs to be loaded.
Args:
``item_name`` (``str``): The name of the item in the dataset.
"""
assert item_name in self.content, f"{item_name} is not provided in the Data"
return (
isinstance(self._content[item_name], dict)
and "upon" in self._content[item_name]
and "loader" in self._content[item_name]
)
def __getitem__(self, key: str) -> Any:
if self.needs_to_load(key):
cur_cfg = self._content[key]
if cur_cfg.get("cache", None) is None:
# get raw data
item = self.raw(key)
# preprocess and cache
pipes = cur_cfg.get("preprocess", None)
if pipes is not None:
cur_cfg["cache"] = compose_pipes(*pipes)(item)
else:
cur_cfg["cache"] = item
return cur_cfg["cache"]
else:
return self._content[key]
def raw(self, key: str) -> Any:
r"""Return the ``key`` of the dataset with un-preprocessed format."""
if self.needs_to_load(key):
cur_cfg = self._content[key]
if self._raw.get(key, None) is None:
upon = cur_cfg["upon"]
if len(upon) == 0:
return None
self.fetch_files(cur_cfg["upon"])
file_path_list = [
self.data_root / u["filename"] for u in cur_cfg["upon"]
]
if len(file_path_list) == 1:
self._raw[key] = cur_cfg["loader"](file_path_list[0])
else:
# here, you should implement a multi-file loader
self._raw[key] = cur_cfg["loader"](file_path_list)
return self._raw[key]
else:
return self._content[key]
def fetch_files(self, files: List[Dict[str, str]]):
r"""Download and check the files if they are not exist.
Args:
``files`` (``List[Dict[str, str]]``): The files to download, each element
in the list is a dict with at lease two keys: ``filename`` and ``md5``.
If extra key ``bk_url`` is provided, it will be used to download the
file from the backup url.
"""
for file in files:
cur_filename = file["filename"]
cur_url = file.get("bk_url", None)
if cur_url is None:
cur_url = self.remote_root + cur_filename
download_and_check(cur_url, self.data_root / cur_filename, file["md5"])
@@ -0,0 +1,78 @@
import os.path as osp
import numpy as np
import scipy.sparse as sp
import torch
from torch_geometric.data import Data
from torch_sparse import coalesce
__all__ = ["load_line_expansion_dataset"]
def load_line_expansion_dataset(
path=None, dataset="cocitation-cora", train_percent=0.5
):
# load edges, features, and labels.
print("Loading {} dataset...".format(dataset))
file_name = f"{dataset}.content"
p2idx_features_labels = osp.join(path, dataset, file_name)
idx_features_labels = np.genfromtxt(p2idx_features_labels, dtype=np.dtype(str))
# features = np.array(idx_features_labels[:, 1:-1])
features = sp.csr_matrix(idx_features_labels[:, 1:-1], dtype=np.float32)
# labels = encode_onehot(idx_features_labels[:, -1])
labels = torch.LongTensor(idx_features_labels[:, -1].astype(float))
print("load features")
# build graph
idx = np.array(idx_features_labels[:, 0], dtype=np.int32)
idx_map = {j: i for i, j in enumerate(idx)}
file_name = f"{dataset}.edges"
p2edges_unordered = osp.join(path, dataset, file_name)
edges_unordered = np.genfromtxt(p2edges_unordered, dtype=np.int32)
edges = np.array(
list(map(idx_map.get, edges_unordered.flatten())), dtype=np.int32
).reshape(edges_unordered.shape)
print("load edges")
# From adjacency matrix to edge_list
edge_index = edges.T
# ipdb.set_trace()
assert edge_index[0].max() == edge_index[1].min() - 1
# check if values in edge_index is consecutive. i.e. no missing value for node_id/he_id.
assert len(np.unique(edge_index)) == edge_index.max() + 1
num_nodes = edge_index[0].max() + 1
num_he = edge_index[1].max() - num_nodes + 1
edge_index = np.hstack((edge_index, edge_index[::-1, :]))
# build torch data class
data = Data(
x=torch.FloatTensor(np.array(features[:num_nodes].todense())),
edge_index=torch.LongTensor(edge_index),
y=labels[:num_nodes],
)
# used user function to override the default function.
# the following will also sort the edge_index and remove duplicates.
total_num_node_id_he_id = len(np.unique(edge_index))
data.edge_index, data.edge_attr = coalesce(
data.edge_index, None, total_num_node_id_he_id, total_num_node_id_he_id
)
n_x = num_nodes
# n_x = n_expanded
num_class = len(np.unique(labels[:num_nodes].numpy()))
data.n_x = n_x
# add parameters to attribute
data.train_percent = train_percent
data.num_hyperedges = num_he
return data
@@ -0,0 +1,113 @@
import requests
from easygraph.utils.exception import EasyGraphError
def request_text_from_url(url):
try:
r = requests.get(url)
except requests.ConnectionError:
raise EasyGraphError("Connection Error!")
if r.ok:
return r.text
else:
raise EasyGraphError(f"Error: HTTP response {r.status_code}")
class mathoverflow_answers:
def __init__(self, data_root=None):
self.data_root = "https://" if data_root is not None else data_root
self.hyperedges_path = "https://gitlab.com/easy-graph/easygraph-data-mathoverflow-answers/-/raw/main/hyperedges-mathoverflow-answers.txt?inline=false"
self.node_labels_path = "https://gitlab.com/easy-graph/easygraph-data-mathoverflow-answers/-/raw/main/node-labels-mathoverflow-answers.txt?ref_type=heads&inline=false"
# self.node_names_path = "https://gitlab.com/easy-graph/easygraph-data-house-committees/-/raw/main/node-names-house-committees.txt?ref_type=heads&inline=false"
self.label_names_path = "https://gitlab.com/easy-graph/easygraph-data-mathoverflow-answers/-/raw/main/label-names-mathoverflow-answers.txt?ref_type=heads&inline=false"
self._hyperedges = []
self._node_labels = []
self._label_names = []
self._node_names = []
self.generate_hypergraph(
hyperedges_path=self.hyperedges_path,
node_labels_path=self.node_labels_path,
# node_names_path=self.node_names_path,
label_names_path=self.label_names_path,
)
self._content = {
"num_classes": len(self._label_names),
"num_vertices": len(self._node_labels),
"num_edges": len(self._hyperedges),
"edge_list": self._hyperedges,
"labels": self._node_labels,
}
def __getitem__(self, key: str):
return self._content[key]
def process_label_txt(self, data_str, delimiter="\n", transform_fun=str):
data_str = data_str.strip()
data_lst = data_str.split(delimiter)
final_lst = []
for data in data_lst:
data = data.strip()
data = transform_fun(data)
final_lst.append(data)
return final_lst
@property
def node_labels(self):
return self._node_labels
"""
@property
def node_names(self):
return self._node_names
"""
@property
def label_names(self):
return self._label_names
@property
def hyperedges(self):
return self._hyperedges
def generate_hypergraph(
self,
hyperedges_path=None,
node_labels_path=None,
# node_names_path=None,
label_names_path=None,
):
def fun(data):
data = int(data) - 1
return data
hyperedges_info = request_text_from_url(hyperedges_path)
hyperedges_info = hyperedges_info.strip()
hyperedges_lst = hyperedges_info.split("\n")
for hyperedge in hyperedges_lst:
hyperedge = hyperedge.strip()
hyperedge = [int(i) - 1 for i in hyperedge.split(",")]
self._hyperedges.append(tuple(hyperedge))
# print(self.hyperedges)
"""
node_labels_info = request_text_from_url(node_labels_path)
process_node_labels_info = self.process_label_txt(
node_labels_info, transform_fun=fun
)
self._node_labels = process_node_labels_info
"""
node_labels_info = request_text_from_url(node_labels_path)
node_labels_info = node_labels_info.strip()
node_labels_lst = node_labels_info.split("\n")
for node_label in node_labels_lst:
node_label = node_label.strip()
node_label = [int(i) - 1 for i in node_label.split(",")]
self._node_labels.append(tuple(node_label))
# print("process_node_labels_info:", process_node_labels_info)
# print("process_node_names_info:", process_node_names_info)
label_names_info = request_text_from_url(label_names_path)
process_label_names_info = self.process_label_txt(label_names_info)
self._label_names = process_label_names_info
# print("process_label_names_info:", process_label_names_info)
@@ -0,0 +1,106 @@
import requests
from easygraph.utils.exception import EasyGraphError
def request_text_from_url(url):
try:
r = requests.get(url)
except requests.ConnectionError:
raise EasyGraphError("Connection Error!")
if r.ok:
return r.text
else:
raise EasyGraphError(f"Error: HTTP response {r.status_code}")
class senate_committees:
def __init__(self, data_root=None):
self.data_root = "https://" if data_root is not None else data_root
self.hyperedges_path = "https://gitlab.com/easy-graph/easygraph-data-senate-committees/-/raw/main/hyperedges-senate-committees.txt?inline=false"
self.node_labels_path = "https://gitlab.com/easy-graph/easygraph-data-senate-committees/-/raw/main/node-labels-senate-committees.txt?ref_type=heads&inline=false"
self.node_names_path = "https://gitlab.com/easy-graph/easygraph-data-senate-committees/-/raw/main/node-names-senate-committees.txt?ref_type=heads&inline=false"
self.label_names_path = "https://gitlab.com/easy-graph/easygraph-data-senate-committees/-/raw/main/label-names-senate-committees.txt?ref_type=heads&inline=false"
self._hyperedges = []
self._node_labels = []
self._label_names = []
self._node_names = []
self.generate_hypergraph(
hyperedges_path=self.hyperedges_path,
node_labels_path=self.node_labels_path,
node_names_path=self.node_names_path,
label_names_path=self.label_names_path,
)
self._content = {
"num_classes": len(self._label_names),
"num_vertices": len(self._node_labels),
"num_edges": len(self._hyperedges),
"edge_list": self._hyperedges,
"labels": self._node_labels,
}
def __getitem__(self, key: str):
return self._content[key]
def process_label_txt(self, data_str, delimiter="\n", transform_fun=str):
data_str = data_str.strip()
data_lst = data_str.split(delimiter)
final_lst = []
for data in data_lst:
data = data.strip()
data = transform_fun(data)
final_lst.append(data)
return final_lst
@property
def node_labels(self):
return self._node_labels
@property
def node_names(self):
return self._node_names
@property
def label_names(self):
return self._label_names
@property
def hyperedges(self):
return self._hyperedges
def generate_hypergraph(
self,
hyperedges_path=None,
node_labels_path=None,
node_names_path=None,
label_names_path=None,
):
def fun(data):
data = int(data) - 1
return data
hyperedges_info = request_text_from_url(hyperedges_path)
hyperedges_info = hyperedges_info.strip()
hyperedges_lst = hyperedges_info.split("\n")
for hyperedge in hyperedges_lst:
hyperedge = hyperedge.strip()
hyperedge = [int(i) - 1 for i in hyperedge.split(",")]
self._hyperedges.append(tuple(hyperedge))
# print(self.hyperedges)
node_labels_info = request_text_from_url(node_labels_path)
process_node_labels_info = self.process_label_txt(
node_labels_info, transform_fun=fun
)
self._node_labels = process_node_labels_info
# print("process_node_labels_info:", process_node_labels_info)
node_names_info = request_text_from_url(node_names_path)
process_node_names_info = self.process_label_txt(node_names_info)
self._node_names = process_node_names_info
# print("process_node_names_info:", process_node_names_info)
label_names_info = request_text_from_url(label_names_path)
process_label_names_info = self.process_label_txt(label_names_info)
self._label_names = process_label_names_info
# print("process_label_names_info:", process_label_names_info)
@@ -0,0 +1,104 @@
import requests
from easygraph.utils.exception import EasyGraphError
def request_text_from_url(url):
try:
r = requests.get(url)
except requests.ConnectionError:
raise EasyGraphError("Connection Error!")
if r.ok:
return r.text
else:
raise EasyGraphError(f"Error: HTTP response {r.status_code}")
class trivago_clicks:
def __init__(self, data_root=None):
self.data_root = "https://" if data_root is not None else data_root
self.hyperedges_path = "https://gitlab.com/easy-graph/easygraph-data-trivago-clicks/-/raw/main/hyperedges-trivago-clicks.txt?inline=false"
self.node_labels_path = "https://gitlab.com/easy-graph/easygraph-data-trivago-clicks/-/raw/main/node-labels-trivago-clicks.txt?ref_type=heads&inline=false"
# self.node_names_path = "https://gitlab.com/easy-graph/easygraph-data-trivago-clicks/-/raw/main/node-names-house-committees.txt?ref_type=heads&inline=false"
self.label_names_path = "https://gitlab.com/easy-graph/easygraph-data-trivago-clicks/-/raw/main/label-names-trivago-clicks.txt?ref_type=heads&inline=false"
self._hyperedges = []
self._node_labels = []
self._label_names = []
self._node_names = []
self.generate_hypergraph(
hyperedges_path=self.hyperedges_path,
node_labels_path=self.node_labels_path,
# node_names_path=self.node_names_path,
label_names_path=self.label_names_path,
)
self._content = {
"num_classes": len(self._label_names),
"num_vertices": len(self._node_labels),
"num_edges": len(self._hyperedges),
"edge_list": self._hyperedges,
"labels": self._node_labels,
}
def __getitem__(self, key: str):
return self._content[key]
def process_label_txt(self, data_str, delimiter="\n", transform_fun=str):
data_str = data_str.strip()
data_lst = data_str.split(delimiter)
final_lst = []
for data in data_lst:
data = data.strip()
data = transform_fun(data)
final_lst.append(data)
return final_lst
@property
def node_labels(self):
return self._node_labels
"""
@property
def node_names(self):
return self._node_names
"""
@property
def label_names(self):
return self._label_names
@property
def hyperedges(self):
return self._hyperedges
def generate_hypergraph(
self,
hyperedges_path=None,
node_labels_path=None,
# node_names_path=None,
label_names_path=None,
):
def fun(data):
data = int(data) - 1
return data
hyperedges_info = request_text_from_url(hyperedges_path)
hyperedges_info = hyperedges_info.strip()
hyperedges_lst = hyperedges_info.split("\n")
for hyperedge in hyperedges_lst:
hyperedge = hyperedge.strip()
hyperedge = [int(i) - 1 for i in hyperedge.split(",")]
self._hyperedges.append(tuple(hyperedge))
# print(self.hyperedges)
node_labels_info = request_text_from_url(node_labels_path)
process_node_labels_info = self.process_label_txt(
node_labels_info, transform_fun=fun
)
self._node_labels = process_node_labels_info
# print("process_node_labels_info:", process_node_labels_info)
# print("process_node_names_info:", process_node_names_info)
label_names_info = request_text_from_url(label_names_path)
process_label_names_info = self.process_label_txt(label_names_info)
self._label_names = process_label_names_info
@@ -0,0 +1,208 @@
import requests
from easygraph.utils.exception import EasyGraphError
def request_text_from_url(url):
"""
Requests text content from the given URL.
Args:
url (str): The URL from which to request text data.
Returns:
str: The text content of the response if the request is successful.
Raises:
EasyGraphError: If a connection error occurs during the request or if the HTTP response status code is not OK.
"""
try:
r = requests.get(url)
except requests.ConnectionError:
raise EasyGraphError("Connection Error!")
if r.ok:
return r.text
else:
raise EasyGraphError(f"Error: HTTP response {r.status_code}")
class walmart_trips:
"""
A class for loading and processing the Walmart trips hypergraph dataset.
This class fetches hyperedge, node label, and label name data from predefined URLs,
processes the data, and generates a hypergraph representation. It also provides access
to various dataset attributes through properties and indexing.
Attributes:
data_root (str): The root URL for the data. If provided during initialization, it is set to "https://";
otherwise, it is None.
hyperedges_path (str): The URL of the file containing hyperedge information.
node_labels_path (str): The URL of the file containing node label information.
label_names_path (str): The URL of the file containing label name information.
_hyperedges (list): A list of tuples representing hyperedges.
_node_labels (list): A list of node labels.
_label_names (list): A list of label names.
_node_names (list): An empty list reserved for node names (currently unused).
_content (dict): A dictionary containing dataset statistics and data, such as the number of classes,
vertices, edges, the edge list, and node labels.
"""
def __init__(self, data_root=None, local_path=None):
"""
Initializes an instance of the walmart_trips class.
Args:
data_root (str, optional): The root URL for the data. If provided, it is set to "https://";
otherwise, it is None. Defaults to None.
local_path (str, optional): Currently unused. Defaults to None.
"""
self.data_root = "https://" if data_root is not None else data_root
self.hyperedges_path = "https://gitlab.com/easy-graph/easygraph-data-walmart-trips/-/raw/main/hyperedges-walmart-trips.txt?inline=false"
self.node_labels_path = "https://gitlab.com/easy-graph/easygraph-data-walmart-trips/-/raw/main/node-labels-walmart-trips.txt?ref_type=heads&inline=false"
# self.node_names_path = "https://gitlab.com/easy-graph/easygraph-data-walmart-trips/-/raw/main/node-names-house-committees.txt?ref_type=heads&inline=false"
self.label_names_path = "https://gitlab.com/easy-graph/easygraph-data-walmart-trips/-/raw/main/label-names-walmart-trips.txt?ref_type=heads&inline=false"
self._hyperedges = []
self._node_labels = []
self._label_names = []
self._node_names = []
self.generate_hypergraph(
hyperedges_path=self.hyperedges_path,
node_labels_path=self.node_labels_path,
# node_names_path=self.node_names_path,
label_names_path=self.label_names_path,
)
self._content = {
"num_classes": len(self._label_names),
"num_vertices": len(self._node_labels),
"num_edges": len(self._hyperedges),
"edge_list": self._hyperedges,
"labels": self._node_labels,
}
def __getitem__(self, key: str):
"""
Retrieves a value from the _content dictionary using the specified key.
Args:
key (str): The key used to access the _content dictionary.
Returns:
Any: The value corresponding to the key in the _content dictionary.
"""
return self._content[key]
def process_label_txt(self, data_str, delimiter="\n", transform_fun=str):
"""
Processes a string containing label data into a list of transformed values.
Args:
data_str (str): The input string containing label data.
delimiter (str, optional): The delimiter used to split the input string. Defaults to "\n".
transform_fun (callable, optional): A function used to transform each label value.
Defaults to the str function.
Returns:
list: A list of transformed label values.
"""
data_str = data_str.strip()
data_lst = data_str.split(delimiter)
final_lst = []
for data in data_lst:
data = data.strip()
data = transform_fun(data)
final_lst.append(data)
return final_lst
@property
def node_labels(self):
"""
Gets the list of node labels.
Returns:
list: A list of node labels.
"""
return self._node_labels
"""
@property
def node_names(self):
return self._node_names
"""
@property
def label_names(self):
"""
Gets the list of label names.
Returns:
list: A list of label names.
"""
return self._label_names
@property
def hyperedges(self):
"""
Gets the list of hyperedges.
Returns:
list: A list of tuples representing hyperedges.
"""
return self._hyperedges
def generate_hypergraph(
self,
hyperedges_path=None,
node_labels_path=None,
# node_names_path=None,
label_names_path=None,
):
"""
Generates a hypergraph by fetching and processing data from the specified URLs.
Args:
hyperedges_path (str, optional): The URL of the file containing hyperedge information.
Defaults to None.
node_labels_path (str, optional): The URL of the file containing node label information.
Defaults to None.
label_names_path (str, optional): The URL of the file containing label name information.
Defaults to None.
"""
def fun(data):
"""
Converts a string to an integer and subtracts 1.
Args:
data (str): The input string to be converted.
Returns:
int: The converted integer value minus 1.
"""
data = int(data) - 1
return data
hyperedges_info = request_text_from_url(hyperedges_path)
hyperedges_info = hyperedges_info.strip()
hyperedges_lst = hyperedges_info.split("\n")
for hyperedge in hyperedges_lst:
hyperedge = hyperedge.strip()
hyperedge = [int(i) - 1 for i in hyperedge.split(",")]
self._hyperedges.append(tuple(hyperedge))
# print(self.hyperedges)
node_labels_info = request_text_from_url(node_labels_path)
process_node_labels_info = self.process_label_txt(
node_labels_info, transform_fun=fun
)
self._node_labels = process_node_labels_info
# print("process_node_labels_info:", process_node_labels_info)
# print("process_node_names_info:", process_node_names_info)
label_names_info = request_text_from_url(label_names_path)
process_label_names_info = self.process_label_txt(label_names_info)
self._label_names = process_label_names_info
# print("process_label_names_info:", process_label_names_info)