Python クローラー + K 平均法機械学習アルゴリズムに基づく今日のホット ニュース レコメンデーション システム - ホット レコメンデーション、ホット ワード プレゼンテーション、およびパーソナライズされた分析 (すべてのプロジェクト ソース コードを含む)


ここに画像の説明を挿入

序文

このプロジェクトは Web クローラー テクノロジーに基づいており、ニュース Web サイト上のニュース記事をクロールするために使用されます。これらの記事に対して中国語の単語分割と特徴抽出を行うことで、同様のニュースコレクションを構築することができます。

まず、Web クローラー テクノロジーを使用して、複数のニュース Web サイトからニュース記事を自動的にスクレイピングします。次に、これらの記事に対して中国語の単語分割を実行し、記事を独立した単語に分割します。次に、特徴抽出方法を使用して、後続のクラスタリング操作のために各記事をベクトルとして表します。

K 平均法アルゴリズムを使用すると、これらのニュース記事をクラスター化できます。K 平均法アルゴリズムは、類似した記事を同じカテゴリに分類し、ホット スポットを形成します。これにより、クラスタリング結果に基づいて注目のトピックを抽出し、関連するニュースをユーザーにレコメンドすることができます。

ホットレコメンドのほか、ホットワード提示やパーソナライズ分析も行えます。記事内の単語の出現頻度をカウントすることで、人気のキーワードを抽出し、ホットワードのプレゼンテーションを作成できます。同時に、ユーザーのこれまでの読書記録や嗜好に基づいてパーソナライズされた分析を行い、よりユーザーの興味に沿ったニュースをレコメンドすることができます。

このプロジェクトは、高いユーザビリティとユーザーエクスペリエンスを備えています。ニュースレコメンド機能により、ユーザーは興味のあるニュース内容を素早く入手できると同時に、自分の興味に関連した話題のトピックスを見つけることができます。これにより、ユーザーの読書体験と情報取得効率が大幅に向上します。

全体的なデザイン

システムの全体構成図とシステムフローチャートを記載します。

システム全体構成図

システムの全体構成を図に示します。

ここに画像の説明を挿入

システムフローチャート

システムフローを図に示します。

ここに画像の説明を挿入

動作環境

このセクションには、Python 環境、Pycharm 環境、および関連ライブラリ (matplotlib/sklearn) のダウンロードが含まれています。

Python環境

Python 3.6 以降の構成が必要です。Windows 環境に Anaconda をダウンロードして、Python に必要な構成を完了します。ダウンロード アドレスはhttps://www.anaconda.com/です。仮想マシンをダウンロードして、Linux 環境でコードを実行することもできます。

Pycharm環境

PyCharm コミュニティ バージョンが必要です。これは、JetBrains 公式 Web サイト ( https://www.jetbrains.com/pycharm/download ) から入手できます。プロンプトに従ってインストール手順を完了します。PyCharm を起動し、Licenseserver を選択し、アクティベーション サーバー アドレスにhttps://jetlicense.nss.im/を入力して、[Activate] をクリックしてアクティベーションを完了します。

関連ライブラリのダウンロード

Python の関連ライブラリ (matplotlib/sklearn など) は直接ダウンロードできませんが、Windows コマンド ラインを通じてダウンロードする必要があります。

pip install matplotlib
pip install scikit-learn

モジュールの実装

このプロジェクトには、データ クローリング、ニュース処理とクラスタリング、ニュース レコメンデーションの 3 つのモジュールが含まれており、各モジュールの機能と関連コードを以下に紹介します。

1. データクローリング

このモジュールは " 爬取分析.py" ファイルであり、指定されたニュース Web サイトと指定された日付のニュースをクロールし、指定されたシステム ディレクトリ フォルダーに保存できます。このプログラムでは、人民日報 Web サイト、Netease Social News、Baidu News Web サイトをクロールするかどうかを選択できます。関連するコードは次のとおりです。

import bs4
import os
import requests
import re
import time
from urllib import request
from bs4 import BeautifulSoup#引入“爬取.py”所需要的所有库


def fetchUrl_RMRB(url):
    '''
    功能:访问 人民日报url 的网页,获取网页内容并返回
    参数:目标网页的 url
    返回:目标网页的 html 内容
    '''
    headers = {
    
    
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
    }
    r = requests.get(url, headers=headers)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    return r.text

def getPageList_RMRB(year, month, day):
    '''
    功能:获取人民日报当天报纸的各版面的链接列表
    参数:年,月,日
    '''
    url = 'http://paper.people.com.cn/rmrb/html/' + year + '-' + month + '/' + day + '/nbs.D110000renmrb_01.htm'
    #在人民日报版面目录的链接中,“/year-month/day/” 表示日期,后面的 “_01” 表示这是第一版面的链接。
    html = fetchUrl_RMRB(url)
    bsobj = bs4.BeautifulSoup(html, 'html.parser')
    pageList = bsobj.find('div', attrs={
    
    'id': 'pageList'}).ul.find_all('div', attrs={
    
    'class': 'right_title-name'})
    linkList = []
    '''
    根据html分析可知,版面目录存放在一个
    id = “pageList” 的div标签下,class = “right_title1” 或 “right_title2” 的 div 标签中,
    每一个 div 表示一个版面
    '''
    for page in pageList:
        link = page.a["href"]
        url = 'http://paper.people.com.cn/rmrb/html/' + year + '-' + month + '/' + day + '/' + link
        linkList.append(url)
    return linkList

def getTitleList_RMRB(year, month, day, pageUrl):
    '''
    功能:获取报纸某一版面的文章链接列表
    参数:年,月,日,该版面的链接
    '''
    html = fetchUrl_RMRB(pageUrl)
    bsobj = bs4.BeautifulSoup(html, 'html.parser')
    titleList = bsobj.find('div', attrs={
    
    'id': 'titleList'}).ul.find_all('li')
    '''
    使用同样的方法,我们可以知道,文章目录存放在一个id = “titleList” 的div标签下的ul标签中,
    其中每一个li标签表示一篇文章
    '''
    linkList = []

    for title in titleList:
        tempList = title.find_all('a')
        #文章的链接就在li标签下的a标签中
        for temp in tempList:
            link = temp["href"]
            if 'nw.D110000renmrb' in link:#筛选出文章链接抓取,去除版面其他无关内容的链接
                url = 'http://paper.people.com.cn/rmrb/html/' + year + '-' + month + '/' + day + '/' + link
                linkList.append(url)
    return linkList

def getContent_RMRB(html):
    '''
    功能:解析人民日报HTML 网页,获取新闻的文章内容
    参数:html 网页内容
    '''
    bsobj = bs4.BeautifulSoup(html, 'html.parser')
    # 获取文章
    '''
    内容进入文章内容页面之后,由网页分析知正文部分存放在 id = “ozoom” 的 div 标签下的 p 标签里。
    '''
    pList = bsobj.find('div', attrs={
    
    'id': 'ozoom'}).find_all('p')
    content = ''
    for p in pList:
        content += p.text + '\n'
    resp = content
    return resp

def saveFile_RMRB(content, path, filename):
    '''
    功能:将文章内容 content 保存到本地文件中
    参数:要保存的内容,路径,文件名
    '''
    # 如果没有该文件夹,则自动生成
    if not os.path.exists(path):
        os.makedirs(path)

    # 保存文件
    with open(path + filename, 'w', encoding='utf-8') as f:
        f.write(content)

def download_RMRB(year, month, day, destdir):
    '''
    功能:爬取《人民日报》网站 某年 某月 某日 的新闻内容,并保存在 指定目录下
    参数:年,月,日,文件保存的根目录
    '''
    pageList = getPageList_RMRB(year, month, day)
    for page in pageList:
        titleList = getTitleList_RMRB(year, month, day, page)
        for url in titleList:
            # 获取新闻文章内容
            html = fetchUrl_RMRB(url)
            content = 'URL:'+url+ '\n' +getContent_RMRB(html)
            bsobj = bs4.BeautifulSoup(html, 'html.parser')
            title = bsobj.h3.text + bsobj.h1.text + bsobj.h2.text
            #剔除title的可能对识别造成影响的字符
            title = title.replace(':', '')
            title = title.replace('"', '')
            title = title.replace('|', '')
            title = title.replace('/', '')
            title = title.replace('\\', '')
            title = title.replace('*', '')
            title = title.replace('<', '')
            title = title.replace('>', '')
            title = title.replace('?', '')
            title = title.replace('.', '')
             # 生成保存的文件路径及文件名
            path = destdir + '/'
            fileName =title + '.txt'

            # 保存文件
            saveFile_RMRB(content, path, fileName)

def fetchUrl_WY(url):
    '''
    功能:访问 网易社会url 的网页,获取网页内容并返回
    参数:目标网页的 url
    返回:目标网页的 html 内容
    '''
    headers = {
    
    
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
    }
    r = requests.get(url, headers=headers)
    r.raise_for_status()
    r.encoding = r.apparent_encoding
    return r.text

def download_WY(title, url, year, month, day):
    '''
    功能:爬取网易社会网站某一URL当日的新闻内容,并保存在指定目录下
    参数:新闻标题,抓取的URL,年,月,日
    '''
    html = fetchUrl_WY(url)
    bsobj = bs4.BeautifulSoup(html, 'html.parser')
    title = title.replace(':', '')
    title = title.replace('"', '')
    title = title.replace('|', '')
    title = title.replace('/', '')
    title = title.replace('\\', '')
    title = title.replace('*', '')
    title = title.replace('<', '')
    title = title.replace('>', '')
    title = title.replace('?', '')
    title = title.replace('.', '')
    #获取新闻的时间来源 class='post_time_source'
    time = bsobj.find('div', class_='post_time_source').text
    #获取新闻正文内容
    tag = bsobj.find('div', class_='post_text').text
    file_name = r'F:\今日新闻\\' + title + '.txt'
    file = open(file_name, 'w', encoding='utf-8')
    tag = tag.replace(' ', '')
    content = 'URL:' + url + '\n' + '发布时间:' + time + '\n' + tag
    #写入文件
    file.write(content)

def downloads_WY():
    '''
    功能:爬取网易社会网站所有种子URL(URL数组)下的新闻内容,并保存在指定目录下
    参数:无
    '''
    urls = ['http://temp.163.com/special/00804KVA/cm_shehui.js?callback=data_callback',
            'http://temp.163.com/special/00804KVA/cm_shehui_02.js?callback=data_callback',
            'http://temp.163.com/special/00804KVA/cm_shehui_03.js?callback=data_callback']
    '''
    网易新闻的标题及内容是使用js异步加载的,单纯的下载网页源代码是没有标题及内容的
    我们可以在Network的js中找到我们需要的内容
    '''
    for url in urls:
        req = request.urlopen(url)
        res = req.read().decode('gbk')
        pat1 = r'"title":"(.*?)",'
        pat2 = r'"tlink":"(.*?)",'
        m1 = re.findall(pat1, res)
        news_title = []
        for i in m1:
            news_title.append(i)
        m2 = re.findall(pat2, res)
        news_url = []
        for j in m2:
            news_url.append(j)
        for i in range(0, len(news_url)):
            download_WY(news_title[i], news_url[i], year, month, day)

def fetchUrl_BD(url, headers): #爬取百度news所有url
	urlsss = []
	r = requests.get(url, headers=headers).text
	soup = BeautifulSoup(r,'lxml')
	for i in soup.find_all('h3'):  #文章标题存放在 h3 标签中
		urlsss.append(i.a.get('href'))
	return urlsss

def getContent_BD(urls,headers,year,month,day): #对抓取到的百度新闻连接的内容的操作
	#先检查是否存在该文件夹
	if os.path.exists('F:/今日新闻/'):
		pass
	else:
		os.mkdir('F:/今日新闻/')
	for q in urls:
		try:
			time.sleep(2)#定时抓取
			r = requests.get(q, headers=headers).text
			soup = BeautifulSoup(r,'lxml')
			for i in soup.find('div', class_="article-title"): #每章的标题
				if os.path.exists('F:/今日新闻/' +i.get_text() +'.txt'): #检查是否已存在该文件
					continue#内容已经抓取过并存在文件夹中,不必再抓取
				else:
					for i in soup.find('div', class_="article-title"): #每章的标题
						title = i.get_text().replace(':', '')
						title = title.replace('"', '')
						title = title.replace('|', '')
						title = title.replace('/', '')
						title = title.replace('\\', '')
						title = title.replace('*', '')
						title = title.replace('<', '')
						title = title.replace('>', '')
						title = title.replace('?', '')
						title = title.replace('.', '')
						f = open('F:/今日新闻/' +title +'.txt','w',encoding='utf-8')
					for i in soup.find_all('div', class_="article-source article-source-bjh"): #发布日期
						aas =  i.find(class_="date").get_text()
						aad =  i.find(class_="time").get_text()
						aaf = 'URL:%s'%q
						f.write(aaf + '\n')
						f.write(aas)
						f.write(aad + '\n')
					for i in soup.find_all('div', class_="article-content"): #每章的内容
						f.write(i.get_text())
						f.close()
		except Exception as result:#处理异常抓取的情况,使程序继续爬取其他网页
			continue

def download_BD():#下载百度新闻的内容以文件形式保存
	headers = {
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36'}
	url = 'https://news.baidu.com/widget?id=AllOtherData&channel=internet&t=1554738238830'
	getContent_BD(fetchUrl_BD(url,headers), headers,year,month,day)

if __name__ == '__main__':
    '''
    主函数:程序入口
    '''
    # 爬取指定日期的新闻
    newsDate = input('请输入要爬取的日期(格式如 20200101 ):')

    year = newsDate[0:4]
    month = newsDate[4:6]
    day = newsDate[6:8]

    #对想爬取收集的网站进行选择
    flag_RMRB = input('是否爬取人民日报?是-1 否-0:')
    if flag_RMRB == '1':
        download_RMRB(year,month,day, 'F:/今日新闻')
        print("人民日报爬取完成!" )

    flag_WY = input('是否爬取网易社会新闻?是-1 否-0:')
    if flag_WY == '1':
        downloads_WY()
        print('网易社会抓取完成!')

    flag_BD = input('是否爬取百度新闻?是-1 否-0:')
    if flag_BD == '1':
        download_BD()
        print('百度新闻抓取完成!')

2. ニュースの処理とクラスタリング

モジュールに分类预备.pyは と分类.pyドキュメントが含まれています。分類準備ファイルでは、クロールされた各ニュースを漢字以外の文字でフィルタリングし、分類フォルダーを作成します; 分類ファイルでは、TF-IDF ベクタライザーを使用してすべてのニュースを単語頻度行列に変換し、それに応じてクラスター化しますK 平均法に変換して結果を出力し、分類されたファイルを生成します。

1) 分類の準備

分類準備の機能は、単語リストを無効にしてニュース内の漢字を除くすべての文字をフィルタリングし、中国語の単語分割を分類し、さまざまなニュースの分類と保存に便利な分類ファイルの保存パスを作成することです。関連するコードは次のとおりです。

import os
import re
'''
“分类预备.py”程序 功能1:过滤新闻中除中文外所有字符,便于进行分类中的中文分词 
功能2:创建分类文件的保存路径,便于进行分类不同类别新闻归类保存
'''

path1='F:\\今日新闻\\过滤'
if os.path.exists(path1):
    path1 = 'F:\\今日新闻\\过滤'
else:
    os.makedirs(path1)
path='F:\\今日新闻'
dirs = os.listdir(path)
for fn in dirs:                            # 循环读取路径下的新闻文件并筛选输出
    if os.path.splitext(fn)[1] == ".txt":   # 筛选txt文件
        print(fn)
        inputs = open(os.path.join('F:\\','今日新闻',fn), 'r',encoding='UTF-8')  # 加载要处理的文件的路径
        guolv = open(path + '\\' + '过滤\\' + fn, 'w', encoding='UTF-8')
        for eachline in inputs:
            eachline = re.sub(u"([^\u4e00-\u9fa5])","",eachline)#只保留汉字字符
            guolv.write(eachline)
        guolv.close()

for i in range(0,50): #创建分类文件的保存路径,便于进行分类不同类别新闻归类保存
    if os.path.exists('F:/今日新闻/分类/'+'label_'+str(i)+'/'):
        pass
    else:
        os.makedirs('F:/今日新闻/分类/'+'label_'+str(i)+'/')

2) TF-IDF ベクトル化 用語
頻度 (用語頻度、TF) は、ファイル内で特定の単語が出現する頻度を指します。この数値は、長いファイルへの偏りを防ぐために用語数に正規化されます。

ある記事では頻繁に出現するが、他の記事ではほとんど出現しない語句は、カテゴリ識別能力が高く、分類に適していると考えられる。

逆文書頻度 (IDF) は、単語の重要性の尺度です。特定の用語の IDF は、ドキュメントの総数をその用語を含むドキュメントの数で割り、10 を底とする対数をとることで取得できます。

TF と IDF の積を計算します。特定の文書内での単語の出現頻度が高く、文書のコレクション全体でのその単語の出現頻度が低いと、TF-IDF の重み付けが高くなる可能性があります。したがって、TF-IDF は一般的な単語を除外する傾向があります。関連するコードは次のとおりです。

from __future__ import print_function
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import CountVectorizer
from sklearn import feature_extraction
from os import listdir
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans, MiniBatchKMeans
import jieba
import os
import re
import shutil
import glob

labels = []#用于存储所有文本标题
def loadDataset():
    '''导入文本数据集,建立语料库'''
    all_file = listdir('F:/今日新闻/过滤')
    corpus = []
    typetext = open('C:/Users/Yoshine/Desktop/stop.txt',encoding='UTF-8')#加载停用词表
    texts = ['\u3000','\n','']
    for word in typetext:
        word = word.strip()
        texts.append(word)
    for i in range(0,len(all_file)):
       filename = all_file[i]
       filelabel = filename.split('.')[0]
       labels.append(filelabel)#所有文本标题
       file_add = 'F:/今日新闻/过滤/' + filename
       doc = open(file_add,encoding='utf-8').read()
       data = jieba.cut(doc)#对打开的文本进行分词
       data_adj=""
       delete_word = []
       for item in data:#运用停用词表进行过滤
            if item not in texts:
                data_adj= data_adj+item + ' '
            else:
                delete_word.append(item)
       corpus.append(data_adj)
    return corpus

def transform(dataset, n_features=1000):
    '''将文本数据转化为词频矩阵'''
    vectorizer = TfidfVectorizer(max_df=0.5, max_features=n_features, min_df=2, use_idf=True)
    X = vectorizer.fit_transform(dataset)

    return X, vectorizer

3) K 平均クラスタリング アルゴリズム
この部分には、クラスタリング基準と K 値の選択が含まれます。

(1) クラスタリングの基準

TF-IDF アルゴリズムを使用して、各記事内のキーワードの数 (このプロジェクトでは 10 個が使用されます) を見つけ、それらをセットにマージし、セットに対する各記事の単語頻度を計算します (キーワードの影響を避けるため)。記事の長さ、相対的な単語頻度を使用)。2 つの記事の単語頻度ベクトルを生成し、2 つのベクトルのコサイン類似度を計算し、値が大きいほど類似度が高くなります。関連するコードは次のとおりです。

def train(X, vectorizer, true_k=10, minibatch=False, showLable=False):
    # 使用采样数据还是原始数据训练k-means,
    if minibatch:
        km = MiniBatchKMeans(n_clusters=true_k, init='k-means++', n_init=1,
                             init_size=1000, batch_size=1000, verbose=False)
    else:
        km = KMeans(n_clusters=true_k, init='k-means++', max_iter=300, n_init=1,
                    verbose=False)
    km.fit(X)
    y = km.fit_predict(X)
    for i in range(true_k):
        label_i=[]
        fileNames = glob.glob('F:/今日新闻/分类/label_' + str(i)+'/'+r'\*')
        for filename in fileNames:
            os.remove(filename)#清除原分类文件夹下的文件
        for j in range(0,len(y)):
            if y[j]==i:
                label_i.append(labels[j])
                title = labels[j]
                shutil.copy('F:/今日新闻/'+title+'.txt','F:/今日新闻/分类/label_' + str(i)+'/'+title+'.txt')
                #把符合分类条件的文本复制入对应分类文件夹
        print('label_'+str(i)+':'+str(label_i)+'\n')

    if showLable:
        print("Top terms per cluster:")
        order_centroids = km.cluster_centers_.argsort()[:, ::-1]
        terms = vectorizer.get_feature_names()#分类后文本中心词
        print(vectorizer.get_stop_words())
        for i in range(true_k):
            print("Cluster %F:" % i, end='  ')#输出类名
            for ind in order_centroids[i, :10]:
                print(' %s' % terms[ind], end='')#输出该类文本的前10个中心词
            print()
    result = list(km.predict(X))
    print('Cluster distribution:')
    print(dict([(i, result.count(i)) for i in result]))#输出分类组成,即每一类的文本个数
    return -km.score(X)

(2) K値の選択

すべてのサンプルの係数をシルエット係数法を使用して取得し、平均して平均シルエット係数を取得しました。
平均シルエット係数の値の範囲は [-1, 1] で、クラスター内のサンプル間の距離が近いほど、またクラスター間のサンプル間の距離が遠いほど、平均シルエット係数が大きくなり、クラスター化がより良くなります
。効果を考慮し、最大の平均シルエット係数を持つ K が最適な
クラスター数になります。関連するコードは次のとおりです。

def test():
    '''测试选择最优参数'''
    dataset = loadDataset()
    print("%d documents" % len(dataset))
    X, vectorizer = transform(dataset, n_features=500)
    true_ks = []
    scores = []
    #依次对不同k取值进行测试得到其轮廓系数,保存每次结果并以曲线图呈现
    for i in range(3, 80, 1):
        sl = 0
        for j in range(0,10):#对每个k值进行多次kmeans聚类,得到轮廓系数的平均值
            score = train(X, vectorizer, true_k=i) / len(dataset)
            sl = sl + score
        print(i, score)
        true_ks.append(i)
        scores.append(sl/10)
    #画图
    plt.figure(figsize=(8, 4))
    plt.plot(true_ks, scores, label="error", color="red", linewidth=1)
    plt.xlabel("n_features")
    plt.ylabel("error")
    plt.legend()
    plt.show()

3. ニュースのおすすめ

このセクションには、ホット ニュースの推奨、ニュースのホット ワードの推奨、およびパーソナライズされた推奨が含まれます。

1) おすすめのホットニュース

「 」ファイルで推荐.py、分類された各フォルダーをセグメント化、フィルター処理し、ベクトル化して、フォルダーの種類ごとにニュースの数とリリース時間を比較し、指数減衰式を使用して重みを計算し、最も人気のあるニュースと出力を取得します。推奨される結果。関連するコードは次のとおりです。

import os
import math
import linecache
import re
import codecs
import time
import jieba
from jieba import analyse
from collections import Counter

import matplotlib.pyplot as plt
from wordcloud import WordCloud


def fenci(txtPath):
    with codecs.open(txtPath, 'r', 'utf8') as f:
        txt = f.read()
    seg_list = jieba.cut(txt)
    # 创建停用词list
    stopwords = [line.strip() for line in open('C:/Users/Yoshine/Desktop/stop.txt', 'r', encoding='utf-8').readlines()]
    clean_list = []
    for word in seg_list:
        if word not in stopwords:
            if ord(word[0]) > 127:
                if word != '\t':
                    clean_list.append(word)
    return clean_list


def tf(seg_list):
    dic_value = {
    
    }
    for word in seg_list:
        if len(word) > 1 and word != '\r\n':
            if not dic_value.get(word):
                dic_value[word] = [1, 0]
            else:
                dic_value[word][0] += 1
    return dic_value


def idf(filePath, dic_value):
    N = 0  # 文章篇数
    idf = 0
    files = os.listdir(filePath)
    for file in files:
        N += 1
    for word in dic_value:
        df = 0
        for file in files:
            # 读入每个txt文件
            txtPath = filePath + '/' + file
            with codecs.open(txtPath, 'r', 'utf8') as f:
                txt = f.read()
            # 判断该词是否在txt中出现
            if re.findall(word, txt, flags=0):
                df += 1
        if df:
            idf = N / df
        dic_value[word][1] = idf
    return dic_value


def weight(dic_value):
    w_value = {
    
    }
    weight = 0
    for key in dic_value:
        weight = dic_value[key][0] * dic_value[key][1]
        w_value[key] = weight
    return w_value


def cos(w1_value, w2_value):
    w_mul = 0
    w1_exp = 0
    w2_exp = 0
    cos = 0
    fenzi = 0
    for word in w1_value:
        if word in w2_value:
            w_mul += float(w2_value[word])
            w1_exp += math.pow(1, 2)
            w2_exp += math.pow(w2_value[word], 2)
    fenzi = (math.sqrt(w1_exp) * math.sqrt(w2_exp))
    if fenzi:
        cos = w_mul / (math.sqrt(w1_exp) * math.sqrt(w2_exp))
    return cos


def similarity(filePath, standard):
    files = os.listdir(filePath)
    stan_list = jieba.cut(standard)
    w1_value = tf(stan_list)
    sim = {
    
    }
    for file in files:
        txtPath = filePath + '/' + file
        seg_list = fenci(txtPath)
        tf_value = tf(seg_list)
        dic_value = idf(filePath, tf_value)
        w2_value = weight(dic_value)
        cos_value = cos(w1_value, w2_value)
        sim[file] = cos_value
    sim_sort = sorted(sim.items(), key=lambda item: item[1], reverse=True)
    i = 0
    for ns_name in sim_sort:
        if i < 3:
            real_name = re.sub(".txt", "", ns_name[0])
            real_name = "    " + real_name
            print(real_name)
        else:
            break
        i += 1


def hot_news(filePath):
    # 对类中的每篇新闻操作
    files = os.listdir(filePath)  # 得到文件夹下的所有文件名称
    Atime = [0] * 50  # 记录每小时内的新闻数
    i = -1
    a = 0.8
    for file in files:  # 遍历文件夹
        i = (i+1) % 12 + 12
        if not os.path.isdir(file):  # 判断是否为文件夹,不是文件夹就打开
            # txt_judge = linecache.getline(filePath + "\\" + file, 2).strip()
            # if re.match('发布时间', txt_judge):
            news = linecache.getline(filePath + "\\" + file, 3).strip()
            if re.findall(r'[0-9]+-[0-9]+-[0-9]+', news, flags=0):
                date_string = re.findall(r'[0-9]+-[0-9]+-[0-9]+', news, flags=0)
                # print(date_string)
                time_string = re.findall(r'[0-9]+:[0-9]+:[0-9]+', news, flags=0)
                # print(time_string)
                news_time_string = date_string[0] + " " + time_string[0]
                # print(news_time_string)
                news_time = int(time.mktime(time.strptime(news_time_string, "%Y-%m-%d %H:%M:%S")))
                now_data = '2020-03-25 00:00:00'
                now = int(time.mktime(time.strptime(now_data, "%Y-%m-%d %H:%M:%S")))
                delta = now - news_time
                m, s = divmod(delta, 60)
                h, m = divmod(m, 60)
                Atime[h] = int(Atime[h]) + 1
            else:
                Atime[i] = int(Atime[i]) + 1
        else:
            continue
    # 指数衰减公式
    i = 0
    weight = 0
    while i < 50:
        weight = weight + a * math.pow((1 - a), i) * Atime[i]
        i += 1
    return weight

2) ニュースホットワードのレコメンド

レコメンドファイルでは、ニュースを現在時刻から遠い古いニュースと現在時刻に近い新しいニュースに分け、新しいニュースの単語の頻度と古いニュースの単語の頻度を表示します。をカウントし、ベイズ公式を用いて単語の人気度を計算しソートし、クラウドマップの形で出力することでホットワードマップを取得します。関連するコードは次のとおりです。

def hotwords(filePath):
    value = Counter()
    tf_value = {
    
    }
    for root, dirs, files in os.walk(filePath):  # dirs 不能去掉
        for file in files:
            txtPath = os.path.join(root, file)
            seg_list = fenci(txtPath)
            judge = time_judge(txtPath)
            if judge == 2:
                for new in seg_list:
                    if len(new) > 1 and new != '\r\n':
                        if not tf_value.get(new):
                            tf_value[new] = [0, 1]
                        else:
                            tf_value[new][1] += 1
                        # print("这是新词")
                        # print(tf_value[new])
            else:
                for old in seg_list:
                    if len(old) > 1 and old != '\r\n':
                        if not tf_value.get(old):
                            tf_value[old] = [1, 0]
                        else:
                            tf_value[old][0] += 1
                        # print("这是旧词")
                        # print(tf_value[old])

    for key in tf_value:
        if tf_value[key][0] == 0:
            continue
        result = tf_value[key][1] / (tf_value[key][1] + tf_value[key][0])
        value[key] = result
    text1 = ""
    for (k, v) in value.most_common(12):
        text1 = text1 + " " + k

    wc = WordCloud(
        background_color="white",  # 设置背景为白色,默认为黑色
        collocations=False, font_path='C:/Windows/Fonts/SimHei.ttf', width=1400, height=1400, margin=2
    ).generate(text1.lower())
    # 为云图去掉坐标轴
    plt.axis("off")
    # 画云图,显示
    # plt.show(wc)
    # 保存云图
    wc.to_file("C:/Users/Yoshine/Desktop/wordcloud.png")

3) 個別の推奨事項

推荐.py」ファイルでは、ユーザーが指定したキーワードに従って、クロールされたすべてのニュースの類似性を比較し、ユーザーが興味のあるニュースと一致し、最も関連性の高い 3 つのニュースをレコメンド結果として出力します。関連するコードは次のとおりです。

def interet(filePath):
    print("请输入你感兴趣的新闻话题:")
    words = input()

    w1_value = {
    
    }
    w1_value[words] = 1

    files = os.listdir(filePath)
    sim = {
    
    }
    news_name = []
    for root, dirs, files in os.walk(filePath):  # dirs 不能去掉
        for file in files:
            txtPath = os.path.join(root, file)
            seg_list = fenci(txtPath)
            tf_value = tf(seg_list)
            dic_value = idf(root, tf_value)
            w2_value = weight(dic_value)
            cos_value = cos(w1_value, w2_value)
            sim[file] = cos_value
    sim_sort = sorted(sim.items(), key=lambda item: item[1], reverse=True)
    i = 0
    for ns_name in sim_sort:
        if i < 3:
            real_name = re.sub(".txt", "", ns_name[0])
            news_name.append(real_name)
            print(i+1, '、', news_name[i])
        else:
            break
        i += 1

システムテスト

この部分には、データ準備、テキスト クラスタリング、ホット ニュースの推奨、ホット ワードのプレゼンテーション、およびパーソナライズされた推奨のテスト結果が含まれます。

1. データの準備

実行インターフェイスは図のようになり、日付を入力し、3 つの Web サイトからニュースをクロールするかどうかを選択します。

ここに画像の説明を挿入

図に示すように、ユーザーの選択に従ってニュースをクロールして保存します。

ここに画像の説明を挿入

分類の準備では、図に示すように、主にニュース内の漢字を除くすべての文字をフィルタリングします。

ここに画像の説明を挿入

2. テキストクラスタリング

図に示すように、トラバースして K 値と対応する等高線係数ポリラインを取得します。

ここに画像の説明を挿入

折れ線グラフを観察し、最適なKパラメータとして変曲点の値(K=47)を選択し、このときのシルエット係数を結果出力制御の判定条件として記録します。シルエット係数がこれより小さい場合のみ記録します。値 (0.617) であれば、分類は有効です。以下は、最適パラメータ K=47 の下での K 平均クラスタリングの結果であり、下の図は分類の 1 つを示しています。

ここに画像の説明を挿入

3. 注目のニュースレコメンド

分類後、人気度を計算し、人気度に応じてニュースを推奨します。推奨結果は、最も人気のあるカテゴリ名 10 件と、このカテゴリ内の最も関連性の高いニュース記事 3 件です。図 1 には複数の種類のニュースが表示され、図 2 に示すようにホットワードがクラウド マップの形式で表示されます。

ここに画像の説明を挿入

図1 ホットニュースの表示

ここに画像の説明を挿入

図 2 ホットワードクラウド

ユーザーは興味のあるニュース トピックを入力すると、関連する 3 つのニュースの推奨事項が表示されます。キーワード「イタリア」を入力すると、結果が図に表示されます。

ここに画像の説明を挿入

プロジェクトのソースコードのダウンロード

詳細については、ブログ リソースのダウンロード ページをご覧ください。

その他の情報ダウンロード

人工知能関連の学習ルートと知識システムについて学び続けたい場合は、私の他のブログ「重い | 完全な人工知能 AI 学習 - 基本知識学習ルート、すべての資料は料金を支払わずにネットワーク ディスクから直接ダウンロードできます」を参照してください。 「ルーチンへの注意
このブログでは、Github の有名なオープンソース プラットフォーム、AI テクノロジー プラットフォーム、および関連分野の専門家 (Datawhale、ApacheCN、AI Youdao、Huang Haiguang 博士など) について言及しています。関連資料は約 100G あります。友達全員を助けてください。

おすすめ

転載: blog.csdn.net/qq_31136513/article/details/131419366