Habrastatistics: eksplorimi i seksioneve më dhe më pak të vizituara të faqes

Hej Habr.

В pjesa e mëparshme Trafiku i Habr u analizua sipas parametrave kryesorë - numri i artikujve, pikëpamjet dhe vlerësimet e tyre. Sidoqoftë, çështja e popullaritetit të seksioneve të faqes mbeti e pashqyrtuar. U bë interesante ta shikojmë këtë në më shumë detaje dhe të gjejmë qendrat më të njohura dhe më të papëlqyeshme. Së fundi, do të shikoj më në detaje efektin geektimes, duke përfunduar me një përzgjedhje të re të artikujve më të mirë bazuar në renditjet e reja.

Habrastatistics: eksplorimi i seksioneve më dhe më pak të vizituara të faqes

Për ata që janë të interesuar për atë që ka ndodhur, vazhdimi është nën prerje.

Më lejoni t'ju kujtoj edhe një herë se statistikat dhe vlerësimet nuk janë zyrtare, nuk kam asnjë informacion të brendshëm. Gjithashtu nuk është e garantuar që nuk kam gabuar diku ose kam humbur diçka. Por megjithatë, unë mendoj se doli interesante. Fillimisht do të fillojmë me kodin; ata që nuk janë të interesuar për këtë mund të kalojnë seksionet e para.

Mbledhja e të dhënave

Në versionin e parë të analizuesit, u morën parasysh vetëm numri i shikimeve, komenteve dhe vlerësimeve të artikujve. Kjo tashmë është e mirë, por nuk ju lejon të bëni pyetje më komplekse. Është koha për të analizuar seksionet tematike të faqes; kjo do t'ju lejojë të bëni kërkime mjaft interesante, për shembull, të shihni se si ka ndryshuar popullariteti i seksionit "C++" gjatë disa viteve.

Analisti i artikujve është përmirësuar, tani ai kthen qendrat të cilave i përket artikulli, si dhe pseudonimin e autorit dhe vlerësimin e tij (shumë gjëra interesante mund të bëhen edhe këtu, por kjo do të vijë më vonë). Të dhënat ruhen në një skedar csv që duket diçka si kjo:

2018-12-18T12:43Z,https://habr.com/ru/post/433550/,"Мессенджер Slack — причины выбора, косяки при внедрении и особенности сервиса, облегчающие жизнь",votes:7,votesplus:8,votesmin:1,bookmarks:32,
views:8300,comments:10,user:ReDisque,karma:5,subscribers:2,hubs:productpm+soft
...

Do të marrim një listë të qendrave kryesore tematike të faqes.

def get_as_str(link: str) -> Str:
    try:
        r = requests.get(link)
        return Str(r.text)
    except Exception as e:
        return Str("")

def get_hubs():
    hubs = []
    for p in range(1, 12):
        page_html = get_as_str("https://habr.com/ru/hubs/page%d/" % p)
        # page_html = get_as_str("https://habr.com/ru/hubs/geektimes/page%d/" % p)  # Geektimes
        # page_html = get_as_str("https://habr.com/ru/hubs/develop/page%d/" % p)  # Develop
        # page_html = get_as_str("https://habr.com/ru/hubs/admin/page%d" % p)  # Admin
        for hub in page_html.split("media-obj media-obj_hub"):
            info = Str(hub).find_between('"https://habr.com/ru/hub', 'list-snippet__tags') 
            if "*</span>" in info:
                hub_name = info.find_between('/', '/"')
                if len(hub_name) > 0 and len(hub_name) < 32:
                    hubs.append(hub_name)
    print(hubs)

Funksioni find_between dhe klasa Str zgjedhin një varg midis dy etiketave, unë i përdora ato më herët. Qendrat tematike janë shënuar me një "*" në mënyrë që ato të mund të theksohen lehtësisht, dhe gjithashtu mund të hiqni komentet e rreshtave përkatës për të marrë seksione të kategorive të tjera.

Prodhimi i funksionit get_hubs është një listë mjaft mbresëlënëse, të cilën e ruajmë si fjalor. Unë po e prezantoj në mënyrë specifike listën në tërësi në mënyrë që të vlerësoni vëllimin e saj.

hubs_profile = {'infosecurity', 'programming', 'webdev', 'python', 'sys_admin', 'it-infrastructure', 'devops', 'javascript', 'open_source', 'network_technologies', 'gamedev', 'cpp', 'machine_learning', 'pm', 'hr_management', 'linux', 'analysis_design', 'ui', 'net', 'hi', 'maths', 'mobile_dev', 'productpm', 'win_dev', 'it_testing', 'dev_management', 'algorithms', 'go', 'php', 'csharp', 'nix', 'data_visualization', 'web_testing', 's_admin', 'crazydev', 'data_mining', 'bigdata', 'c', 'java', 'usability', 'instant_messaging', 'gtd', 'system_programming', 'ios_dev', 'oop', 'nginx', 'kubernetes', 'sql', '3d_graphics', 'css', 'geo', 'image_processing', 'controllers', 'game_design', 'html5', 'community_management', 'electronics', 'android_dev', 'crypto', 'netdev', 'cisconetworks', 'db_admins', 'funcprog', 'wireless', 'dwh', 'linux_dev', 'assembler', 'reactjs', 'sales', 'microservices', 'search_technologies', 'compilers', 'virtualization', 'client_side_optimization', 'distributed_systems', 'api', 'media_management', 'complete_code', 'typescript', 'postgresql', 'rust', 'agile', 'refactoring', 'parallel_programming', 'mssql', 'game_promotion', 'robo_dev', 'reverse-engineering', 'web_analytics', 'unity', 'symfony', 'build_automation', 'swift', 'raspberrypi', 'web_design', 'kotlin', 'debug', 'pay_system', 'apps_design', 'git', 'shells', 'laravel', 'mobile_testing', 'openstreetmap', 'lua', 'vs', 'yii', 'sport_programming', 'service_desk', 'itstandarts', 'nodejs', 'data_warehouse', 'ctf', 'erp', 'video', 'mobileanalytics', 'ipv6', 'virus', 'crm', 'backup', 'mesh_networking', 'cad_cam', 'patents', 'cloud_computing', 'growthhacking', 'iot_dev', 'server_side_optimization', 'latex', 'natural_language_processing', 'scala', 'unreal_engine', 'mongodb', 'delphi',  'industrial_control_system', 'r', 'fpga', 'oracle', 'arduino', 'magento', 'ruby', 'nosql', 'flutter', 'xml', 'apache', 'sveltejs', 'devmail', 'ecommerce_development', 'opendata', 'Hadoop', 'yandex_api', 'game_monetization', 'ror', 'graph_design', 'scada', 'mobile_monetization', 'sqlite', 'accessibility', 'saas', 'helpdesk', 'matlab', 'julia', 'aws', 'data_recovery', 'erlang', 'angular', 'osx_dev', 'dns', 'dart', 'vector_graphics', 'asp', 'domains', 'cvs', 'asterisk', 'iis', 'it_monetization', 'localization', 'objectivec', 'IPFS', 'jquery', 'lisp', 'arvrdev', 'powershell', 'd', 'conversion', 'animation', 'webgl', 'wordpress', 'elm', 'qt_software', 'google_api', 'groovy_grails', 'Sailfish_dev', 'Atlassian', 'desktop_environment', 'game_testing', 'mysql', 'ecm', 'cms', 'Xamarin', 'haskell', 'prototyping', 'sw', 'django', 'gradle', 'billing', 'tdd', 'openshift', 'canvas', 'map_api', 'vuejs', 'data_compression', 'tizen_dev', 'iptv', 'mono', 'labview', 'perl', 'AJAX', 'ms_access', 'gpgpu', 'infolust', 'microformats', 'facebook_api', 'vba', 'twitter_api', 'twisted', 'phalcon', 'joomla', 'action_script', 'flex', 'gtk', 'meteorjs', 'iconoskaz', 'cobol', 'cocoa', 'fortran', 'uml', 'codeigniter', 'prolog', 'mercurial', 'drupal', 'wp_dev', 'smallbasic', 'webassembly', 'cubrid', 'fido', 'bada_dev', 'cgi', 'extjs', 'zend_framework', 'typography', 'UEFI', 'geo_systems', 'vim', 'creative_commons', 'modx', 'derbyjs', 'xcode', 'greasemonkey', 'i2p', 'flash_platform', 'coffeescript', 'fsharp', 'clojure', 'puppet', 'forth', 'processing_lang', 'firebird', 'javame_dev', 'cakephp', 'google_cloud_vision_api', 'kohanaphp', 'elixirphoenix', 'eclipse', 'xslt', 'smalltalk', 'googlecloud', 'gae', 'mootools', 'emacs', 'flask', 'gwt', 'web_monetization', 'circuit-design', 'office365dev', 'haxe', 'doctrine', 'typo3', 'regex', 'solidity', 'brainfuck', 'sphinx', 'san', 'vk_api', 'ecommerce'}

Për krahasim, seksionet e geektimes duken më modeste:

hubs_gt = {'popular_science', 'history', 'soft', 'lifehacks', 'health', 'finance', 'artificial_intelligence', 'itcompanies', 'DIY', 'energy', 'transport', 'gadgets', 'social_networks', 'space', 'futurenow', 'it_bigraphy', 'antikvariat', 'games', 'hardware', 'learning_languages', 'urban', 'brain', 'internet_of_things', 'easyelectronics', 'cellular', 'physics', 'cryptocurrency', 'interviews', 'biotech', 'network_hardware', 'autogadgets', 'lasers', 'sound', 'home_automation', 'smartphones', 'statistics', 'robot', 'cpu', 'video_tech', 'Ecology', 'presentation', 'desktops', 'wearable_electronics', 'quantum', 'notebooks', 'cyberpunk', 'Peripheral', 'demoscene', 'copyright', 'astronomy', 'arvr', 'medgadgets', '3d-printers', 'Chemistry', 'storages', 'sci-fi', 'logic_games', 'office', 'tablets', 'displays', 'video_conferencing', 'videocards', 'photo', 'multicopters', 'supercomputers', 'telemedicine', 'cybersport', 'nano', 'crowdsourcing', 'infographics'}

Qendrat e mbetura u ruajtën në të njëjtën mënyrë. Tani është e lehtë të shkruash një funksion që kthen rezultatin nëse artikulli i përket geektimes ose një qendre profili.

def is_geektimes(hubs: List) -> bool:
    return len(set(hubs) & hubs_gt) > 0

def is_geektimes_only(hubs: List) -> bool:
    return is_geektimes(hubs) is True and is_profile(hubs) is False

def is_profile(hubs: List) -> bool:
    return len(set(hubs) & hubs_profile) > 0

Funksione të ngjashme u bënë për seksione të tjera ("zhvillimi", "administrimi", etj.).

Përpunim

Është koha për të filluar analizimin. Ne ngarkojmë grupin e të dhënave dhe përpunojmë të dhënat e qendrës.

def to_list(s: str) -> List[str]:
    # "user:popular_science+astronomy" => [popular_science, astronomy]
    return s.split(':')[1].split('+')

def to_date(dt: datetime) -> datetime.date:
    return dt.date()

df = pd.read_csv("habr_2019.csv", sep=',', encoding='utf-8', error_bad_lines=True, quotechar='"', comment='#')
dates = pd.to_datetime(df['datetime'], format='%Y-%m-%dT%H:%MZ')
dates += datetime.timedelta(hours=3)
df['date'] = dates.map(to_date, na_action=None)
hubs = df["hubs"].map(to_list, na_action=None)
df['hubs'] = hubs
df['is_profile'] = hubs.map(is_profile, na_action=None)
df['is_geektimes'] = hubs.map(is_geektimes, na_action=None)
df['is_geektimes_only'] = hubs.map(is_geektimes_only, na_action=None)
df['is_admin'] = hubs.map(is_admin, na_action=None)
df['is_develop'] = hubs.map(is_develop, na_action=None)

Tani mund të grupojmë të dhënat sipas ditës dhe të shfaqim numrin e publikimeve për qendra të ndryshme.

g = df.groupby(['date'])
days_count = g.size().reset_index(name='counts')
year_days = days_count['date'].values
grouped = g.sum().reset_index()
profile_per_day_avg = grouped['is_profile'].rolling(window=20, min_periods=1).mean()
geektimes_per_day_avg = grouped['is_geektimes'].rolling(window=20, min_periods=1).mean()
geektimesonly_per_day_avg = grouped['is_geektimes_only'].rolling(window=20, min_periods=1).mean()
admin_per_day_avg = grouped['is_admin'].rolling(window=20, min_periods=1).mean()
develop_per_day_avg = grouped['is_develop'].rolling(window=20, min_periods=1).mean()

Ne shfaqim numrin e artikujve të botuar duke përdorur Matplotlib:

Habrastatistics: eksplorimi i seksioneve më dhe më pak të vizituara të faqes

I ndava artikujt "geektimes" dhe "vetëm geektimes" në grafik, sepse Një artikull mund t'u përkasë të dy seksioneve në të njëjtën kohë (për shembull, "DIY" + "mikrokontrolluesit" + "C++"). Kam përdorur përcaktimin "profil" për të nxjerrë në pah artikujt e profilit në faqe, megjithëse ndoshta termi anglisht profil për këtë nuk është plotësisht i saktë.

Në pjesën e mëparshme, ata pyetën për "efektin geektimes" që lidhet me ndryshimin e rregullave të pagesës për artikujt për geektimes këtë verë. Le të shfaqim artikujt e geektimes veçmas:

df_gt = df[(df['is_geektimes_only'] == True)]
group_gt = df_gt.groupby(['date'])
days_count_gt = group_gt.size().reset_index(name='counts')
grouped = group_gt.sum().reset_index()
year_days_gt = days_count_gt['date'].values
view_gt_per_day_avg = grouped['views'].rolling(window=20, min_periods=1).mean()

Rezultati është interesant. Raporti i përafërt i shikimeve të artikujve të geektimes me totalin është diku rreth 1:5. Por ndërkohë që numri total i shikimeve luhatej dukshëm, shikueshmëria e artikujve “argëtues” mbeti afërsisht në të njëjtin nivel.

Habrastatistics: eksplorimi i seksioneve më dhe më pak të vizituara të faqes

Ju gjithashtu mund të vini re se numri i përgjithshëm i shikimeve të artikujve në seksionin "geektimes" ende ra pas ndryshimit të rregullave, por "me sy", jo më shumë se 5% të vlerave totale.

Është interesante të shikosh numrin mesatar të shikimeve për artikull:

Habrastatistics: eksplorimi i seksioneve më dhe më pak të vizituara të faqes

Për artikujt “argëtues” është rreth 40% mbi mesataren. Kjo ndoshta nuk është për t'u habitur. Dështimi në fillim të prillit është i pakuptueshëm për mua, ndoshta kështu ka ndodhur, ose është një lloj gabimi analize, ose ndoshta një nga autorët e geektimes ka shkuar me pushime ;).

Nga rruga, grafiku tregon dy maja më të dukshme në numrin e shikimeve të artikujve - festat e Vitit të Ri dhe majit.

Qendrat

Le të kalojmë në analizën e premtuar të shpërndarësve. Le të rendisim 20 qendrat kryesore sipas numrit të shikimeve:

hubs_info = []
for hub_name in hubs_all:
    mask = df['hubs'].apply(lambda x: hub_name in x)
    df_hub = df[mask]

    count, views = df_hub.shape[0], df_hub['views'].sum()
    hubs_info.append((hub_name, count, views))

# Draw hubs
hubs_top = sorted(hubs_info, key=lambda v: v[2], reverse=True)[:20]
top_views = list(map(lambda x: x[2], hubs_top))
top_names = list(map(lambda x: x[0], hubs_top))

plt.rcParams["figure.figsize"] = (8, 6)
plt.bar(range(0, len(top_views)), top_views)
plt.xticks(range(0, len(top_names)), top_names, rotation=90)
plt.ticklabel_format(style='plain', axis='y')
plt.tight_layout()
plt.show()

Rezultati:

Habrastatistics: eksplorimi i seksioneve më dhe më pak të vizituara të faqes

Çuditërisht, qendra më e njohur për sa i përket pikëpamjeve ishte "Siguria e Informacionit"; 5 liderët kryesorë përfshinin gjithashtu "Programimin" dhe "Shkencën popullore".

Antitop zë Gtk dhe Kakao.

Habrastatistics: eksplorimi i seksioneve më dhe më pak të vizituara të faqes

Unë do t'ju them një sekret, mund të shihen edhe qendrat kryesore këtu, megjithëse numri i shikimeve nuk tregohet atje.

Vlerësim

Dhe së fundi, vlerësimi i premtuar. Duke përdorur të dhënat e analizës së qendrës, ne mund të shfaqim artikujt më të njohur për qendrat më të njohura për këtë vit 2019.

Siguria e informacionit

Programim

Shkencë popullore

karierë

Legjislacioni në TI

Zhvillimi i uebit

GTK

Dhe së fundi, në mënyrë që askush të mos ofendohet, unë do të jap vlerësimin e qendrës më pak të vizituar "gtk". Brenda një viti u botua një artikulli, i cili gjithashtu “automatikisht” zë rreshtin e parë të vlerësimit.

Përfundim

Nuk do të ketë asnjë përfundim. Gëzuar lexim të gjithëve.

Burimi: www.habr.com

Shto një koment