Лекция
Это окончание невероятной информации про машинное обучение на больших данных .
...
табуляции)
Посчитанные результаты участников принимаются в файле формата txt и
сравнивается с полными данными специально написанной программой, которая считает
расхождение между данными участников и настоящими данными.
Чем меньше расхождение, тем выше оценивается результат команды согласно схеме,
представленной далее в разделе «Методика оценки».
Предоставляемое участникам базовое решение (дает 1 балл):
1. import random
2. import math
3.
4. from GraphParser import graphParser
5. def printall(res):
6.
for i in range(0,len(res)):
7.
print(res[i])
8.
print("---------")
9. cols = list()
10. cols.append(2)
11. (demog,fd) = graphParser.parseFolder("Task1\\Task1\\trainDemography",0,"",0,
cols)
12. c=1
13. for key, value in demog.items():
14.
print(str(key) + " val "+ str(value))
15.
c+=1
16.
if c==3:
17.
break
18.
19.
#print(demog)
20.
graph = graphParser.parseFolderBySchema("Task1\\Task1\\graph",30,"")
21.
#print(graph )
22.
minBD = 9999999999999999
23.
maxBD = 0
24.
keyVal = 0 #'birth_date'
25.
for key, value in demog.items():
26.
#print(key)
27.
bd = int(value[keyVal])
28.
# print( people)
29.
if bd>maxBD:
30.
maxBD=bd
31.
if bd
32.
minBD=bd
33.
print(minBD)
34.
print(maxBD)
35.
randCount=15
36.
diffSum1 = 0
37.
diffSum = *randCount
38.
for people in graph :
39.
pId = people['from']
40.
if pId not in demog.keys():
41.
print("err for "+str(pId))
42.
continue
43.
dateSum = 0
44.
totalLen=0
45.
maxBDp = 0
46.
minBDp = 9999999999999999
47.
#print(people['links'])
48.
for links in people['links']:
49.
50.
pIdr = links['to']
51.
print(links['to'])
52.
53.
54.
if pIdr not in demog.keys():
55.
print("err for "+str(pIdr))
56.
continue
57.
totalLen+=1
58.
bd = int(demog[pIdr][keyVal])
59.
if bd>maxBDp:
60.
maxBDp=bd
61.
if bd
62.
minBDp=bd
63.
dateSum+=int(bd)
64.
65.
if
(totalLen == 0):
66.
continue
67.
#
avg=propBirthDate
68.
#else:
69.
avg=(dateSum)/(totalLen)
70.
71.
if (totalLen>=4):
72.
print("TOTAL Len big!"+str(totalLen))
73.
avg=(dateSum-maxBDp-minBDp)/(totalLen-2)
74.
else:
75.
print("total len small!"+str(totalLen))
76.
avg=(dateSum)/(totalLen)
77.
78.
#avg=propBirthDate
79.
51
80.
trueVal = int(demog[pId][keyVal])
81.
diffSum1+= abs(trueVal-avg)
82.
for ind in range(0,len(diffSum)):
83.
avg = random.randrange(minBD,maxBD)
84.
diffSum[ind]+= abs(trueVal-avg)
85.
86. print(diffSum1)
87. for ind in range(0,randCount):
88.
print(diffSum[ind])
СПОСОБ ОЦЕНКИ РЕЗУЛЬТАТА:
Для получения количественной оценки правильности результата использовалась
следующая программа-компаратор на языке Python:
import pandas as pd
import numpy as np
from random import randint
import math
dir_name = 'testDemography'
files = ['part-v004-o000-r-00000', 'part-v004-o000-r-00001', 'part-v004-o000-r-
00002', 'part-v004-o000-r-00003', 'part-v004-o000-r-00004', 'part-v004-o000-r-
00005', 'part-v004-o000-r-00006', 'part-v004-o000-r-00007', 'part-v004-o000-r-
00008', 'part-v004-o000-r-00009', 'part-v004-o000-r-00010', 'part-v004-o000-r-
00011', 'part-v004-o000-r-00012', 'part-v004-o000-r-00013', 'part-v004-o000-r-
00014', 'part-v004-o000-r-00015']
files = [dir_name + '/' + i for i in files]
df = pd.DataFrame()
frames = []
for file_name in files:
d = pd.read_csv(file_name, sep='\t', names=['id', 'date', 'num', 'bla1',
'bla2', 'bla3', 'bla4', 'bla5'])
del d['date']
del d['bla1']
del d['bla2']
del d['bla3']
del d['bla4']
del d['bla5']
frames.append(d)
test_data = pd.concat(frames, ignore_index=True)
answers = pd.read_csv('results.txt', sep='\t', names=['id', 'num'])
def compare(res, test):
to_sum = []
for i, row in res.iterrows():
vals = test[test['id'] == row['id']]['num'].values
if(len(vals)):
stds = []
for v in vals:
if ((not math.isnan(v)) and not math.isnan(row['num'])):
stds.append(math.pow(v - row['num'], 2))
if(len(stds)):
print('stds', stds)
to_sum.append(min(stds))
return sum(to_sum)
s = compare(answers, test_data)
print(s)
РЕШЕНИЕ:
В первую очередь надо определить что поставленная задача является регрессионой
задачей, после чего можно провести исследование особенностей данной задачи, найти
корреляции между свойствами пользователей и провести исследование на поиск лучшей
модели для работа с этими данными.
Также важные результаты могут показать гипотезы о возрасте друзей пользователя.
Задача 4.2.2 «Регион»
Представленный для анализа фрагмент социального графа включает информацию о
связях 100 тысяч пользователей, попавших в двухшаговую окрестность сотни случайно
выбранных пользователей. Участникам предоставляются файлы графа социальной сети со
всеми связями и файл демографии, в котором указан данные по пользователям, включая
регион, однако регион указан не для всех пользователей.
По пользователям которые присутствуют в графе, но не присутствуют в демографии
необходимо установить их аттрибут ID_Location (регион).
Ответ записывается в текстовый файл в формате:
(
Посчитанные результаты участников принимаются в файле формата txt и
сравнивается с полными данными специально написанной программой, которая считает
расхождение между данными участников и настоящими данными.
Чем меньше расхождение, тем выше оценивается результат команды согласно схеме,
представленной в разделе «Методика оценки».
Предоставляемое участникам базовое решение (дает 1 балл):
1. import math
2. import sys
3.
4. def bl(graph, locs, fd=False):
5.
res = list()
6.
count = int(0)
7.
8.
for pId,conns in graph.items():
9.
count+=1
10.
if count%1000 == 0:
11.
print(count)
12.
dateSum = 0
13.
totalLen=0
14.
locIds=dict();
15.
print(pId)
16.
try:
17.
if locs[pId] != None:
18.
continue
19.
except:
20.
pass
21.
if type(conns) == int:
22.
conns=[conns]
53
23.
for links in conns:
24.
totalLen+=1
25.
try:
26.
frLoc=locs[links]
27.
except:
28.
continue
29.
try:
30.
locIds[frLoc]+=1 #int(demog[links])
31.
except:
32.
locIds[frLoc]=1
33.
34.
resId=0
35.
popId=0
36.
for locId, total in locIds.items():
37.
if total>popId:
38.
popId=total
39.
resId=locId
40.
41.
res.append([pId,resId])
42.
if (fd):
43.
fd.write(str(pId)+'\t'+str(resId)+'\n')
44.
return res
45.
46. from GraphParser import graphParser
47.
48. pass
49. cols = list()
50. cols.append("userId")
51. cols.append("ID_Location")
52. (locs,fd) =
graphParser.parseFolderBySchema("Task2\\Task2\\trainDemography",0,"","userId",
cols, True)
53. cols = list()
54. cols.append("from")
55. cols.append("to")
56. cols.append("links")
57. (graph, fd) =
graphParser.parseFolderBySchema("Task2\\Task2\\graph",0,"","from",cols,True)
58. print("data loaded")
59. fdres=open("results.txt",'w')
60. bl(graph,locs, fdres)
СПОСОБ ОЦЕНКИ РЕЗУЛЬТАТА:
Для получения количественной оценки правильности результата использовалась
следующая программа-компаратор на языке Python:
import pandas as pd
import numpy as np
import math
import ast
test_df = pd.read_csv('task2/test.tsv', sep='\t', names=['id', 'groups'])
results_df = pd.read_csv('task2/results.tsv', sep='\t', names=['id', 'groups'])
def compare(results, test):
#Iterate over all submitters results
score = 0
not_found_penalty = -5
false_found_penalty = -5
found_reward = 10
for i, row in test.iterrows():
test_groups = ast.literal_eval(row['groups'])
#No such user
if(not (any(results.id == row['id']))):
score = score + (len(test_groups) * not_found_penalty)
continue
#Get fit
result_groups = ast.literal_eval(results[results['id'] == row['id']]
['groups'].values )
for tg in test_groups:
if (tg in result_groups):
score = score + found_reward
result_groups.remove(tg)
test_groups.remove(tg)
#Get penalty
score = score + (len(result_groups) * not_found_penalty)#not found
score = score + (len(test_groups) * false_found_penalty)#false found
return score
compare(results_df, test_df)
РЕШЕНИЕ:
В первую очередь надо определить, что поставленная задача является задачей на
классификацию, после чего можно провести исследование особенностей задачи, найти
корреляции между свойствами пользователей и провести исследование на поиск лучшей
модели для работа с этими данными.
Так же важные результаты могут показать гипотезы о месте атрибута location_id
друзей пользователя, особенно тех, которые учились с ним в одной школе.
Вторая задача похожа на первую, хоть и принадлежит к другому классу задач
машинного обучения, таким образом участники могли использовать свои наработки первой
задачи для решения второй.
Задача 4.2.3 «Поиск связей»
Представленный для анализа фрагмент социального графа включает информацию о
связях 1 миллиона пользователей, попавших в двухшаговую окрестность сотни случайно
выбранных пользователей. Участникам предоставляются файлы графа и демографии по
пользователям. Часть связей в предоставленном социальном графе скрыта и задачей
участников является максимально полно и точно раскрыть их.
Сокрытие связей коснулось только пользователей из исходного миллиона, остаток от
деления аттрибут ID которых на 11 равен 7 (id % 11 == 7), сокрытию подверглось порядка
10% связей для каждого из этих пользователей. Были скрыты только ведущие в исходный
миллион связи.
В прогнозе достаточно восстановить наличие связи, ее тип не важен. Результаты
прогноза нужно представить в формате CSV файла вида:
ID_пользователя1 ID_кандидата1.1 ID_кандидата1.2 ID_кандидата1.3
ID_пользователя2 ID_кандидата2.1 ID_кандидата2.2
Записи в файле отсортированы по ID пользователя (по возрастанию), а затем по
предсказанной релевантности кандидатов (по убыванию, саму релевантность при этом в
файл писать не надо). Пример результатов:
5111 178542 78754
18807 982346 1346 57243
Результаты участников оцениваются с помощью метрики Нормализованной
скидочной совокупной выгоды
(Normalized Discounted Cumulative Gain, NDCG),
используемой в индустрии для оценки точности работы алгоритма для этой и аналогичных
ей задач. Метрика рассчитывается отдельно по каждому из пользователей, для которых есть
скрытые связи, а затем усредняться. Записи в файле результата, не имеющие отношения к
пользователям со скрытыми связями, при оценке результата учитываться не будут. Если по
какому-то пользователю не будет предложено ни одного кандидата, то значение метрики для
него будет считаться за 0.
Предоставляемое участникам базовое решение (дает 1 балл):
1. # Для чтения/записи csv файлов
2. import csv
3. # Для работы с архивами
4. import gzip
5. # Для работы с файловой системой
6. import os
7. # Эффективные массивы простых типов
8. import numpy
9. # Работа с матрицами (подсчет общих друзей реализован как умножение матрицы
графа самое на себя)
10. import scipy
11. from scipy.sparse import coo_matrix, csr_matrix
12. # Пути к данным
13. dataPath = "./"
14. graphPath = os.path.join(dataPath, "trainGraph")
15. predictionPath = os.path.join(dataPath,"prediction.gz")
16.
17. # Основные параметры графа
18. numUsers = 107474
19. numLinks = int(72384968 / 2)
20. maxUserId = 9418031
21. # В этих массивах мы будем собирать данные. Инициализируем их заранее нужным
размером чтобы
22. # небыло лишнего копирования
23. form = numpy.zeros( (numLinks), dtype=numpy.int32 )
24. to = numpy.zeros( (numLinks), dtype=numpy.int32 )
25. data = numpy.ones( (numLinks), dtype=numpy.int32 )
26.
27. # Здесь храним позицию, на которую надо записать новую связь
28. current = 0
29.
30. # Итерируемся по файлам в папке
31. for file in [f for f in os.listdir(graphPath) if f.startswith("part")]:
32.
csvinput = gzip.open(os.path.join(graphPath, file), mode='rt')
33.
csv_reader = csv.reader(csvinput, delimiter='\t')
34.
# А теперь по строкам в файле
35.
for line in csv_reader:
36.
user = int(line )
37.
# Разбираем идшки и маски друзей
38.
for friendship in line .replace("{(", "").replace(")}",
"").split("),("):
39.
parts=friendship.split(",")
40.
# Записываем связь в массивы и двигаем указатель
41.
form[current] = user
42.
to[current] = int(parts )
43.
current += 1
44.
45.
# Не забываем закрыть файл
46.
csvinput.close()
47. # Создаем из массивов матрицу. Изначальна матрица хранится в виде списка
[i,j,v], но для эффективной
48. # дальнейшей работы нам надо преобразовать в вид [i->[j,v]]
49. fullMatrix = coo_matrix(
50.
(data, (form, to)),
51.
shape=(numLinks + 1, numLinks + 1)).tocsr()
52.
53. # Массивы больше не нужны, удаляем их из памяти
54. del form
55. del to
56. del data
57. # Считаем транспонированную матрицу (колонки и ряды поменяны местами) и ее
тоже приводим в вид [i->[j,v]]
58. reversedMatrix = scipy.transpose(fullMatrix).tocsr()
59. # Поскольку прогноз нам нужно строить только для части пользователей,
остальных из
60. # исходной матрицы уберем (забьем нулями)
61. for i in range(maxUserId + 1):
62.
if i % 11 != 7:
63.
ptr = fullMatrix.indptr[i]
64.
ptr_next = fullMatrix.indptr[i+1]
65.
if ptr != ptr_next:
66.
fullMatrix.data[ptr:ptr_next].fill(0)
67.
68. # Чтобы нули не мешались при умножении, вычистим их и подуменьшим матрицу
69. fullMatrix.eliminate_zeros()
70. # Здесь и происходит основная магия - через умножение матриц получаем
счетчики общих друзей,
71. # По которым сделаем прогноз
72. commonFriends = fullMatrix.dot(reversedMatrix)
73. # Теперь осталось его записать в файл. Открываем врайтеры
74. f = open('prediction.csv', 'w')
75. writer = csv.writer(f, delimiter='\t')
76.
77. for i in range(maxUserId + 1):
78.
# Два указателя дают нам границы в которых лежат данные для этого i в
матрице
79.
ptr = commonFriends.indptr[i]
80.
ptr_next = commonFriends.indptr[i+1]
81.
# Если они не равны, значит данные есть и можно экспортировать
82.
if ptr != ptr_next:
83.
# Достаем счетчики общих друзей и создаем порядок на них от большего
к меньшему
84.
counts = commonFriends.data[ptr:ptr_next]
85.
order = numpy.argsort(-counts)
86.
87.
# Не забываем что из прогноза надо убрать себя и своих известных
друзей
88.
mineFriends =
set(fullMatrix.indices[fullMatrix.indptr[i]:fullMatrix.indptr[i+1]])
89.
mineFriends.add(i)
90.
91.
# Достаем идшки друзей, сортируем, фильтруем, обрезаем и пишем
92.
ids = commonFriends.indices[ptr:ptr_next]
93.
writer.writerow([i] + list(filter(lambda x: x not in mineFriends,
ids[order]))[:42])
94.
95. # Не забываем закрыть файл
96. f.close()
СПОСОБ ОЦЕНКИ РЕЗУЛЬТАТА:
Для получения количественной оценки правильности результата использовалась
следующая программа-компаратор на языке Python:
import pandas as pd
import numpy as np
dir_name = 'testDemography'
files = ['part-v004-o000-r-00000', 'part-v004-o000-r-00001', 'part-v004-o000-r-
00002', 'part-v004-o000-r-00003', 'part-v004-o000-r-00004', 'part-v004-o000-r-
00005', 'part-v004-o000-r-00006', 'part-v004-o000-r-00007', 'part-v004-o000-r-
00008', 'part-v004-o000-r-00009', 'part-v004-o000-r-00010', 'part-v004-o000-r-
00011', 'part-v004-o000-r-00012', 'part-v004-o000-r-00013', 'part-v004-o000-r-
00014', 'part-v004-o000-r-00015']
files = [dir_name + '/' + i for i in files]
df = pd.DataFrame()
frames = []
for file_name in files:
print(file_name)
d = pd.read_csv(file_name, sep='\t', names=['id', 'date', 'num', 'bla1',
'bla2', 'bla3', 'bla4', 'bla5'])
del d['date']
del d['bla1']
del d['bla2']
del d['bla3']
del d['bla4']
del d['bla5']
frames.append(d)
result = pd.concat(frames, ignore_index=True)
result
def dcg_at_k(r, k, method=0):
"""Score is discounted cumulative gain (dcg)
Relevance is positive real values. Can use binary
as the previous methods.
Args:
r: Relevance scores (list or numpy) in rank order
(first element is the first item)
k: Number of results to consider
method: If 0 then weights are [1.0, 1.0, 0.6309, 0.5, 0.4307, ...]
If 1 then weights are [1.0, 0.6309, 0.5, 0.4307, ...]
Returns:
Discounted cumulative gain
"""
r = np.asfarray(r)[:k]
if r.size:
if method == 0:
return r + np.sum(r[1:] / np.log2(np.arange(2, r.size + 1)))
elif method == 1:
return np.sum(r / np.log2(np.arange(2, r.size + 2)))
else:
raise ValueError('method must be 0 or 1.')
return 0.
def ndcg_at_k(r, k, method=0):
"""Score is normalized discounted cumulative gain (ndcg)
Relevance is positive real values. Can use binary
as the previous methods.
Args:
r: Relevance scores (list or numpy) in rank order
(first element is the first item)
k: Number of results to consider
method: If 0 then weights are [1.0, 1.0, 0.6309, 0.5, 0.4307, ...]
If 1 then weights are [1.0, 0.6309, 0.5, 0.4307, ...]
Returns:
Normalized discounted cumulative gain
"""
dcg_max = dcg_at_k(sorted(r, reverse=True), k, method)
if not dcg_max:
return 0.
return dcg_at_k(r, k, method) / dcg_max
r = [3, 2, 3, 0, 0, 1, 2, 2, 3, 0]
ndcg_at_k(r, 7)
len(test[test['id'] == 15102006]['num'].values)
pd.Series([123, 0], index=['id', 'num'])
any(result.id == 115368359)
t.to_csv('results.csv', sep='\t', index = False, header = False)
def compare(res, test):
#Iterate over all submitters results
to_sum = []
for i, row in test.iterrows():
#
If there is no such id crete with zero
if(not (any(res.id == row['id']))):
res.append(pd.Series([row['id'], 0], index=['id', 'num']))
for i, row in res.iterrows():
vals = test[test['id'] == row['id']]['num'].values
if(len(vals)):
stds = []
for v in vals:
if (not math.isnan(v)):
stds.append(math.pow(v - row['num'], 2))
if(len(stds)):
to_sum.append(min(stds))
return sum(to_sum)
t1 = result.copy()
# t1[t1['id'] == 11536835]['num'] = t1[t1['id'] == 11536835]['num'] + 1
t1.loc[1,'num'] = t1.loc[1,'num'] + 1
t1.loc[2,'num'] = t1.loc[2,'num'] + 2
t1.loc[3,'num'] = t1.loc[3,'num'] - 5
# t1[t1['id'] == 11536835]['num']
s = compare(t1, result)
s
РЕШЕНИЕ:
В качестве примера решения задачи, точность прогноза которого надо превзойти,
используется логистическая регрессия, натренированная на трех признаках:
1. количестве общих друзей двух пользователей,
2. разнице в возрасте и
3. факте совпадения или различия полов.
Помимо улучшения алгоритма, необходимо так же учитывать вычислительную
сложность, которая ставит требование не только качественно повысить эффективность
базового решения, но и успеть рассчитать результаты для всех пользователей.
Поэтому для эффективного решения необходимо выделить только те особенности
для включения в модель, которые имеют достаточно высокую корреляцию с дружбой
пользователей.
Это ставит перед участниками потребность в постановке гипотез о том, какие
факторы имеют высокую корреляцию, а какие
— низкую, и проверку гипотез на
предоставленных данных.
По каждой из задач была написана программа-компаратор (указанная выше), которая
сравнивает решение участников с полными данными, которые были не раскрыты и имеются
только у жюри Олимпиады.
Чем сильнее расхождение между результатами участников и полными данными, тем
ниже результат участников в баллах. Таким образом, проверка работ участников и размер
начисляемых баллов были полностью автоматизированы.
Максимальный балл заключительного этапа по командной части мог составить 56
баллов. Максимальный балл по задачам распределялся следующим образом:
• Задача 1 — 10 баллов;
• Задача 2 — 16 баллов;
• Задача 3 — 30 баллов.
Для расчета количества баллов, начисляемых участникам, использовалась
логистическая регрессия с округлением до целочисленного количества баллов, в которой
максимальному баллу соответствовал уровень результата, в 4 раза превосходящий базовое
решение, а минимальный балл
(1 балл) начислялся за уровень результата, равного
предложенному базовому решению.
0 баллов начислялось в случае, если результат не был показан (команда не сдала
валидное решение в срок) или если точность результата была ниже базового решения.
В заключительном этапе олимпиады баллы участника складываются из двух частей: он получает баллы за индивидуальное решение задач по предметам (математика, информатика) и за командное решение практической задачи. Итоговая оценка участника олимпиады получается по следующей формуле: S=S1+S2 , где S1 — количество баллов, набранное в рамках индивидуальной части заключительного этапа (максимум — 24 балла); S2 — количество баллов, набранное в рамках командной части заключительного этапа (максимум — 56 баллов). Критерий определения победителей и призеров:
А как ты думаешь, при улучшении машинное обучение на больших данных , будет лучше нам? Надеюсь, что теперь ты понял что такое машинное обучение на больших данных , машинное обучение, большие данные и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Машинное обучение
Часть 1 Машинное обучение на больших данных Теория и примеры решения задач
Часть 2 2.2. Критерии определения призеров и победителей - Машинное обучение на
Часть 3 4.3. Методика расчета баллов - Машинное обучение на больших данных
Комментарии
Оставить комментарий
Машинное обучение
Термины: Машинное обучение