亂燉“簡書交友”資料之程式碼(1)

古柳_Deserts_X發表於2018-06-13
上一篇文章亂燉資料之2700餘篇“簡書交友”專題文章資料的花式玩法釋出後,不少人想學習下程式碼,由於此前不曾在GitHub上開源過,流程還不熟悉,再者本專案中很多嘗試性的程式碼,異常雜亂,因而沒有立馬公開。在經過刪減和整理後,將繼續更新出來。
本文主要涉及一些結構化資料的分析,文字資料如詞頻統計、詞雲圖等等。暫且跳過爬蟲部分。 程式碼見於 GitHub - DesertsX / JianShuJiaoYou,後續LDA主題模型、word2vec詞向量、文章照片爬取、人臉識別及顏值打分和照片牆等等更新後也會開源在此專案,歡迎star與指正。
另外先預告下,之後打算開個“Kaggle Kernel 學習系列”,GitHub - DesertsX / Kaggle-Kernel-Learning,主要是翻譯和學習下kaggle上優秀的kernels。其中第一篇非常粗糙,還沒潤色、修改排版佈局的notebook可供瀏覽下,也歡迎關注、star和提供寶貴建議: desertsx.github.io/2018/06/09/… desertsx.github.io/2018/06/09/…

結構化資料

文章配圖數

讀取資料
import pandas as pd
df12 = pd.read_csv('JianShuJiaoYou-All-Data.csv', encoding='utf-8')
df12.head(2)複製程式碼
結果如下:
Page    Num Author  Author_Url  Title   Time    Read    Comment Like    Abstract    Artical_Url Image_Url   Artical_Content
0   1   0   劉秀玲 https://www.jianshu.com/u/470f33ea0c92  我要嫁這樣的你 2016-07-25T12:16:39+08:00   109763  4508    5333    你不用太高,比穿三五釐米跟鞋的我看起來不矮就行。我不是小鳥依人的型,累了或者想哭的時候,我願...   https://www.jianshu.com/p/8de3d395734f  ['//upload-images.jianshu.io/upload_images/125...   你不用太高,比穿三五釐米跟鞋的我看起來不矮就行。我不是小鳥依人的型,累了或者想哭的時候,我願...
1   1   1   道長是名思維販子    https://www.jianshu.com/u/92eb338437ee  如果你喜歡一個人,說些什麼話讓對方也喜歡你呢  2017-10-29T11:42:34+08:00   69260   497 3693    NaN https://www.jianshu.com/p/373d67f7cbce  ['//upload-images.jianshu.io/upload_images/299...   你現在有沒有喜歡一個人?複製程式碼
新增Images_Num一列記錄每篇文章配圖數,但發現數字異常,Image_Url中的每一元素是字串而非列表。
def images_num(imageslist):
    return len(imageslist)
df12['Images_Num'] = df12.Image_Url.apply(images_num)
df12.head(1)

df12.Images_Num.hist();複製程式碼
亂燉“簡書交友”資料之程式碼(1)
將字串轉化成 list 格式
eval()函式:可以將 list, tuple, dict 與 string 相互轉化
例項:
a = "[[1,2], [3,4], [5,6], [7,8], [9,0]]"
print(a)
print(type(a))
b = eval(a)
print(b)
print(type(b))複製程式碼
輸出結果:
[[1,2], [3,4], [5,6], [7,8], [9,0]]
<class 'str'>
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 0]]
<class 'list'>複製程式碼
統計每篇文章配圖數的正確方式
def images_num(imageslist):
    return len(eval(imageslist))
df12['Images_Num'] = df12.Image_Url.apply(images_num)
df12.head(1)複製程式碼
分佈情況
df12.Images_Num.value_counts()複製程式碼
直方圖 分佈情況一目瞭然,文章配圖數最多的高達80+。
df12.Images_Num.hist();複製程式碼
亂燉“簡書交友”資料之程式碼(1)

文章長度 / 字數

粗略統計下每篇文章的長度
def artical_length(artical_content):
    return len(artical_content)
df12['Artical_Length'] = df12.Artical_Content.apply(artical_length)
df12.head(1)

df12.Artical_Length.hist();複製程式碼

亂燉“簡書交友”資料之程式碼(1)

字數與配圖數

看看文章篇幅和配圖數之間是否存在某種關係。 seaborn.jointplot
import seaborn as sns
sns.jointplot(x="Artical_Length" , y = "Images_Num" ,data = df12);複製程式碼

亂燉“簡書交友”資料之程式碼(1)

改個引數看看
sns.jointplot(x="Artical_Length" , y = "Images_Num" ,data = df12, kind="hex");複製程式碼

亂燉“簡書交友”資料之程式碼(1)

評論數與點贊數

由皮爾遜相關係數為0.58可知,評論數與點贊數有一定的線性相關性。
sns_joinplot = sns.jointplot(x="Like" , y = "Comment" ,data = df12);
sns_joinplot.savefig('seaborn_Like_Comment_joinplot.png')複製程式碼
亂燉“簡書交友”資料之程式碼(1)

閱讀量、評論數與點贊數

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
%matplotlib inline

plt.figure(figsize=(12, 7))
ax1 = plt.subplot(111,projection='3d')
x,y,z = df12['Read'],df12['Comment'],df12['Like']
ax1.scatter(x, y, z, s=15)
ax1.set_title('Read-Commnet-Like')
ax1.set_zlabel('Like')
ax1.set_ylabel('Comment')
ax1.set_xlabel('Read')
#plt.show()複製程式碼

亂燉“簡書交友”資料之程式碼(1)

多變數

看看閱讀量、評論數、點贊數、文章篇幅與配圖數五個變數之間的相關關係。

Pairplot圖

import matplotlib.pyplot as plt
data = df12[["Read", "Comment", "Like", "Artical_Length","Images_Num"]]
#plt.figure(figsize=(6,4))
g = sns.pairplot(data, palette="husl");
g.savefig('seaborn_pairplot.png')複製程式碼

亂燉“簡書交友”資料之程式碼(1)

Heatmap圖

sns.heatmap(data=data.corr(), annot=True, linewidths=0, vmin=-0.2, cmap='RdBu_r');

複製程式碼
亂燉“簡書交友”資料之程式碼(1)

sns.heatmap( data=data.corr(), annot=True, linewidths=0, vmin=-0.2, cmap='YlGnBu');複製程式碼
亂燉“簡書交友”資料之程式碼(1)

文章釋出時間

從Time列分別提取年份、月份、天、小時等等資料。
def split_time_ymd(timestamp):
    ymd = timestamp.split('T')[0]
    return ymd

def split_time_year(timestamp):
    ymd = timestamp.split('T')[0]
    year = ymd.split('-')[0]
    return year

def split_time_month(timestamp):
    ymd = timestamp.split('T')[0]
    month = ymd.split('-')[1]
    return month

def split_time_day(timestamp):
    ymd = timestamp.split('T')[0]
    day = ymd.split('-')[-1]
    return day

def split_time_hour(timestamp):
    timestamp = timestamp.split('T')[1]
    hour = timestamp[:2]
    return hour

df12['YMD'] = df12.Time.apply(split_time_ymd)
df12['Year'] = df12.Time.apply(split_time_year)
df12['Month'] = df12.Time.apply(split_time_month)
df12['Day'] = df12.Time.apply(split_time_day)
df12['Hour'] = df12.Time.apply(split_time_hour)
df12.head(2)

複製程式碼

發文年份

可以和另一專題“今日看點”及一篇舊文裡的資料比較:簡書=雞湯?爬取簡書今日看點:1916篇熱門文章視覺化
df12.Year.value_counts()

# 輸出結果
    2018    1992
    2017     718
    2016       6
    2015       2
    Name: Year, dtype: int64

import matplotlib.pyplot as plt
%matplotlib inline
df12.Year.hist();複製程式碼
亂燉“簡書交友”資料之程式碼(1)

發文月份

df12.Month.value_counts()

# 輸出結果
    04    644
    03    471
    05    444
    02    251
    11    237
    08    205
    01    188
    12     93
    10     93
    09     82
    07      8
    06      2
    Name: Month, dtype: int64

df12.Month.hist();複製程式碼
亂燉“簡書交友”資料之程式碼(1)

發文日期

df12.Day.hist();複製程式碼
亂燉“簡書交友”資料之程式碼(1)

發文小時

df12.Hour.hist();複製程式碼
亂燉“簡書交友”資料之程式碼(1)

ECharts美顏一下:發文小時

上述繪製的釋出時間的相關圖表都不夠美觀,於是翻出壓箱底的又一篇舊文:圖表太醜怎麼破,ECharts神器帶你飛!
直接套用ECharts圖表模板,改下資料和標題等引數就行了,程式碼參見:簡書交友”專題文章之24小時分佈情
更多圖表見於:ECharts3官網的個人主頁
亂燉“簡書交友”資料之程式碼(1)

年度月份分佈情況

df12.groupby(['Year','Month']).Month.count()

# 輸出結果
    Year  Month
    2015  04         1
          09         1
    2016  07         2
          08         1
          10         1
          12         2
    2017  01         1
          02         3
          04         1
          06         2
          07         6
          08       204
          09        81
          10        92
          11       237
          12        91
    2018  01       187
          02       248
          03       471
          04       642
          05       444
    Name: Month, dtype: int64複製程式碼

ECharts美顏一下:年度月份

將echarts_bar_year_month.js裡程式碼複製到該連結後重新整理即可:“簡書交友”專題文章之年度月份分佈情況
亂燉“簡書交友”資料之程式碼(1)

文字挖掘

讀取資料

import warnings
warnings.filterwarnings("ignore")
import jieba
import numpy as np
import codecs
import pandas as pd  
import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib
matplotlib.rcParams['figure.figsize'] = (10.0, 5.0)
from wordcloud import WordCloud
# https://github.com/amueller/word_cloud/
# conda install -c conda-forge wordcloud

複製程式碼

文章內容轉化成 list 格式

這段情話還不錯的樣子,一定是個可愛漂亮的小姐姐寫的吧,逃...
content = df12.Artical_Content.values.tolist()
print(len(content), '\n', content[-1])

2718 
我攢了一被子的情話,想要說給你聽最近有種很雜碎的感覺,嗯...如果用比喻修辭來說的話,就是已經很久都沒有那種寫完滿滿一張紙的感覺,沒有看完整整一本書的感覺,沒有跑完操場一圈,沒有聽完一整首歌,也沒有睡滿整整一夜。總感覺還是缺一點什麼。但我有很走心的去想了,可能是因為缺了每一個可愛的你。“如果是去見你,我會跑著去”剛看到這句話的時候,我也很贊同,因為畢竟去見一個想見了很久的人的時候,怎麼也按捺不住你你內心的欣喜。到後來,當你真正去見ta的時候,你沒有跑,你依然故作鎮定的樣子,只是你會比平時都邁的步子大一點,你擔心你跑起來的樣子不那麼美觀,你擔心就算是夏天的微風也還是會把你輕薄的劉海吹亂。你會在意每個細節,你每次都希望你在ta面前是最好的狀態。嗨,如果要去見你的話,我不跑著去了,我只想以我最好的狀態去見你你像是我被子裡的舒服你像是我右手背上的那顆痣你像是我眼角微微泛出來的光你像是我全身每一寸肌膚在呼吸你像是我枕頭裡的枕芯棉你像是我買過最好看書裡的一頁你像是我踩著雲就可以飛上天你像是我走過的所有路途最想停留的瞬間你是我在夜晚閉上眼最後想到的人你是我在清晨睜開眼最先念起的人你是我的一日三餐你是我的一年四季來不及了不想再浪費時間昨天,今天,明天我還是最喜歡你總有一個人的出現,讓我像流沙,像落雪。那些別人在上面劃了又劃的痕跡,你輕輕一抹,就平了。攢了一被子的情話,以後慢慢數給你聽。希望認識更多可愛的人,一起做喜歡的事,寫最純真的字,講有趣的故事。我是禮雪晶,那麼你呢?作者:禮雪晶。“真羨慕你們這麼年輕就遇到了這麼才華橫溢的我。”一個整天與數字對抗卻藏了一被子情話的95後女生。願你的深情不被辜負,你喜歡的人也喜歡你。

複製程式碼

jieba 分詞

segs = jieba.lcut(content[-1])
print(segs)
for seg in segs:
    if len(seg) > 1:
        print(seg)

# 輸出結構
['我', '攢', '了', '一', '被子', '的', '情話', ',', '想要', '說', '給', '你', '聽', '最近', '有種', '很', '雜碎', '的', '感覺', ',', '嗯', '...', '如果', '用', '比喻', '修辭', '來說', '的話', ',', '就是', '已經', '很久', '都', '沒有', '那種', '寫', '完', '滿滿', '一張', '紙', '的', '感覺', ',', '沒有', '看', '完', '整整', '一', '本書', '的', '感覺', ',', '沒有', '跑', '完', '操場', '一圈', ',', '沒有', '聽', '完一', '整首歌', ',', '也', '沒有', '睡滿', '整整', '一夜', '。', '總', '感覺', '還是', '缺', '一點', '什麼', '。', '但', '我', '有', '很', '走心', '的', '去', '想', '了', ',', '可能', '是因為', '缺', '了', '每', '一個', '可愛', '的', '你', '。', '“', '如果', '是', '去', '見', '你', ',', '我會', '跑', '著', '去', '”', '剛', '看到', '這句', '話', '的', '時候', ',', '我', '也', '很', '贊同', ',', '因為', '畢竟', '去', '見', '一個', '想見', '了', '很', '久', '的', '人', '的', '時候', ',', '怎麼', '也', '按捺不住', '你', '你', '內心', '的', '欣喜', '。', '到', '後來', ',', '當', '你', '真正', '去', '見', 'ta', '的', '時候', ',', '你', '沒有', '跑', ',', '你', '依然', '故作', '鎮定', '的', '樣子', ',', '只是', '你', '會', '比', '平時', '都', '邁', '的', '步子', '大', '一點', ',', '你', '擔心', '你', '跑', '起來', '的', '樣子', '不', '那麼', '美觀', ',', '你', '擔心', '就算', '是', '夏天', '的', '微風', '也', '還是', '會', '把', '你', '輕薄', '的', '劉海', '吹亂', '。', '你', '會', '在意', '每個', '細節', ',', '你', '每次', '都', '希望', '你', '在', 'ta', '面前', '是', '最好', '的', '狀態', '。', '嗨', ',', '如果', '要', '去', '見', '你', '的話', ',', '我', '不', '跑', '著', '去', '了', ',', '我', '只', '想', '以', '我', '最好', '的', '狀態', '去', '見', '你', '你', '像是', '我', '被子', '裡', '的', '舒服', '你', '像是', '我', '右手', '背上', '的', '那顆', '痣', '你', '像是', '我', '眼角', '微微', '泛出來', '的', '光', '你', '像是', '我', '全身', '每一寸', '肌膚', '在', '呼吸', '你', '像是', '我', '枕頭', '裡', '的', '枕芯', '棉', '你', '像是', '我', '買', '過', '最好', '看書', '裡', '的', '一頁', '你', '像是', '我', '踩', '著', '雲', '就', '可以', '飛', '上天', '你', '像是', '我', '走過', '的', '所有', '路途', '最想', '停留', '的', '瞬間', '你', '是', '我', '在', '夜晚', '閉上眼', '最後', '想到', '的', '人', '你', '是', '我', '在', '清晨', '睜開眼', '最先', '念起', '的', '人', '你', '是', '我', '的', '一日三餐', '你', '是', '我', '的', '一年四季', '來不及', '了', '不想', '再', '浪費時間', '昨天', ',', '今天', ',', '明天', '我', '還是', '最', '喜歡', '你', '總有', '一個', '人', '的', '出現', ',', '讓', '我', '像', '流沙', ',', '像', '落雪', '。', '那些', '別人', '在', '上面', '劃', '了', '又', '劃', '的', '痕跡', ',', '你', '輕輕', '一抹', ',', '就平', '了', '。', '攢', '了', '一', '被子', '的', '情話', ',', '以後', '慢慢', '數給', '你', '聽', '。', '希望', '認識', '更', '多', '可愛', '的', '人', ',', '一起', '做', '喜歡', '的', '事', ',', '寫', '最', '純真', '的', '字', ',', '講', '有趣', '的', '故事', '。', '我', '是', '禮雪晶', ',', '那麼', '你', '呢', '?', '作者', ':', '禮雪晶', '。', '“', '真', '羨慕', '你們', '這麼', '年輕', '就', '遇到', '了', '這麼', '才華橫溢', '的', '我', '。', '”', '一個', '整天', '與', '數字', '對抗', '卻', '藏', '了', '一', '被子', '情話', '的', '95', '後', '女生', '。', '願', '你', '的', '深情', '不', '被', '辜負', ',', '你', '喜歡', '的', '人', '也', '喜歡', '你', '。']

    被子
    情話
    想要
    最近
    有種
    雜碎
    感覺
    ...
    如果
    比喻
    修辭
    來說
    的話
    就是
    已經
    很久
    沒有

segment = []
for line in content:
    try:
        segs = jieba.lcut(line)
        for seg in segs:
            if len(seg)>1 and seg != '\r\n':
                segment.append(seg)
    except:
        print(line)
        continue複製程式碼

載入停用詞

words_df = pd.DataFrame({"segment": segment})
stopwords_df = pd.read_csv('Stopwords/Chinese_Stopwords.txt',index_col=False, quoting=3,sep="\t",names=['stopwords'], encoding='utf-8') #quoting=3全不引用
stopwords_df.head()

複製程式碼

去掉停用詞

words_df = words_df[~words_df.segment.isin(stopwords_df.stopwords)]
words_df.head()

複製程式碼

統計詞頻

words_stat = words_df.groupby(by=['segment'])['segment'].agg({"計數": np.size})
words_stat = words_stat.reset_index().sort_values(by=["計數"], ascending=False)
words_stat.head(30)

words_stat.to_csv("JianShuJiaoYou-Words_Segments.csv", encoding='utf-8')

複製程式碼

文章內容詞雲

醜版

wordcloud = WordCloud(font_path='simhei.ttf', background_color='white',max_font_size=80)
word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
wordcloud = wordcloud.fit_words(word_frequence)
plt.imshow(wordcloud);
# plt.imsave(path)

複製程式碼

亂燉“簡書交友”資料之程式碼(1)

自定義背景圖 1.0版

簡書交友專題 Logo
亂燉“簡書交友”資料之程式碼(1)

from scipy.misc import imread
matplotlib.rcParams['figure.figsize'] = (8.0, 8.0)
from wordcloud import WordCloud,ImageColorGenerator
bimg=imread('Logo-1.jpg')
wordcloud=WordCloud(background_color="white",mask=bimg,font_path='simhei.ttf',max_font_size=200)
word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
wordcloud=wordcloud.fit_words(word_frequence)
bimgColors=ImageColorGenerator(bimg)
plt.axis("off")
plt.imshow(wordcloud.recolor(color_func=bimgColors));

複製程式碼

亂燉“簡書交友”資料之程式碼(1)

自定義背景圖 2.0版

中古民謠樂團Bloody Woods
亂燉“簡書交友”資料之程式碼(1)

from scipy.misc import imread
matplotlib.rcParams['figure.figsize'] = (8.0, 8.0)
from wordcloud import WordCloud,ImageColorGenerator
bimg=imread('中古民謠樂團Bloody Woods.jpg')
wordcloud=WordCloud(background_color="white",mask=bimg,font_path='simhei.ttf',max_font_size=200)
word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
wordcloud=wordcloud.fit_words(word_frequence)
bimgColors=ImageColorGenerator(bimg)
plt.axis("off")
plt.imshow(wordcloud.recolor(color_func=bimgColors));

複製程式碼

亂燉“簡書交友”資料之程式碼(1)

還是太醜

線上詞雲生成網站:HTML5 Word Cloud

亂燉“簡書交友”資料之程式碼(1)


亂燉“簡書交友”資料之程式碼(1)

標題詞頻、詞雲

title = df12.Title.values.tolist()
print(len(title), '\n', title[-1])
segment = []
for line in title:
    try:
        segs = jieba.lcut(line)
        for seg in segs:
            if len(seg)>1 and seg != '\r\n':
                segment.append(seg)
    except:
        print(line)
        continue

# 2718 
# 攢了一被子的情話,想說給你聽

titles_df = pd.DataFrame({"segment": segment})
titles_df = titles_df[~titles_df.segment.isin(stopwords_df.stopwords)]
titles_df.head()

titles_stat = titles_df.groupby(by=['segment'])['segment'].agg({"計數": np.size})
titles_stat = titles_stat.reset_index().sort_values(by=["計數"], ascending=False)
titles_stat.head(30)

wordcloud = WordCloud(font_path='simhei.ttf', background_color='white',max_font_size=80)
word_frequence = {x[0]:x[1] for x in titles_stat.head(1000).values}
wordcloud = wordcloud.fit_words(word_frequence)
plt.imshow(wordcloud);複製程式碼

亂燉“簡書交友”資料之程式碼(1)

自定義背景圖:Bloody Woods

from scipy.misc import imread
matplotlib.rcParams['figure.figsize'] = (8.0, 8.0)
from wordcloud import WordCloud,ImageColorGenerator
bimg=imread('中古民謠樂團Bloody Woods.jpg')
wordcloud=WordCloud(background_color="white",mask=bimg,font_path='simhei.ttf',max_font_size=200)
word_frequence = {x[0]:x[1] for x in titles_stat.head(1000).values}
wordcloud=wordcloud.fit_words(word_frequence)
bimgColors=ImageColorGenerator(bimg)
plt.axis("off")
plt.imshow(wordcloud.recolor(color_func=bimgColors));複製程式碼

亂燉“簡書交友”資料之程式碼(1)

線上詞雲生成網站:HTML5 Word Cloud


亂燉“簡書交友”資料之程式碼(1)

簡書“今日看點”專題熱門文章標題詞雲

亂燉“簡書交友”資料之程式碼(1)

亂燉“簡書交友”資料之程式碼(1)

程式碼:GitHub - DesertsX / JianShuJiaoYou,後續更新LDA主題模型、word2vec詞向量、文章照片爬取、人臉識別及顏值打分和照片牆等,敬請期待,歡迎star與指正。
PS:預告下,即將開啟“Kaggle Kernel 學習系列”,GitHub - DesertsX / Kaggle-Kernel-Learning,歡迎star。


相關文章