Прогнозирование вероятности связи между двумя узлами с использованием машинного обучения или глубокого обучения, где дается сопоставление узла узлу - PullRequest
2 голосов
/ 07 апреля 2020

Может кто-нибудь, пожалуйста, направьте меня в учебное пособие, чтобы дать стартовую идею для проблемы, указанной ниже

У меня есть сопоставление авторов с соавторами, приведенное ниже:

mapping
>>
{0: [2860, 3117],
 1: [318, 1610, 1776, 1865, 2283, 2507, 3076, 3108, 3182, 3357, 3675, 4040],
 2: [164, 413, 1448, 1650, 3119, 3238],
} # this is just sample


link_attributes.iloc[:5,:7]
>>

first   id  keyword_0   keyword_10  keyword_13  keyword_15  keyword_2
0        4      0        1.0             1.0    1.0         1.0
1        9      1        1.0             1.0    1.0         1.0
2        7      2        1.0             NaN    1.0         1.0
3        6      3        1.0             1.0    NaN         1.0
4        9      4        1.0             1.0    1.0         1.0

Я должен предсказать вероятность наличия связи между Source и Sink

Например, если мне даны Source = 13 и Sink = 31, тогда я должен найти вероятность наличия ссылки между 13 и 31. Все ссылки являются ненаправленными .

Ответы [ 2 ]

5 голосов
/ 07 апреля 2020
import json
import numpy
from keras import Sequential
from keras.layers import Dense

def get_keys(data, keys):  # get all keys from json file
    if isinstance(data, list):
        for item in data:
            get_keys(item, keys)
    if isinstance(data, dict):
        sub_keys = data.keys()
        for sub_key in sub_keys:
            keys.append(sub_key)

# get all keys, each key is a feature of instances
json_data = open("nodes.json")  # read 4016 instances
jdata = json.load(json_data)
keys = []
get_keys(jdata, keys)
keys = set(keys)
print(set(keys))

def build_instance(json_object):  # use to build instance from json object, ex: instance = [f0,f1,f2,f3,....f404]
    features = []
    features.append(json_object.get('id'))
    for key in keys:
        value = json_object.get(key)
        if value is None:
            value = 0
        elif key == 'id':
            continue
        features.append(value)
    return features

# read all instances and format them, each instance will be [f0,f1, f2,...], as i read from json file, each instance will have 405 features
instances = []
num_of_instances = 0
for item in jdata:
    features = build_instance(item)
    instances.append(features)
    num_of_instances = num_of_instances + 1
    print(num_of_instances)

# read "author_id - co author ids" file
traintxt = open('train.txt', 'r')
lines = traintxt.readlines()

au_vs_co_auth_list = []
for line in lines:
    line = line.split('\t', 200)
    print(line)
    # convert value from string to int
    string = line[0]  # example line[0] = '14 445'
    id_vs_coauthor = string.split(" ", 200)
    id = id_vs_coauthor[0]
    co_author = id_vs_coauthor[1]

    line[0:1] = [int(id), int(co_author)]
    for i in range(2, len(line)):
        line[i] = int(line[i])
    au_vs_co_auth_list.append(line)

print(len(au_vs_co_auth_list))  # we have 4016 authors

X_train = []
Y_train = []
generated_train_pairs = []
train_num = 30000  # choose 30000 random training instances
for i in range(train_num):
    print(i)
    index1 = numpy.random.randint(0, len(au_vs_co_auth_list), 1)[0]
    co_authors_of_index1 = au_vs_co_auth_list[index1]
    author_id_of_index_1 = au_vs_co_auth_list[index1][0]

    if index1 % 2 == 0:  # try to create a sample that two author is not related
        index2 = numpy.random.randint(0, len(au_vs_co_auth_list), 1)[0]
        author_id_of_index_2 = au_vs_co_auth_list[index2][0]

        # make sure id1 != id2 and auth 1 and auth2 are not related
        while (index1 == index2) or (author_id_of_index_2 in co_authors_of_index1):
            index2 = numpy.random.randint(0, len(au_vs_co_auth_list), 1)[0]
            author_id_of_index_2 = au_vs_co_auth_list[index2][0]
        y = [0, 1]  # [relative=FALSE,non-related = TRUE]
    else:  # try to create a sample that two author is related
        author_id_of_index_2 = numpy.random.randint(1, len(co_authors_of_index1),size=1)[0]
        y = [1, 0]  # [relative=TRUE,non-related = FALSE]

    x = instances[author_id_of_index_1][1:] + instances[author_id_of_index_2][
                                              1:]  # x = [feature1, feature2,...feature404',feature1', feature2',...feature404']
    X_train.append(x)
    Y_train.append(y)
X_train = numpy.asarray(X_train)
Y_train = numpy.asarray(Y_train)
print(X_train.shape)
print(Y_train.shape)

# now we have x_train, y_train, build model right now
model = Sequential()
model.add(Dense(512, input_shape=X_train[0].shape, activation='relu'))
model.add(Dense(128, activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(8, activation='relu'))
model.add(Dense(2, activation='sigmoid'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(X_train, Y_train, batch_size=512, epochs=3, verbose=2)
model.save("model.h5")
# now to predict probability of linking between two author ids

id1 = 11  # just random
id2 = 732  # just random

author1 = None
author2 = None
for item in jdata:
    if item.get('id') == id1:
        author1 = build_instance(item)
    if item.get('id') == id2:
        author2 = build_instance(item)
    if author1 is not None and author2 is not None:
        break

x_test = author1[1:] + author2[1:]
x_test = numpy.expand_dims(numpy.asarray(x_test), axis=0)
probability = model.predict(x_test)

print("author id ", id1, " and author id ", id2, end=" ")
if probability[0][1] > probability[0][0]:
    print("Not related")
else:
    print("Related")
print(probability)

Выход:

author id  11  and author id  732 related
1 голос
/ 20 апреля 2020

Прежде чем углубиться в поиски решения, я рекомендую хорошо понять ваши данные и потратить большую часть вашего времени на изучение проблемы и подготовку набора данных.

Так что из описанного вами сценария кажется, что мне ваша проблема , учитывая два узла и их атрибуты предсказывают, если есть ссылка , это может интерпретироваться как задача двоичной классификации. Я предоставлю первоначальное минималистичное c простое решение.

меня смутило то, что вы упомянули, что у вас есть только link_attributes.iloc[:5,:7] link_attributes, но не атрибуты узла. В случае, если у вас есть атрибуты узла, это имеет больше смысла, потому что тогда мы просто создаем комбинации пар узлов и помечаем пары, которые не связаны как 0 or not_connected, а те, которые связаны как 1 or connected.

Итак, давайте сделаем набор данных. Поскольку я не совсем понимаю, что означают атрибуты ссылки, давайте сгенерируем случайные данные, но мы можем адаптировать лучший пример, если вы отредактируете свой вопрос с более подробной информацией о ваших данных.

О создании набора данных Для каждого узла в отображении мы создадим 10 фиктивных случайных столбцов только для демонстрации.

Затем мы создадим список всех авторов и соавторов с именем list_of_authors и генерируем пары из этого вызова, pair_of_authors.

для каждого pair of authors мы пометим их как связанные или несвязанные, используя mapping, для этого я создал функцию с именем check_if_pair_is_linked.

После этого я покажу, как создать простое базовое решение для задачи. Мы будем использовать scikit-learn with большой список простых в использовании моделей для классификации.

Код

Я сложил код и описал его в 3 основных простых шага:

  1. подготовить ваши входные данные для создания набора данных (с использованием сопоставлений и атрибутов)
  2. создать набор данных (для каждой пары авторов, пометьте затем как связанные или нет и объедините их атрибуты)
  3. Используйте sci-kit, чтобы научиться подбирать, прогнозировать и оценивать модель
import itertools
import pandas as pd
import numpy as np
from sklearn.metrics import classification_report
from sklearn import svm

######## first preparing data to create a dataset
+-- 17 lines: ### we already have mappings {---------------------------------------------------------------------------------------------------
This part creates -----> mappings => {
                                      0:[coauthor12,coauthor17231,...],
                                      1:[...],
                                        ...,
                                      732: [...]
                                      }
i                        author_attributes => {
                                               0:[a0_1,attr0_2,...,attr0_10],
                                               1:[a1_1,attr1_2,...,attr1_10],
                                               ...,
                                               732: [...]
                                              }

#### Generating our Dataset and preparing dataset to the scikit-learn library(and most other) format
### The idea is generating pairs of authors regardless if they're linked or not and label if a pair is linked
+-- 24 lines: {--------------------------------------------------------------------------------------------------------------------------------
This part creates, a list of pairs of authors containing (attributes_of_both_authors, is_linked_label)
-----> dataset  = [
                     ([a0_1,...,a0_10,a1_1,...,a1_10],label_pair0_1)),
                     ([a0_1,...,a0_10,a2_1,...,a2_10],label_pair1_2),
                                ...

                 ([a142_1,...,a142_10,a37_1,...,a37_10],label_pair142_37),
                  ]

#### Training and evaluating a simple machine learning solution
+-- 12 lines: ---------------------------------------------------------------------------------------------------------------------------------This part outputs a report about the model after training the model with a training dataset and evaluate the model in a test dataset (I used the same train data and test data but dont ever do that in a real scenario)
----->         precision    recall  f1-score   support

           0       0.93      1.00      0.96       466
           1       1.00      0.10      0.18        40

Решение :

import itertools
import pandas as pd
import numpy as np
from sklearn.metrics import classification_report
from sklearn import svm

######## first preparing data to create a dataset
#### we already have mappings
def generate_random_author_attributes(mapping):
    author_attributes = {}
    for author in mapping.keys():
        author_attributes[author] = np.random.random(10).tolist()
    for coauthors in mapping.values():
        for coauthor in coauthors:
            if author_attributes.get(coauthor, False): 
                pass # check if this coauthor was alredy added
            else:
                author_attributes[coauthor] = np.random.random(10).tolist()
    return author_attributes 
mapping = {
 0: [2860, 3117],
 1: [318, 1610, 1776, 1865, 2283, 2507, 3076, 3108, 3182, 3357, 3675, 4040],
 2: [164, 413, 1448, 1650, 3119, 3238],
}
#### hopefully you have attributes like this, for each author you have some attributes, I created 10 random values for each for demonstrating
author_attributes = generate_random_author_attributes(mapping)

#### Generating our Dataset and preparing dataset to the scikit-learn library(and most other) format
### The idea is generating pairs of authors regardless if they're linked or not and label if a pair is linked
def check_if_pair_is_linked(pair_of_authors, mapping):
    ''' return 1 if linked, 0 if not linked'''
    coauthors_of_author0 = mapping.get(pair_of_authors[0],[])
    coauthors_of_author1 = mapping.get(pair_of_authors[1],[])
    if(pair_of_authors[1] in coauthors_of_author0) or (pair_of_authors[0] in coauthors_of_author1):      
        return 1
    else:
        return 0

def create_dataset(author_attributes, mapping):
    list_of_all_authors = list(itertools.chain.from_iterable([coauthors for coauthors in mapping.values()]))
    list_of_all_authors.extend(mapping.keys())
    dataset = []
    for pair_of_authors in itertools.permutations(list_of_all_authors, 2):
        pair_label = check_if_pair_is_linked(pair_of_authors, mapping)
        pair_attributes = author_attributes[pair_of_authors[0]] + author_attributes[pair_of_authors[1]]
        dataset.append((pair_attributes,pair_label))
    return dataset

dataset=create_dataset(author_attributes, mapping)
X_train = [pair_attributes for pair_attributes,_ in  dataset]
y_train = [pair_label for _,pair_label in  dataset]

#### Training and evaluating a simple machine learning solution
binary_classifier = svm.SVC()
binary_classifier.fit(X_train, y_train)


#### Checking if the model is good
X_test = X_train # never use you train data as test data
y_test = y_train
true_pairs_label = y_test
predicted_pairs_label =  binary_classifier.predict(X_test)
print(classification_report(true_pairs_label, predicted_pairs_label))

ВЫХОД

              precision    recall  f1-score   support

           0       0.93      1.00      0.96       466
           1       1.00      0.15      0.26        40

    accuracy                           0.93       506
   macro avg       0.97      0.57      0.61       506
weighted avg       0.94      0.93      0.91       506
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...