【论文实现】一篇Sigkdd的弹幕分析论文的python实现【LDA 实践者】
来源:互联网 发布:小米盒子3破解软件 编辑:程序博客网 时间:2024/06/05 18:49
【论文实现】一篇Sigkdd的弹幕分析论文的python实现 【LDA 实践者】
Author : Jasper Yang
School : Bupt
warning : 此篇文章基于较为熟悉GibbsLDA++的源码的前提下阅读。
论文link
在开始之前,我想提前说明一下,这篇文章是我实现了基于用户喜好和评论的前后影响的改进LDA,因为实验室在做弹幕分析这方面的研究,就找到了这篇A类会议的文章,本来找他们要源码的,但是他们一作并不理我。。。然后我只好自己实现了。
由于是第一次写这类文章,不知道在逻辑上表达的清不清楚,~.~,望有看的各位给点建议,哈。
怎么实现
first of first
from scipy.special import digamma import eulerlib import numpy as np import math from scipy.special import gamma import jieba import pandas as pd from scipy import stats
以上是本文所需库。
let’s begin(前期准备工作)
首先是处理数据
数据来源:bilibili(爬虫爬取)
数据格式如下。
<?xml version="1.0" encoding="UTF-8"?><i> <chatserver>chat.bilibili.com</chatserver><chatid>1007373</chatid><mission>0</mission><maxlimit>8000</maxlimit><source>e-r</source><ds>274694331</ds><de>3034701550</de><max_count>8000</max_count> <d p="72.409,1,25,16777215,1375542175,0,7526c714,274694331">我来组成弹幕..................</d><d p="33.551,1,25,16777215,1375543533,0,925384b2,274711742">大佬系边 </d><d p="117.977,1,25,16777215,1375543631,0,925384b2,274712904">甘嗨假噶 </d><d p="134.849,1,25,16777215,1375547487,0,D3dfe4a5,274755463">呢个日文..一个字都听唔明</d>...
下面写了段代码解析获得上面的用户id以及每个用户的评论。
最后形成一个所有评论的列表以及每个用户对应其评论的字典。
user = {} comments = [] split_num = 10 # 分割一部电影为几个片段 # 数据和停用词 danmu = open('danmu/1007373.xml') stopwords = {}.fromkeys([ line.rstrip().decode('gbk') for line in open('stopwords.txt') ]) # 读取文件,分析后存储到 user 和 comments for line in danmu.readlines()[:-1]: start = line.find('p=') stop = line.find('">') sub1 = line[start+3:stop] time = sub1.split(',')[0] sub1 = sub1.split(',')[6] start = line.find('">') stop = line.find('</d>') sub2 = line[start+2:stop].decode('utf-8') comments.append((float(time),sub2)) temp = [] if not user.has_key(sub1) : temp.append(sub2) user[str(sub1)] = temp else: user[str(sub1)].append(sub2)
经过以上处理后,我们还需要分片,我这里默认分割成十份。
# 统计user的个数 , 现在统计的是这个文档里的user,后期要做成对所有文档的统计量,还要能支持增量 user_num = len(user) # comments的数量 comments_num = len(comments) # 排序,分割comments ---> shots comments = sorted(comments) spli = (comments[-1][0]-comments[0][0])/split_num shots = [] for i in range(10): shots.append([x[1] for x in comments if x[0] > i*spli and x[0] <= (i+1)*spli ])
分割之后就是分词,我这里用的是python版的jieba,效果很一般,以后再更新。
注意:这里的切词我分成了两个部分。因为在文中认为片段(shot)和片段之间有时间上的影响,然后每个片段里的每一个comment之间有时间上的影响。但是不同的片段之间的comment是没有关系的。
def cut_word(x): words = jieba.cut(x, cut_all=False) final = [] for word in words: if word not in stopwords: final.append(word) return finaldef null(l): return len(l) > 0 or l[0] == ' 'for i in range(split_num): shots[i] = map(cut_word,shots[i]) shots[i] = filter(null,shots[i])
上面的代码对每一个shot里面的所有comment进行切词。
准备工作到此为止~
real work
由于这是我第一次还原论文的实现内容,一开始也是一头雾水,无从下手。慢慢多看了几遍公式,我发现了一些规律。
了解LDA的同学对上面的一系列定义应该不陌生。
这是一个我们要实现的所有的矩阵的描述。
从头开始,对每一个用户生成一个用户对应主题的矩阵(
# 制造假的sigma文件 user_num = len(user) f = open('sigma_u_t.csv','w') f.write(',user') for i in range(split_num*10): f.write(',topic'+str(i)) f.write('\n') for key in user.keys(): f.write(','+key) for j in range(split_num*10): f.write(',0.1') f.write('\n') # 每一个用户的user-topic分布 # sigma_u_t 是每个用户对于每一个topic的sigma值 # 从文件里面读取每一个用户的每一个topic的sigma值 # 每一行一个用户 (顺序就是下面生成的 user_ 中的顺序) user_sigma = pd.read_csv('sigma_u_t.csv') user_sigma = user_sigma.drop(['Unnamed: 0'],1) user_sigma.fillna(0.1) # 利用上面的用户对应评论的字典 make 一个 dataframe user_ = pd.DataFrame() temp1 = [] temp2 = [] for key in user.keys(): for i in range(len(user[key])): temp1.append(key) temp2.append(user[key][i]) user_['user'] = temp1 user_['comment'] = temp2
【后期的做法可以是去通过标签统计分析每一个用户对于主题的概率再去确定每一个用户的
下面我们需要实现
可以从文中读到这个
因为comment的
实现 Δ
先讲下余弦值计算的原理:
一个简单的例子(后面第三部分是相对复杂的例子): 句子A:我喜欢看电视,不喜欢看电影。 句子B:我不喜欢看电视,也不喜欢看电影。请问怎样才能计算上面两句话的相似程度?基本思路是:如果这两句话的用词越相似,它们的内容就应该越相似。因此,可以从词频入手,计算它们的相似程度。第一步,分词。 句子A:我/喜欢/看/电视,不/喜欢/看/电影。 句子B:我/不/喜欢/看/电视,也/不/喜欢/看/电影。第二步,列出所有的词。 我,喜欢,看,电视,电影,不,也。第三步,计算词频。 句子A:我 1,喜欢 2,看 2,电视 1,电影 1,不 1,也 0。 句子B:我 1,喜欢 2,看 2,电视 1,电影 1,不 2,也 1。第四步,写出词频向量。 句子A:[1, 2, 2, 1, 1, 1, 0] 句子B:[1, 2, 2, 1, 1, 2, 1]到这里,问题就变成了如何计算这两个向量的相似程度。使用余弦这个公式,我们就可以得到,句子A与句子B的夹角的余弦。
余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫余弦相似性。所以,上面的句子A和句子B是很相似的,事实上它们的夹角大约为20.3度。
从上面可以看出如果套用到我们的模型中,分成两类:
- 每个shot有一个词向量矩阵
- 每个comment有一个词向量矩阵
如下图。
左边是单词,右边是单词出现的次数。
因为我们是对一部视频也就是一篇文档处理,所以词向量可以是这篇文档里出现过的词。因此用下面的代码找出所有的词并存储成一个pandas的dataframe(使用这个的原因是处理起来很快而且方便)
# 统计关键词及个数 (根据文件)def CountKey(fileName, resultName): try: #计算文件行数 lineNums = len(open(fileName,'rU').readlines()) # print u'文件行数: ' + str(lineNums) #统计格式 格式<Key:Value> <属性:出现个数> i = 0 table = {} source = open(fileName,"r") result = open(resultName,"w") while i < lineNums: line = source.readline() line = line.rstrip() # print line words = line.split(" ") #空格分隔 # print str(words).decode('string_escape') #list显示中文 #字典插入与赋值 for word in words: if word!="" and table.has_key(word): #如果存在次数加1 num = table[word] table[word] = num + 1 elif word!="": #否则初值为1 table[word] = 1 i = i + 1 #键值从大到小排序 函数原型:sorted(dic,value,reverse) dic = sorted(table.iteritems(), key = lambda asd:asd[1], reverse = True) word_fre = pd.DataFrame(dic) for i in range(len(dic)): #print 'key=%s, value=%s' % (dic[i][0],dic[i][1]) result.write("<"+dic[i][0]+":"+str(dic[i][1])+">\n") return word_fre except Exception,e: print 'Error:',e finally: source.close() result.close() # print 'END\n\n'f = open('comments.txt','w')for i in range(split_num): for x in shots[i]: for word in x: f.write(word.encode('utf-8') + ' ') f.write('\n')word_fre = CountKey('comments.txt','comments_map')
最后得到的 word_fre 就是一个词频向量(全集),其实并不需要计算全集的词频。
0 10 好 1201 哈哈哈 1162 哈哈哈哈 723 吴妈 504 卧槽 485 神父 486 人 417 黑社会 378 靓坤 359 真的 3410 死 3311 叻 3112 说 3013 君 2814 一个 2515 太 2316 想 2217 大佬 2018 卖 2019 吴 2020 坤 2021 香港 1922 樽 1923 爆 1924 古惑仔 1825 2333333 1726 233333 1727 笑 1628 可爱 1629 李丽珍 16... ... ...1986 额滴 11987 痛 11988 死于 11989 递纸 11990 hahahahhahahah8 11991 扭 11992 扑 11993 却 11994 扛 11995 阿公 11996 头子 11997 交个 11998 对手 11999 解构 12000 改一改 12001 惹不起 12002 湖地 12003 把持 12004 布吉岛 12005 傻仔 12006 莫名 12007 ′ 12008 ‵ 12009 陸仔 12010 兴趣 12011 祛湿 12012 君比靓 12013 培养 12014 不卡 12015 留学 1
我的构思是这样的。
构建每一个shot的词向量,就去统计每个shot里面的每个词的词频,没在该shot里出现过的但是在全集有的为0,词向量的顺序就和上面的 word_fre 一样,这样后面的计算直接就是处理两个dataframe就可以了。
同理,对每一个comment也是一样的。每一个comment都有一个词向量dataframe(这里会造成对内存的大量使用,但是计算起来快)
# 计算每一个shot里面的所有的单词的词频 -------> 缺点:执行速度实在太慢了,后期需要修改result_s = []for i in range(split_num): shot_word_fre = word_fre.copy() shot_word_fre['time'] = 0 for x in shots[i]: for word in x: index = shot_word_fre[word_fre[0] == word.encode('utf-8')].index shot_word_fre['time'][index] = shot_word_fre['time'][index] + 1 shot_word_fre = shot_word_fre.drop(1,1) result_s.append(shot_word_fre)# 计算每一个comment的词频向量 -----------> 现在的办法是每个 comment 都有一个完整的词向量,便于后面的计算,问题是这样很占内存资源# 按照每一个shot分片后内部的comment之间的delta计算# result_c = []# for i in range(split_num):# temp = []# for j in range(len(shots[i])):# shot_word_fre = word_fre.copy()# shot_word_fre['time'] = 0# for x in shots[i][j]:# for word in x:# index = shot_word_fre[word_fre[0] == word.encode('utf-8')].index# shot_word_fre['time'][index] = shot_word_fre['time'][index] + 1# shot_word_fre = shot_word_fre.drop(1,1)# temp.append(shot_word_fre)# result_c.append(temp)# 计算每一个comment的词频向量 -----------> 现在的办法是每个 comment 都有一个完整的词向量,便于后面的计算,问题是这样很占内存资源# 不按照每一个shot分片后内部的comment之间的delta计算,所有的comment进行计算result_c = []for i in range(split_num): for j in range(len(shots[i])): shot_word_fre = word_fre.copy() shot_word_fre['time'] = 0 for x in shots[i][j]: for word in x: index = shot_word_fre[word_fre[0] == word.encode('utf-8')].index shot_word_fre['time'][index] = shot_word_fre['time'][index] + 1 shot_word_fre = shot_word_fre.drop(1,1) result_c.append(shot_word_fre)
有了词向量之后就可以计算
我这里是将所有的
p.s. 我做了修改,之前我理解的是每个shot里面的所有的comment之间计算
# 计算delta<s,_s> : 这里用的是词频向量 余弦值 -----> 下三角矩阵,后面方便计算# 从后面的shot往前计算delta_s = np.zeros((split_num,split_num))seq = range(split_num)# 修改 time 的数据类型 to float64for shot in result_s: shot.time = shot.time.astype('float64')seq.reverse()for i in seq: for j in range(i): numerator = np.sum(result_s[i].time*result_s[j].time) denominator = pow(np.sum(pow(result_s[i].time,2)),0.5)*pow(np.sum(pow(result_s[j].time,2)),0.5) if denominator != 0: cos = numerator/denominator else: cos = 0 delta_s[i][j] = cos# 计算delta<c,_c> : 这里用的是词频向量 余弦值 -----> 下三角矩阵,后面方便计算# 从后往前# 这里是按照每个shot分开然后计算里面的comment# seq = range(len(result_c))# # 修改 time 的数据类型 to float64# for i in seq:# for comment in result_c[i]:# comment.time = comment.time.astype('float64')# # 创建每个shot的一个矩阵,用list存储# delta_c = []# for i in seq:# length = len(result_c[i])# delta_c_temp = np.zeros((length,length))# delta_c.append(delta_c_temp)# for i in seq:# seq2 = range(len(result_c[i]))# seq2.reverse()# for j in seq2:# for k in range(j):# numerator = np.sum(result_c[i][j].time*result_c[i][k].time)# denominator = pow(np.sum(pow(result_c[i][j].time,2)),0.5)*pow(np.sum(pow(result_c[i][i].time,2)),0.5)# if denominator != 0:# cos = numerator/denominator# else:# cos = 0# delta_c[i][j][k] = cos# 计算delta<c,_c> : 这里用的是词频向量 余弦值 -----> 下三角矩阵,后面方便计算# 从后往前# 这里是不按照每个shot分开然后计算里面的commentseq = range(len(result_c))# 修改 time 的数据类型 to float64for i in seq: result_c[i].time = result_c[i].time.astype('float64')# list存储delta_c = np.zeros((len(result_c),len(result_c)))for i in seq: for k in range(i): numerator = np.sum(result_c[i].time*result_c[k].time) denominator = pow(np.sum(pow(result_c[i].time,2)),0.5)*pow(np.sum(pow(result_c[j].time,2)),0.5) if denominator != 0: cos = numerator/denominator else: cos = 0 delta_c[i][k] = cos
由于第一个shot没有在它之前的shot,所以第一个shot的
接下来的每个
# 有了上面的矩阵后,计算论文中提到的 M_pre_s 以及 M_pre_c# 需要两个衰减参数 gamma_s 以及 gamma_c# M_pre_s 比较好计算,M_pre_c 比较复杂一点,因为涉及到了每一个shotgamma_s = 0.5 # 我自己设的gamma_c = 0.3 # 论文中做实验得到的最好的值M_pre_s = np.zeros((split_num,total_topic)) # 行:shot个数 列:topic个数lambda_s = np.zeros((split_num,total_topic))sigma_s = 0.1 # 应该是每个片段的都不一样,但是这里我认为其实每个片段的topic分布没有统计可能性,不合理,都设成一样的了# 先初始化 M_pre_s[0] 以及 lambda_s[0]mu = 0 # 初始的 M_pre_s[0] 都是0s = np.random.normal(mu,sigma_s,total_topic) # 不知道这个做法对不对,用正态生成x坐标,再用pdf去生成y值lambda_s[0] = st.norm(mu, sigma_s).pdf(s)# 从 第1的开始for i in range(1,split_num): for topic in range(total_topic): # 先循环topic for j in range(i): numerator = np.exp(-gamma_s*delta_s[i][j])*lambda_s[j][topic] denominator = np.exp(-gamma_s*delta_s[i][j]) M_pre_s[i][topic] = numerator/denominator s = np.random.normal(M_pre_s[i][topic],sigma_s,1) lambda_s[i][topic] = st.norm(M_pre_s[i][topic], sigma_s).pdf(s)
需要提一句,我里面可能会有些变量没定义就使用了,毕竟这是我的一个心路历程的总结,不是完整的源代码,如果需要看源代码可以去我的 Github 上看。
接下来就是计算
# 总的topic个数,我在这里才填了total_topic这个参数,是有点晚了,不过,我之前在这里还遇到了一些问题,我以为是每个shot里面有固定的topic数,然后总的topic数是相乘的结果,后来经过一番认真思考,我才悔悟到原LDA中的topic数是固定的,然后不管你输入了多少文档,这个也应该一样,只不过文档变成了shot。total_topic = 10# 每一个用户的user-topic分布# sigma_u_t 是每个用户对于每一个topic的sigma值# 从文件里面读取每一个用户的每一个topic的sigma值# 每一行一个用户 (顺序就是下面生成的 user_ 中的顺序)user_sigma = pd.read_csv('sigma_u_t.csv')user_sigma = user_sigma.drop(['Unnamed: 0'],1)user_sigma.fillna(0.1)# 利用上面的用户对应评论的字典 make 一个 dataframeuser_ = pd.DataFrame()temp1 = []temp2 = []for key in user.keys(): for i in range(len(user[key])): temp1.append(key) temp2.append(user[key][i])user_['user'] = temp1user_['comment'] = temp2# 处理得到一个大表,里面包括所有评论以及评论的人,和每个人对应的所有的topic的sigma值# 这里处理之后好像有点问题,有些用户没有,下面我直接就都填充0.1了comment_per_shot = []for i in range(split_num): temp = pd.DataFrame(com[i]) u = [] tem = pd.DataFrame() for j in range(len(temp)): user_id = user_[user_.comment == temp[0][j]].iloc[0][0] u.append(user_id) a = user_sigma[user_sigma.user == user_id].iloc[:,1:] tem = [tem,a] tem = pd.concat(tem) tem = tem.reset_index().drop(['index'],1) temp['user'] = pd.DataFrame(u) temp = temp.join(tem) comment_per_shot.append(temp)# 所有的 comment 的一个 dataframe ,comment-user_id-topic0,1,2...99 ,后面的topic分布是user_id的comment_all = pd.concat(comment_per_shot).reset_index().drop('index',1)# 给那些没有topic分布的用户填充0.1 ----> 缺失值(就是生成用户的topic分布表没有生成全)comment_all = comment_all.fillna(0.1) # 没有topic分布的都填充为0.1comment_all = comment_all.rename(columns={0:'comment'})
上面的 comment_all 的结构基本上就是
index - comment - user - user's topic distribution(列数是总的topic个数)
这结构下面我还会更新用作更方便的计算。
然后有个这个 dataframe 之后我们就可以计算
# 生成 pi_c 和 M_pre_c 不同于上面,因为这里是对每个shot的面的comment进行操作# 先初始化 M_pre_c[0] 和 第0个 shot 里的第一个 comment 对应的 pi_c[0]M_pre_c = np.zeros((len(comment_all),total_topic)) # 行:shot个数 列:topic个数pi_c = np.zeros((len(comment_all),total_topic))for i in range(total_topic): pi_c[0][i] = lambda_s[0][i]*comment_all.iloc[0][i+2] + M_pre_c[0][i]start = 0 # shot 之间的位移for q in range(split_num): if q == 0: for i in range(1,len(com[q])): for topic in range(total_topic): # 先循环topic numerator = 0 denominator = 0 for j in range(i): numerator += np.exp(-gamma_c*delta_c[i][j])*pi_c[j][topic] denominator += np.exp(-gamma_c*delta_c[i][j]) M_pre_c[i][topic] = numerator/denominator pi_c[i][topic] = lambda_s[q][topic]*comment_all.iloc[i][topic+2] + M_pre_c[i][topic] start += len(com[q]) else: for i in range(start,start+len(com[q])): for topic in range(total_topic): # 先循环topic numerator = 0 denominator = 0 for j in range(i): numerator += np.exp(-gamma_c*delta_c[i][j])*pi_c[j][topic] denominator += np.exp(-gamma_c*delta_c[i][j]) M_pre_c[i][topic] = numerator/denominator pi_c[i][topic] = lambda_s[q][topic]*comment_all.iloc[i][topic+2] + M_pre_c[i][topic] start += len(com[q])
基本任务上面就完成了,下面的是两个更新公式的实现(下面两幅图),看上去只有两个,但是实现起来特别困难,而且还要考虑时间复杂的问题。
在我第一次实现出来的版本需要两个多小时的执行时间(-_-|),后来进行了 dataframe的更新以及采用多个线程池的方式提高了运行的速度。
最后的最后,我终于知道为什么了,我把topic设置的太多了,我认为一部电影分片10片,每一片里面有10个topic,这样一部电影里面就有了100个topic,计算起来时间很久,这段心路历程在上面的total_topic这个变量定义的地方我有详述了,所以在优化之后,我修改了topic的总数
下面我直接贴出我优化后的版本,再去讲怎么优化的。
下面代码的前半段是生成一些需要的矩阵,当然,我这里做成了 dataframe。
注意:下面的代码很长很长,但是,我做了很多的注释,我相信能够解释的清楚。
里面涉及了 GibbsLDApy (我模仿 GibbsLDA++ 实现的python版本)的内容。大家也可以去看看我实现的这个版本 GibbsLDApy,顺便点点赞 :)。后面我会整合所有代码形成新的 danmuLDA 做成分支。
# 生成 trndocs.dat 文件# 该文件就是视频的剪切 -----> 分成了 split_num 份数,每一份代表一篇文档f = open('test_data/trndocs.dat','w')f.write(str(split_num)+'\n')for i in range(split_num): for j in range(len(shots[i])): for k in range(len(shots[i][j])): f.write(shots[i][j][k].encode('utf-8')+' ') f.write('\n')import time # 用来记录代码执行时间# 欧拉函数的定义eur = eulerlib.numtheory.Divisors(10000) # maxnum# 执行 model 初始化# 因为现在还是实验阶段,我没有和原LDA整合成一个完整的LDA,所以我这里用了 GibbsLDApy的初始化model的功能argv = ['-est', '-alpha', '0.5', '-beta', '0.1', '-ntopics', '100', '-niters', '1000', '-savestep', '100', '-twords', '20', '-dfile', 'trndocs.dat', '-dir', 'test_data/', '-model', 'trnmodel']pmodel = Model()pmodel.init(len(argv),argv)# 将 comment_all 升级成一个新的大表 comment_all_sort 结构为 {comment,user_id,user_id的topic,该comment属于的shot的topic分布},有了这个表,后面的处理会很方便a1 = pd.concat([comment_all,pd.DataFrame(M_pre_c)],axis=1)temp = []for i in range(split_num): for j in range(len(shots[i])): t = pd.DataFrame(lambda_s)[i:i+1] t['shot'] = i t['com'] = j temp.append(t)a2 = pd.concat(temp)a2 = a2.reset_index().drop('index',1)comment_all_sort = pd.concat([a1,a2],axis=1)comment_all_sort = comment_all.sort_values('user') # 按照 user 排序# 生成 user-topic 分布的 dataframex_u_c_t = np.zeros((len(comment_all_sort),total_topic))for i in range(len(comment_all_sort)): for topic in range(total_topic): s = np.random.normal(mu,comment_all_sort.icol(topic+2)[i],1) x_u_c_t[i][topic] = st.norm(mu, comment_all_sort.icol(topic+2)[i]).pdf(s)user_id = comment_all_sort.drop_duplicates('user')['user'].reset_index().drop('index',1)x_u_c_t = user_id.join(pd.DataFrame(x_u_c_t))def lgt(y): return math.log(1+math.exp(y))def dlgt(y): return 1/((1+math.exp(y))*np.log(10))word2id = pd.read_csv('test_data/wordmap.txt',sep=' ') # 读取单词对应id的表column = list(word2id)[0] # 这个是因为第一行是单词的个数,会变成index,下面转换成字典后出现二级索引,所以做了处理word2id = word2id.to_dict()yita_lambda_s = lambda_s.copy()# 线程函数 --> 计算 yita_lambda_sdef calculate_lambda_s(shot,start): for topic in range(total_topic): result = 0 lam_s = lambda_s[shot][topic] for comment in range(len(shots[shot])): u = x_u_c_t[x_u_c_t.user == comment_all.iloc[comment+start][topic+1]] x_u = u.iloc[0][topic+1] m_pre_c = M_pre_c[comment+start][topic] t1 = x_u*dlgt(x_u*lam_s+m_pre_c) t2 = 0 for t in range(total_topic): t2 += lgt(comment_all.iloc[comment+start][t+2]*lam_s+M_pre_c[comment+start][t]) t3 =t2 t2 = eur.phi(t2) t3 = eur.phi(t3+len(shots[shot][comment])) n_tc = 0 for word in shots[shot][comment]: word = word.encode('utf-8') if word != ' ' : try: num = word2id[column][word] n_tc += pmodel.nw[num][topic] except Exception,e: print Exception,":",e t4 = eur.phi(lgt(x_u*lam_s+m_pre_c) + n_tc) t5 = eur.phi(lgt(x_u*lam_s+m_pre_c)) result += t1 * (t2 - t3 + t4 - t5) yita_lambda_s[shot][topic] = -(lam_s+M_pre_s[shot][topic])/(lam_s*lam_s) + result# 定义容量比视频片段一样多一些的线程池pool = threadpool.ThreadPool(split_num+2) start_time = time.time() # 下面的多线程开始执行的时间start = 0 # 初始化,用于控制在哪一个shot里面for shot in range(len(shots)): lst_vars = [shot,start] func_var = [(lst_vars, None)] start += len(shots[shot]) # start 增加位移,移动一个shot requests = threadpool.makeRequests(calculate_lambda_s, func_var) [pool.putRequest(req) for req in requests]pool.wait()print 'updating lambda_s %d second'% (time.time()-start_time)# 定义容量为 total_topic 的一半pool_cal = threadpool.ThreadPool(total_topic/2) # x_u_c_t 的更新代码# 注意 :这里的 comment_all 已经排过序了,和上面的不一样def calculate_x_u_c_t(i,start): for topic in range(total_topic): result = 0 for j in range(start,start+user_ct.iloc[i]): lambda_s_t = comment_all_sort.iloc[j,topic+total_topic+total_topic+2] m_pre_c_t = comment_all_sort.iloc[j,topic+total_topic+2] x_u = x_u_c_t.iloc[j,topic+1] print(lambda_s_t) print(m_pre_c_t) print(x_u) t1 = lambda_s_t*dlgt(x_u*lambda_s_t + m_pre_c_t) t2 = [] for t in range(total_topic): lst_vars = [comment_all_sort.iloc[j,t+2]*comment_all_sort.iloc[j,t+total_topic+total_topic+2]+comment_all_sort.iloc[j,t+total_topic+2],t2] func_var = [(lst_vars, None)] requests = threadpool.makeRequests(add_t2, func_var) [pool_cal.putRequest(req) for req in requests] pool_cal.wait() t2 = sum(t2) print(t2) t3 = eur.phi(t2+len(shots[int(comment_all_sort.ix[j,['shot']])][int(comment_all_sort.ix[j,['com']])])) t2 = eur.phi(t2) n_tc = 0 for word in shots[int(comment_all_sort.ix[j,['shot']])][int(comment_all_sort.ix[j,['com']])]: word = word.encode('utf-8') if word != ' ' : try: num = word2id[column][word] n_tc += pmodel.nw[num][topic] except Exception,e: print Exception,":",e t4 = eur.phi(lgt(x_u*lambda_s_t + m_pre_c_t)+ n_tc) t5 = eur.phi(lgt(x_u*lambda_s_t + m_pre_c_t)) result += t1 * (t2 - t3 + t4 - t5) x_u_c_t.iloc[j,topic+1] = x_u_c_t.iloc[j,topic+1] - yita*(-x_u/(comment_all_sort.iloc[j,topic+2]*comment_all_sort.iloc[j,topic+2]) + result) print(x_u_c_t.iloc[j,topic+1])# 定义容量比用户数量十分之一多一些的线程池pool = threadpool.ThreadPool(len(x_u_c_t)/10+2) user_ct = comment_all_sort.groupby('user').count()['topic0']yita_x_u_c_t = x_u_c_t.copy()yita = 0.3start_time = time.time() # 下面的多线程开始执行的时间start = 0 # 初始化,用于控制在哪一个shot里面for i in range(len(user_ct)): lst_vars = [i,start] func_var = [(lst_vars, None)] start += user_ct.iloc[i] # start 增加位移,移动一个shot requests = threadpool.makeRequests(calculate_x_u_c_t, func_var) [pool.putRequest(req) for req in requests]pool.wait()print 'updating x_u_c_t %d second'% (time.time()-start_time)
到现在为止我们所需要的新功能就都实现啦,后面需要的就是遵循之前的伪代码图去阶段更新参数~
beta 版本先写到这,后面我还会补充的,代码整合过几天再做,服务器被老师关掉了 -_-||
paper done 2017/05/12
- 【论文实现】一篇Sigkdd的弹幕分析论文的python实现【LDA 实践者】
- 从零开始,如何阅读一篇人工智能论文,及构建论文与代码的实现
- Online LDA的python实现
- lda模型的python实现
- LDA原论文的部分解读
- 深度学习论文-神经网络的代码实现(python版本)
- python实现完整的特征工程,实践论文中的分类模型和方法用于恶意页面的分类与识别
- 我的第一篇论文
- 第一篇论文的流程
- 一篇介绍Hive的论文
- 关于一篇icsp的论文
- 我的第一篇论文
- 弹幕的简单实现
- Android弹幕的实现
- [论文开工]MLESAC实现的一个网址
- 如何实现科技论文里面的算法
- 如何实现科技论文里面的算法
- 如何实现科技论文里面的算法
- 0502
- RSA加密算法解析+数字签名验证
- php视频
- 1035: 自守数问题
- smtp_c++发带附件的邮件
- 【论文实现】一篇Sigkdd的弹幕分析论文的python实现【LDA 实践者】
- 浏览器用户脚本
- 解析Tomcat之HttpServlet详解
- Stop The World(STW)
- linux上安装免安装版MySQL5.7.18小记
- 初识国际化和ResourceBundle
- 二叉树遍历算法的应用
- Oracle 如何查询Number类型的精度
- 《集体智慧编程》第2章 提供推荐 个人笔记