用户画像练习

来自CloudWiki
跳转至: 导航搜索

第三方模块安装

需要安装的第三方模块有jieba、sklearn和wordcloud。jieba用于分词,sklearn已在第2章介绍过,wordcloud用于生成标签云图,分别用pip命令进行安装:

$ pip3 install jieba
$ pip3 install sklearn

wordcloud需要下载whl文件进行安装,打开下载网站https://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud,�选择对应Python版本安装,�例如64位的Python 3.6,就选择如图所示进行下载。

下载之后进行安装:

$ pip3 install wordcloud-1.4.1-cp36-cp36m-win_amd64.whl


从京东那里爬取商品评论

爬取评论方法:

def getComments():
    f_comments_json = open('comments_json.txt', mode='w', encoding='gbk') #使用GBK编码,否则会出错
    for i in range(100): #爬取100页,每页10条评论
        url = 'https://sclub.jd.com/comment/productPageComments.action'
        data = 'productId=7437788&score=0&sortType=5&pageSize=10&page=%s' % str(i)
        complete_url = url + "?" + data
        response = urllib.request.urlopen(complete_url).read().decode('gbk')
        f_comments_json.write('%s\n' % response)

上述代码做了这些操作:先以gbk编码创建一个文件用来储存原始评论数据,这里使用gbk是因为京东返回的数据就是gbk编码的;接着组织好get请求的链接,使用urllib发起请求,就这样连续爬取100页,每页10条评论,把返回的json格式的数据写入comments_json.txt文件。( 详细代码及需要导入的模块请参考实操手册章节4.1.2)

www.bejson.com

数据清洗

爬取的评论数据包含了许多信息,包括用户名、评论时间等等,我们需要的是评论内容,所以需要把原始数据进行过滤清洗。原始评论的数据是json形式的,格式如图4-2所示。

使用 www.bejson.com使格式更好看一点。

从图中可以看出,comments是一个json对象数组,每个元素对应一个用户的评论,而用户评论的具体内容又存放在content中。了解了数据的具体结构后,就可以很容易实现代码了:

def filterComments():
    f_comments = open('comments.txt', encoding='utf8', mode='w')
    with open('comments_json.txt', encoding='gbk') as f:
        for line in f:
            s = json.loads(line.strip())  # 解析json
            comments = s['comments']  # 读取json对象数组
            for comment in comments:
                content = comment['content'].replace('\n', '')  # 去掉换行符
                f_comments.write('%s\n' % content) 

上述代码做了这些操作:先创建一个utf-8编码的文件用于存放过滤后的评论数据;读取原始评论数据comments_json.txt的文件的每一行,每一行对应一个评论,调用json进行解析即可读取具体的评论内容;最后写入文件即可。

对评论进行中文分词、去停用词

中文分词(Chinese Word Segmentation) 指的是将一个汉字序列切分成一个个单独的词。 举个例子来简单说明分词做了什么操作。“张三买了张三角桌”可以分词为“张三”、“买了”、“张”、“三角桌”。使用jieba库可以很方便的实现分词操作,代码如下:

def wordSeg():
    f_comments = open('comments.txt', encoding='utf8')
    f_comments_ws = open('comments_word_seg.txt', encoding='utf-8', mode='w')
    for line in f_comments:
        cut_txt = ' '.join(jieba.cut(line))  # 调用jibea进行分词
        f_comments_ws.write('%s\n' % cut_txt)

上述代码做了这些操作:以utf-8编码创建一个文件用于存放分词的结果;读取评论内容文件comments的每一行调用jieba进行分词操作;最后把分词的结果写入文件。

在基于词的检索系统中,停用词是指出现频率太高、 没有太大检索意义的词,如“的、是、太、of、the等[7],停用词可以从互联网上搜索下载,这里使用的停用词列表是stop_words.txt文件,可以在附件中找到。去除停用词的代码如下:�

def removeStopWords():
    f_stop_words = open('stop_words.txt', encoding='utf8')
    stop_words = [line.replace('\n', '') for line in f_stop_words]  # 读取停用词列表
    f_comments_processed = open('comments_processed.txt', encoding='utf-8', mode='w')
    with open('comments_word_seg.txt', encoding='utf-8') as f:
        for line in f:
            line = line.strip().split(' ')  # 去除首尾空格,按照空格分割为列表
            new_line = ''
            for c in line:
                if c not in stop_words:  # 非停用词保留,停用词则去除
                    new_line = new_line + ' ' + c
            for word in new_line.split(' '):
                if len(word) != 0:
                    f_comments_processed.write('%s  ' % word)
            f_comments_processed.write('\n')

上述代码做了这些操作:首先读取停用词文件stop_words.txt存储为一个列表;以utf-8编码创建一个文件用于存储去停用词后的评论;按行读取先前分词后的评论文件comments_word_seg.txt;这每一行都按照空格分割为列表,遍历这个列表中的元素,判断是否为停用词,若是则进行保留;最后写入文件。



计算TF-IDF词频并应用K-均值聚类算法

TF-IDF的全称是Term Frequency-Inverse Document Frequency,翻译过来就是“词频-逆文本频率”。TF容易理解,即一个文本中各个词出现的频率统计。IDF反映了一个词在所有文本中出现的频率,能够反映词语的重要性,举个例子来说明IDF,有如下语料:

corpus=["I come to China to travel", 
       "This is a car polupar in China",          
       "I love tea and Apple ",   
       "The work is to write some papers in science"]

上面的4个文本中几乎都出现了to、is、and,词频虽然高,但是重要性却没有China、Apple高。所以,若一个词出现在很多文本中,它的IDF值应当低,若一个词出现在比较少的文本中,它的IDF应当高。最后的TF-IDF值等于TF与IDF相乘。总的来说,TF-IDF就是从两个方面对文本中的词进行加权:①词在当前文本中出现的次数;②总文本数包含词的数目。

具体实现方法:为每一行建立一个10000个元素的数组,以统计每个词出现的次数

def calcTFIDF(n):
    corpus = []
    # 读取评论文件作为语料
    with open('comments_processed.txt', encoding='utf-8') as f:
        for line in f:
            if not line == '\n':
                corpus.append(line.strip())
    # 将文本中的词语转换为词频矩阵 矩阵元素a[i][j] 表示j词在i类文本下的词频
    vectorizer = CountVectorizer()
    # 该类会统计每个词语的tf-idf权值
    transformer = TfidfTransformer()
    # 第一个fit_transform是计算tf-idf 第二个fit_transform是将文本转为词频矩阵
    tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))
    # 获取词袋模型中的所有词语
    terms = vectorizer.get_feature_names()
    # 将tf-idf矩阵抽取出来,元素w[i][j]表示j词在i类文本中的tf-idf权重
    weight = tfidf.toarray()

    # for i in range(len(weight)):
    #     print(u"-------这里输出第", i, u"类文本的词语tf-idf权重------")
    #     for j in range(len(terms)):
    #         print(weight[i][j], end=' ')
    #     print()
    n_clusters = n
    model = KMeans(n_clusters)  # 聚类成5组
    model.fit(weight)  # 进行拟合

    for i in range(n_clusters):
        with open('cluster_' + str(i) + '.txt', encoding='utf-8', mode='w') as f:
            for j in range(len(model.labels_)):  # 读取每个聚类的词并写入文件
                if model.labels_[j] == i:
                    f.write(corpus[j] + '')

生成词云

def generateCloud(n):
    for i in range(n):
        f = open('cluster_' + str(i) + '.txt', encoding='utf-8')
        lines = []
        for line in f:
            if not line == '\n':
                lines.append(line.replace('\n', ''))
        all_words = ''.join(lines)  # 读取文本中的文件合并为1行
        color_mask = numpy.array(Image.open('mask.jpg'))
        cloud = WordCloud(
            # 设置字体,不指定就会出现乱码
            font_path='simhei.ttf',
            width=1000,
            height=1000,
            # 设置背景色
            background_color='white',
            # 词云形状
            mask=color_mask,
            # 允许最大词汇
            max_words=200,
            # 最大号字体
            max_font_size=300,
            collocations=False
        )
        word_cloud = cloud.generate(all_words)  # 产生词云
        word_cloud.to_file('cluster_cloud_' + str(i) + '.jpg')  # 保存图片

返回 Spark电影推荐