【Pyecharts】20W條淘寶文胸商品評論數(shù)據(jù)可視化~

咳咳~不要懷疑,這是一個正經(jīng)的可視化項目碉哑,而且附帶一點科普??


數(shù)據(jù)來源

  • 數(shù)據(jù)來自爬蟲獲取,淘寶約50個文胸商品的20W條評論數(shù)據(jù)~

  • 數(shù)據(jù)源來自chenjiandongx/cup-size


前言

對于很多只知道A/B/C的紳士們共屈,我們在看數(shù)據(jù)之前可能先得了解點知識~

首先我們得先了解兩個概念——上胸圍 & 下胸圍柬采,具體看示意圖:

通過上胸圍與下胸圍的差值,我們就可以確定罩杯的大小了搏予,具體的對應(yīng)關(guān)系可參考下圖:

有了下胸圍 & 罩杯就能確定文胸對應(yīng)的尺碼了~
當(dāng)然這又有分為英式尺碼和國際尺碼熊锭,具體參考下圖:

好了,接下倆就可以開始我們的可視化了~


依賴模塊

from pyecharts.charts import *
from pyecharts import options as opts
from pyecharts.commons.utils import JsCode
from collections import Counter
import re
import pandas as pd
import jieba
import jieba.posseg as psg
from stylecloud import gen_stylecloud
from IPython.display import Image

數(shù)據(jù)處理

原始數(shù)據(jù)是txt格式雪侥,為了方便處理碗殷,這邊轉(zhuǎn)為Dataframe~

尺碼部分通過正則表達式提取出對應(yīng)的下胸圍和罩杯,具體代碼如下:

patterns = re.compile(r'(?P<datetime>.*),顏色分類:(?P<color>.*?);尺碼:(?P<size>.*?),(?P<comment>.*)')

with open('/home/kesci/input/cup6439/cup_all.txt', 'r') as f:
    data = f.readlines()

obj_list = []
for item in data:
    obj = patterns.search(item)
    obj_list.append(obj.groupdict())
    
data = pd.DataFrame(obj_list)
data = pd.concat([data, data['size'].str.extract('(?P<circumference>[7-9]{1}[0|5]{1}).*(?P<cup>[a-zA-Z])', 
                                          expand=True)], axis=1)
data.head()

商品類別

我們通過jieba分詞來看看商品分類中最常出現(xiàn)的是哪些關(guān)鍵詞~

  • 代碼:
w_all = []
for item in data.color:
    w_l = psg.cut(item)
    w_l = [w for w, f in w_l if f in ('n', 'nr') and len(w)>1]
    w_all.extend(w_l)

c = Counter(w_all)

counter = c.most_common(50)

bar = (Bar(init_opts=opts.InitOpts(theme='purple-passion', width='1000px', height='800px'))
       .add_xaxis([x for x, y in counter[::-1]])
       .add_yaxis('出現(xiàn)次數(shù)', [y for x, y in counter[::-1]], category_gap='30%')
       .set_global_opts(title_opts=opts.TitleOpts(title="出現(xiàn)最多的關(guān)鍵詞",
                                                  pos_left="center",
                                                  title_textstyle_opts=opts.TextStyleOpts(font_size=20)),
                        datazoom_opts=opts.DataZoomOpts(range_start=70, range_end=100, orient='vertical'),
                        visualmap_opts=opts.VisualMapOpts(is_show=False, max_=6e4, min_=3000, dimension=0,
                                range_color=['#f5d69f', '#f5898b', '#ef5055']),
                        legend_opts=opts.LegendOpts(is_show=False),
                        xaxis_opts=opts.AxisOpts(is_show=False,),
                        yaxis_opts=opts.AxisOpts(axistick_opts=opts.AxisTickOpts(is_show=False),
                                                 axisline_opts=opts.AxisLineOpts(is_show=False)))
       .set_series_opts(label_opts=opts.LabelOpts(is_show=True,
                                                  position='right',
                                                  font_style='italic'),
                        itemstyle_opts={"normal": {
                                                    "barBorderRadius": [30, 30, 30, 30],
                                                    'shadowBlur': 10,
                                                    'shadowColor': 'rgba(120, 36, 50, 0.5)',
                                                    'shadowOffsetY': 5,
                                                }
                                       }
).reversal_axis())

bar.render_notebook()

  • 顏色:膚色 > 黑色 > 粉色 > 白色速缨;
  • 薄款 > 厚款锌妻;
  • 鋼圈似乎是個比較重要的賣點;

尺碼分布

  • 代碼:
t_data = data.groupby(['circumference', 'cup'])['datetime'].count().reset_index()
t_data.columns = ['circumference', 'cup', 'num']
#t_data.num = round(t_data.num.div(t_data.num.sum(axis=0), axis=0) * 100, 1)

data_pair = [
            {"name": 'A',
              "label":{"show": True},
              "children": []},
            {"name": 'B',
              "label":{"show": True},
              "children": []},
            {"name": 'C',
              "label":{"show": True},
              'shadowBlur': 10,
              'shadowColor': 'rgba(120, 36, 50, 0.5)',
              'shadowOffsetY': 5,
              "children": []},
            {"name": 'D',
              "label":{"show": False},
              "children": []},
            {"name": 'E',
              "label":{"show": False},
              "children": []}
    ]

for idx, row in t_data.iterrows():
    t_dict = {"name": row.cup,
              "label":{"show": True},
              "children": []}
    if row.num > 3000:
        child_data = {"name": '{}-{}'.format(row.circumference, row.cup), "value":row.num, "label":{"show": True}}
    else:
        child_data = {"name": '{}-{}'.format(row.circumference, row.cup), "value":row.num, "label":{"show": False}}
    if row.cup == "A":
        data_pair[0]['children'].append(child_data)   
    elif row.cup == "B":
        data_pair[1]['children'].append(child_data)   
    elif row.cup == "C":
        data_pair[2]['children'].append(child_data)  
    elif row.cup == "D":
        data_pair[3]['children'].append(child_data)  
    elif row.cup == "E":
        data_pair[4]['children'].append(child_data)  


c = (Sunburst(
        init_opts=opts.InitOpts(
            theme='purple-passion',
            width="1000px",
            height="1000px"))
    .add(
        "",
        data_pair=data_pair,
        highlight_policy="ancestor",
        radius=[0, "100%"],
        sort_='null',
        levels=[
            {},
            {
                "r0": "20%",
                "r": "48%",
                "itemStyle": {"borderColor": 'rgb(220,220,220)', "borderWidth": 2}
            },
            {"r0": "50%", "r": "80%", "label": {"align": "right"},
                "itemStyle": {"borderColor": 'rgb(220,220,220)', "borderWidth": 1}}
        ],
    )
    .set_global_opts(
        visualmap_opts=opts.VisualMapOpts(is_show=False, max_=90000, min_=3000, 
                                range_color=['#f5d69f', '#f5898b', '#ef5055']),
        title_opts=opts.TitleOpts(title="文 胸\n\n尺 碼 分 布",
                                               pos_left="center",
                                               pos_top="center",
                                               title_textstyle_opts=opts.TextStyleOpts(font_style='oblique', font_size=30),))
    .set_series_opts(label_opts=opts.LabelOpts(font_size=18, formatter="旬牲: {c}"))
)

c.render_notebook()

  • 單看罩杯的話:B > A > C
  • 細分到具體尺碼:75B > 80B > 75A > 70A

罩杯分布

我們通過不同的胸圍來看看罩杯的比例:

  • 代碼:
grid = Grid(init_opts=opts.InitOpts(theme='purple-passion', width='1000px', height='1000px'))


for idx, c in enumerate(['70', '75', '80', '85', '90', '95']):
    
    if idx % 2 == 0:
        x = 30
        y = int(idx/2) * 30 + 20
    else:
        x = 70
        y = int(idx/2) * 30 + 20

    pos_x = str(x)+'%'
    pos_y = str(y)+'%'
    
    pie = Pie(init_opts=opts.InitOpts())
    
    pie.add(
            c,
            [[row.cup, row.num]for i, row in t_data[t_data.circumference==c].iterrows()],
            center=[pos_x, pos_y],
            radius=[70, 100],
            label_opts=opts.LabelOpts(formatter='仿粹:48ag4q6%'),
    )
    
    pie.set_global_opts(
        title_opts=opts.TitleOpts(title="下胸圍={}".format(c),
                                  pos_top=str(y-1)+'%', pos_left=str(x-4)+'%',
                                  title_textstyle_opts=opts.TextStyleOpts(font_size=15)),
        legend_opts=opts.LegendOpts(is_show=True))
    grid.add(pie,grid_opts=opts.GridOpts(pos_left='20%'))

grid.render_notebook()

  • 下胸圍=70:A > B > C
  • 下胸圍=75:B > A > C
  • 下胸圍=80:B > A > C
  • 下胸圍=85:B > C > A
  • 下胸圍=90:C > B > A
  • 下胸圍=95:C > B > D

評論詞云

最后我們來看看評論中經(jīng)常說到的是什么詞語吧~

  • 代碼:
w_all = []
for item in data.comment:
    w_l = jieba.lcut(item)
    w_all.extend(w_l)

c = Counter(w_all)


gen_stylecloud(' '.join(w_all),
              size=1000,
              #max_words=1000,
              font_path='/home/kesci/work/font/simhei.ttf',
              #palette='palettable.tableau.TableauMedium_10',
              icon_name='fas fa-heartbeat',
              output_name='comment.png',
              custom_stopwords=['沒有','用戶','填寫','評論']
              )

Image(filename='comment.png')

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末原茅,一起剝皮案震驚了整個濱河市吭历,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌擂橘,老刑警劉巖晌区,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異通贞,居然都是意外死亡朗若,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門滑频,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人唤冈,你說我怎么就攤上這事峡迷。” “怎么了你虹?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵绘搞,是天一觀的道長。 經(jīng)常有香客問我傅物,道長夯辖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任董饰,我火速辦了婚禮蒿褂,結(jié)果婚禮上圆米,老公的妹妹穿的比我還像新娘。我一直安慰自己啄栓,他們只是感情好娄帖,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著昙楚,像睡著了一般近速。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上堪旧,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天削葱,我揣著相機與錄音,去河邊找鬼淳梦。 笑死析砸,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谭跨。 我是一名探鬼主播干厚,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼螃宙!你這毒婦竟也來了蛮瞄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤谆扎,失蹤者是張志新(化名)和其女友劉穎挂捅,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體堂湖,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡闲先,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了无蜂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伺糠。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖斥季,靈堂內(nèi)的尸體忽然破棺而出训桶,到底是詐尸還是另有隱情,我是刑警寧澤酣倾,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布舵揭,位于F島的核電站,受9級特大地震影響躁锡,放射性物質(zhì)發(fā)生泄漏午绳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一映之、第九天 我趴在偏房一處隱蔽的房頂上張望拦焚。 院中可真熱鬧蜡坊,春花似錦、人聲如沸耕漱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽螟够。三九已至灾梦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間妓笙,已是汗流浹背若河。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留寞宫,地道東北人萧福。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像辈赋,于是被迫代替她去往敵國和親鲫忍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容