on
读取Graph数据的代码
背景
记录读图的一些代码,由于图一般都会储存为稀疏矩阵的形式,否则大图根本无法储存,所以最终返回的都是稀疏矩阵,比较节约空间的是csr matrix。
CSR Matrix and COO Matrix
COO Matrix 比较容易理解。从图的角度出发其实就是将每条边都存下来。
要想压缩数据,无论什么方法,其实都是在合并同类项。COO Matrix有什么好压缩的呢?单个顶点出发的边可以将它们的顶点合并,用一个数表示。最终也就得到了CSR Matrix。
CSR Matrix可以理解为,先对顶点都预先编号为0-V,那么只需要记录一下,每个顶点有多少出边和出边的位置即可。CSR Matrix由三个数组构成:offsets、edges、values。有时候,offsets 在某些函数输入会拆分为 PointerB 和 PointE,意思也很简单,即某顶点开始时,已经记录边的数量,和此顶点结束时,会记录边的数量。至于 edges 记录的是边的终点,values 记录边的权重。对 CSR Matrix理解的程度决定了,你能对矩阵计算所沉浸的深度,利用CSR进行图的访问和计算是非常方便的,要使有机会写到 MKL 矩阵运算库的解析,会有更深的理解。
Python 部分
Mat
Mat 格式的文件通常是由 Matlab 生成,读取可以使用scipy.io.loadmat,在图数据中,似乎是约定好的,变量”network”代表图的邻接矩阵,”group”代表的是图结点的分类,所以读取代码为:
# 读取图的邻接矩阵
def load_matrix(file,variable_name="network"):
return scipy.io.loadmat(file)[variable_name]
# 读取图的结点的标签
def load_label(file,variable_name="group"):
return scipy.io.loadmat(file)[variable_name]
值得注意的是,这里的标签需要根据对应的训练模型调整为合理的形式。例如多分类任务sklearn和logreg应该是有区别的。
edgelist
def load_adjacency_matrix(file):
fl=open(file,'r')
#这里有的-u文件会在第一行放节点个数,则需要用其他方法记录一下节点个数,比如用set
n=int(fl.readline().replace("\n",""))
row=[]
col=[]
while True:
data=fl.readline()
if not data:
break
#这里其实要视数据而定,有时候要加反边,往csr矩阵里导入的时候是不会自动加反边的,否则返回G+G^T
#也许整体读也不错,这里不一定要一行行读
data=data.replace("\n","").split(" ")
row.append(int(data[0]))
row.append(int(data[1]))
data=[1 for i in range(len(row))]
return csc_matrix((data,(row,col)),shape=(n,n))
GCN datasets
GCN专用数据有三个,cora,citeseer,pubmed,因为有特征,所以跟其他单纯图数据稍微不太一样。基本都是用tkipf/gcn的读取方式
def load(dataset_str="cora"):
names = ['x', 'y', 'tx', 'ty', 'allx', 'ally', 'graph']
objects = []
for i in range(len(names)):
with open("data/ind.{}.{}".format(dataset_str, names[i]), 'rb') as f:
if sys.version_info > (3, 0):
objects.append(pkl.load(f, encoding='latin1'))
else:
objects.append(pkl.load(f))
x, y, tx, ty, allx, ally, graph = tuple(objects)
test_idx_reorder = parse_index_file("data/ind.{}.test.index".format(dataset_str))
test_idx_range = np.sort(test_idx_reorder)
if dataset_str == 'citeseer':
# Fix citeseer dataset (there are some isolated nodes in the graph)
# Find isolated nodes, add them as zero-vecs into the right position
test_idx_range_full = range(min(test_idx_reorder), max(test_idx_reorder)+1)
tx_extended = sp.lil_matrix((len(test_idx_range_full), x.shape[1]))
tx_extended[test_idx_range-min(test_idx_range), :] = tx
tx = tx_extended
ty_extended = np.zeros((len(test_idx_range_full), y.shape[1]))
ty_extended[test_idx_range-min(test_idx_range), :] = ty
ty = ty_extended
features = sp.vstack((allx, tx)).tolil()
features[test_idx_reorder, :] = features[test_idx_range, :]
adj = nx.adjacency_matrix(nx.from_dict_of_lists(graph))
labels = np.vstack((ally, ty))
labels[test_idx_reorder, :] = labels[test_idx_range, :]
idx_test = test_idx_range.tolist()
idx_train = range(len(y))
idx_val = range(len(y), len(y)+500)
train_mask = sample_mask(idx_train, labels.shape[0])
val_mask = sample_mask(idx_val, labels.shape[0])
test_mask = sample_mask(idx_test, labels.shape[0])
y_train = np.zeros(labels.shape)
y_val = np.zeros(labels.shape)
y_test = np.zeros(labels.shape)
y_train[train_mask, :] = labels[train_mask, :]
y_val[val_mask, :] = labels[val_mask, :]
y_test[test_mask, :] = labels[test_mask, :]
return adj, features, y_train, y_val, y_test, train_mask, val_mask, test_mask
Matlab
Matlab 这里主要提一下读取.matfile, 使用可视化界面尤为简单,直接拖拉就可以,等价于以下命令:
load(filename)
对于图数据来说,一般变量network是邻接矩阵,group是标签。