代码本身就是最好的解释,不赘述。

文本聚类输出: cluster.py

#!/usr/bin/env python
# coding=utf-8 import jieba,re
from gensim import corpora,models
from sklearn.cluster import KMeans
import sys
reload(sys)
sys.setdefaultencoding('utf-8') class MyCorpus(object):
def __init__(self,fname):
self.fname = fname def __iter__(self):
for line in open(self.fname):
yield jieba.cut(line,cut_all=False) class MyCluster(object): def __init__(self):
self.CLEAN = re.compile(ur"[^\u4e00-\u9f5aA-Za-z0-9]")
self.dictionary = {}
self.corpus = [] def gen_dataset(self,documents):
self.gen_corpus(documents)
res = [self.doc2vec(doc) for doc in documents]
return res def gen_corpus(self,documents):
texts = [ list(jieba.cut(doc)) for doc in documents ]
self.dictionary = corpora.Dictionary(texts)
self.corpus = [self.dictionary.doc2bow(text) for text in texts]
self.tfidf = models.TfidfModel(self.corpus) def doc2vec(self,doc):
vec = self.dictionary.doc2bow(jieba.cut(doc))
vec = self.tfidf[vec]
wordlist = [.0] * len(self.dictionary)
for w in vec:
wordlist[w[0]] = w[1]
return wordlist def kcluster(self,texts,k=3):
from random import shuffle
data = self.gen_dataset(texts)
data = [ map(lambda x:round(x,5),line) for line in data ]
km = KMeans(n_clusters=k,init='k-means++',max_iter=200,n_init=1,verbose=True)
km.fit(data)
labels = km.labels_
flag = [0]*len(labels)
randomtext = zip(labels,texts)
shuffle(randomtext)
res = []
for d in randomtext:
if flag[d[0]]==0:
res.append(d[1])
flag[d[0]] = 1 return res if __name__ == "__main__":
texts = [ line for line in open('data/python.db') ]
test = MyCluster()
res = test.kcluster(texts,k=4) print '\n'.join(res)

自动生成主文件: auto_gen_jd.py

#!/usr/bin/env python
# coding=utf-8 import sys,os
import simplejson as json
import codecs
# from snownlp import SnowNLP
from simhash import Simhash
# from bosonnlp import BosonNLP
from cluster import MyCluster
from jd_parser import JdParser
import re
reload(sys)
sys.setdefaultencoding('utf-8') class AutoGenJD(object):
''' 自动生成JD,输入一个职位名 和句子数,输出一份岗位描述和要求 ''' def __init__(self):
self.CLEAR_NUM = re.compile(u"^\d+[\.、::]|^[\(\(]\d+[\)\)\.]?|\d\s*[\))】]")
self.CLEAR_COLO = re.compile(u"^[。\.)(【】]\S+|[\.;:;。]$")
self.jd_database = json.load(codecs.open('data/lagou_jd_clean.json'))
# self.jobname = [ jobname[:-3] for jobname in os.listdir("data") if jobname.endswith(".db") ]
self.jobname = self.jd_database.keys()
# self.bosonnlp = BosonNLP('UYTG1Csb.3652.5pZ2otkIncEn')
self.jdparser = JdParser()
self.km = MyCluster() def load_json_data(self,fname="../preprocess/data/mini_jd.json",arg1=None,arg2=None):
for line in codecs.open(fname):
try:
data = json.loads(line)
except Exception,e:
print e
continue
if data.get(arg1,False) != False and data[arg1].has_key("job_title") and data[arg1].has_key("job_description"):
if len(data[arg1]["job_title"])<2 or len(data[arg1]["job_title"])>16:
continue
else:
fw = codecs.open('./data/'+data[arg1][arg2]+".txt",'w','utf-8')
fw.write(data[arg1]["job_description"].strip()+"\n\n")
print "writing...",data[arg1][arg2] # 去除 序列号等清洗数据
def clean_jd(self,fname="./data/java.txt"):
clean_sents = set()
with codecs.open(fname+".txt",'r','utf-8') as fr:
for line in fr:
line = self.CLEAR_NUM.sub("",line.strip())
line = self.CLEAR_COLO.sub("",line.strip())
if len(line)>2:
clean_sents.add(line.strip())
with codecs.open(fname[:-3]+"db",'w','utf-8') as fw:
for line in clean_sents:
fw.write(line+'\n')
return clean_sents def is_most_english(self,line):
en_word = [ uchar for uchar in line if (uchar>=u'\u0041' and uchar<=u'\u005a') or (uchar>=u'\u0061' and uchar<=u'\u007a') ]
return float(len(en_word)*1.0/len(line))>0.7 def clean_jd2(self,jdstr):
"""
清洗数据,去除句子前后的标点符合,序号等杂乱数据
"""
res = set()
for line in jdstr.split("\n"):
line = line.strip()
if len(line)<12:
print "line",line
if re.search(u"[;\.;。]\d+|\d?[,,、::\.]$|^\d\s{0,1}[\u4e00-\u9f5e]",line) or len(line)<8 or len(line)>32:continue
if self.is_most_english(line):continue
line = self.CLEAR_NUM.sub("",line)
line = self.CLEAR_COLO.sub("",line)
res.add(line)
return res # 获取和用户输入相似度最近的职位名
def get_closet_job(self,jobname="java"):
dis = [ (other,Simhash(jobname).distance(Simhash(other))) for other in self.jobname ]
sorteddis = sorted(dis,key = lambda x:x[1])
for k,v in sorteddis[:5]:
print k,v
return sorteddis[0][0] # 规范化jd句子数目
def norm_jd_num(self,num):
if num<1:
num=1
elif num>20:
num = 20
return num # 根据职位名和句子数,获得jd
def get_jd_with_snownlp(self,jobname="java",num=5):
jobname = self.get_closet_job(jobname)
# with open("./data/"+jobname+".db") as fr:
# s = SnowNLP(fr.read())
# return s.summary(num)
jdstr = self.clean_jd2(self.jd_database[jobname])
s = SnowNLP(jdstr)
return s.summary(num) def get_jd_with_bosonnlp(self,jobname="java",num=5): res = set()
jobname = self.get_closet_job(jobname)
jdstr = self.clean_jd2(self.jd_database[jobname])[:80]
all_cluster = self.bosonnlp.cluster(jdstr)
sort_all_cluster = sorted(all_cluster,key = lambda x:x['num'],reverse=True)
for idx,cluster in enumerate(sort_all_cluster):
print idx+1,cluster['_id']
res.add(jdstr[cluster['_id']])
return res def _get_sent_score(self,line):
"""
句子得分,最后结果排序使用,分值越小,排序越靠前
"""
s = len(line)+100
if re.search(u"男|女|男女不限|性别|岁",line):
s -= 60
if re.search(u"学历|专业|\d+[kK元]",line):
s -= 40
if re.search(u"经验",line):
s -= 20
return s def get_jd_with_kmeans(self,jobname='python',num=6):
"""
使用kmeans 进行聚类,相同一类只出现一句
"""
jobname = self.get_closet_job(jobname)
jdstr = self.clean_jd2(self.jd_database[jobname])
print "jdstr",len(jdstr)
print self.jd_database[jobname] if len(jdstr)<int(num):
num = len(jdstr)
res = self.km.kcluster(jdstr,k=int(num))
return sorted(res,cmp=lambda x,y:self._get_sent_score(x)-self._get_sent_score(y)) def jd_parser(self,jdstr):
result = self.jdparser.parser(jdstr)
return result if __name__ == "__main__": test = AutoGenJD()
jobname = sys.argv[1]
jdnum = int(sys.argv[2])
print "job name:",jobname
print "demand:"
demand = test.get_jd_with_kmeans(jobname,jdnum)
for i,jdstr in enumerate(demand):
print "%d. %s" %(i+1,jdstr)

根据职位名,自动生成jd的更多相关文章

  1. Java代码自动生成,生成前端vue+后端controller、service、dao代码,根据表名自动生成增删改查功能

    本项目地址:https://github.com/OceanBBBBbb/ocean-code-generator 项目简介 ocean-code-generator采用(适用):     ,并使用m ...

  2. 转载:C#保存文件时重名自动生成新文件的方法

    /// <summary> /// Generates a new path for duplicate filenames. /// </summary> /// <p ...

  3. c# datagridview禁止自动生成额外列

    在某些时候,处于重用pojo的考虑,我们希望在不同的datagridview之间进行复用,这就涉及到pojo中的字段会比有些datagridview所需要的字段多,默认情况下,.net对于pojo中的 ...

  4. oracle数据库高级应用之《自动生成指定表的insert,update,delete语句》

    /* * 多条记录连接成一条 * tableName 表名 * type 类型:可以是insert/update/select之一 */ create or replace function my_c ...

  5. 懒人小工具:自动生成Model,Insert,Select,Delete以及导出Excel的方法

    在开发的过程中,我们为了节约时间,往往会将大量重复机械的代码封装,考虑代码的复用性,这样我们可以节约很多时间来做别的事情.最近跳槽到一节webform开发的公司,主要是开发自己公司用的ERP.开始因为 ...

  6. 懒人小工具1:winform自动生成Model,Insert,Select,Delete以及导出Excel的方法

       懒人小工具2:T4自动生成Model,Insert,Select,Delete以及导出Excel的方法    github地址:https://github.com/Jimmey-Jiang/J ...

  7. PowerDesigner中表名过长,自动生成的主键名截取的问题

    在PowerDesinger中,若表名过长,自动生成的主键名会被自动截取. 解决如下:DataBase/Edit Current DBMS/Scripts/Objects/PKey/ConstName ...

  8. Linq to Sql自动生成实体类重名情况的处理

    使用Linq to sql自动生成实体类时,如果要生成多个库的实体类,往往会遇到类名重名的情况,也就是表名重名,这样编译会不通过,这种情况下要在自动生成的实体类文件中(.designer.cs后缀)将 ...

  9. eclipse自动生成变量名声明(按方法返回值为本地变量赋值)

    eclipse自动生成变量名声明(按方法返回值为本地变量赋值) ctrl+2+L 这个快捷键可自动补全代码,极大提升编码效率! 注:ctrl和2同时按完以后释放,再快速按L.不能同时按! 比如写这句代 ...

随机推荐

  1. 使用Animation实现摄像机动画

    项目剧情模块分给了我做,其中很重要的一个功能就是摄像机旋转平移等操作,本来打算使用Camera Path这个插件制作的,但是鉴于项目Unity版本还停留在4.3,低于插件要求版本,另外编辑器做出来是交 ...

  2. Nginx+Tomcat实现反向代理及动静分离

    Nginx+Tomcat实现反向代理及动静分离 时间 2014-07-07 15:18:35  51CTO推荐博文 原文  http://yijiu.blog.51cto.com/433846/143 ...

  3. ASP.NET MVC中的拦截器

    在ASP.NET MVC中,有三种拦截器:Action拦截器.Result拦截器和Exception拦截器, 所谓的拦截器也没有什么的,只是写一个类,继承另一个类和一个接口,顺便实现接口里面的方法而以 ...

  4. 搭建EF6.0+MVC4搭建框架遇到的问题及解决方案

    问题一:“未能加载文件或程序集“EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089” ...

  5. 宝洁的Pvp

    1.公司宗旨(Purpose) 我们生产和提供更佳品质及价值的产品,以改善全球消费者的生活.作为回报,我们将会获得领先的市场销售地位和利润增长,从而令我们的员工.我们的股东以及我们的生活.工作所处的社 ...

  6. 【性能诊断】三、单功能场景的性能分析(RedGate Profiler)

    上一篇我们简单的对客户前端和数据库后端的性能问题进行了定位,如果排除了这两块,问题基本就确定在应用服务器上.但是我们往往对应用服务器,或者说应用程序的性能最陌生,一旦出现性能问题往往有无所适从的感觉, ...

  7. RMAN备份与恢复之不完全恢复

    要点:对于RMAN的不完全恢复,有如下步骤: 1)加载数据到mount状态(建议恢复前先做备份) 2)为高并发分配多个通道 3)还原所有(所需)的数据文件 4)使用until time,until s ...

  8. VBA実績表

    VBA 插入一行保留样式 VBA 打开一个string指定的文件 VBA 按照文件类型名称打开一个文件 VBA excel中表示列的字母换成数字

  9. [原]网络库libevent在Visual Studio中的使用方法

    libevent是一个事件触发的网络库,适用于windows.linux.bsd等多种平台,内部使用select.epoll.kqueue等系统调用管理事件机制.著名分布式缓存软件memcached也 ...

  10. 服务器判断客户端为移动端还是PC端

    public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/html&quo ...