Habrastatistics: kanna mest og minnst heimsóttu hluta síðunnar

Hæ Habr.

В fyrri hluta Umferð Habr var greind eftir helstu breytum - fjölda greina, skoðunum þeirra og einkunnum. Hins vegar var spurningin um vinsældir síðuhlutanna órannsökuð. Það varð áhugavert að skoða þetta nánar og finna vinsælustu og óvinsælustu miðstöðina. Að lokum mun ég skoða áhrif geektimes nánar, endar með nýju úrvali af bestu greinunum byggðum á nýjum röðum.

Habrastatistics: kanna mest og minnst heimsóttu hluta síðunnar

Fyrir þá sem hafa áhuga á því sem gerðist er framhaldið í skorðum.

Ég vil enn og aftur minna þig á að tölfræði og einkunnir eru ekki opinberar, ég hef engar innherjaupplýsingar. Það er heldur ekki tryggt að ég hafi ekki gert mistök einhvers staðar eða misst af einhverju. En samt held ég að þetta hafi verið áhugavert. Við byrjum fyrst á kóðanum; þeir sem ekki hafa áhuga á þessu geta sleppt fyrstu hlutunum.

Gagnasafn

Í fyrstu útgáfu greinarans var aðeins tekið tillit til fjölda skoðana, athugasemda og greinaeinkunna. Þetta er nú þegar gott, en það leyfir þér ekki að gera flóknari fyrirspurnir. Það er kominn tími til að greina þemahluta síðunnar; þetta gerir þér kleift að gera nokkuð áhugaverðar rannsóknir, til dæmis, sjá hvernig vinsældir „C++“ hlutans hafa breyst á nokkrum árum.

Greinarþátturinn hefur verið endurbættur, nú skilar hann þeim miðstöðvum sem greinin tilheyrir, svo og gælunafni höfundar og einkunn hans (margt áhugavert er hægt að gera hér líka, en það kemur síðar). Gögnin eru vistuð í csv skrá sem lítur eitthvað svona út:

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
...

Við munum fá lista yfir helstu þemamiðstöðvar síðunnar.

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)

Find_between fallið og Str flokkurinn velja streng á milli tveggja merkja, ég notaði þau áðan. Þemamiðstöðvar eru merktar með „*“ svo auðvelt sé að auðkenna þær, og þú getur líka afskrifað samsvarandi línur til að fá hluta úr öðrum flokkum.

Úttak get_hubs fallsins er nokkuð áhrifamikill listi, sem við vistum sem orðabók. Ég er sérstaklega að kynna listann í heild sinni svo þú getir metið magn hans.

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'}

Til samanburðar líta Geektime kaflarnir út fyrir að vera hófsamari:

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'}

Höfuðstöðvarnar sem eftir voru voru varðveittar á sama hátt. Nú er auðvelt að skrifa fall sem skilar niðurstöðunni hvort sem greinin tilheyrir geektimes eða prófílmiðstöð.

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

Svipaðar aðgerðir voru gerðar fyrir aðra hluta („þróun“, „stjórnsýsla“ osfrv.).

Vinnslu

Það er kominn tími til að byrja að greina. Við hleðum gagnasafninu og vinnum úr miðstöðinni.

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)

Nú getum við flokkað gögnin eftir degi og birt fjölda rita fyrir mismunandi miðstöðvar.

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()

Við birtum fjölda birtra greina með Matplotlib:

Habrastatistics: kanna mest og minnst heimsóttu hluta síðunnar

Ég skipti greinunum „geektimes“ og „geektimes only“ í töfluna, vegna þess að Grein getur tilheyrt báðum hlutum á sama tíma (til dæmis „DIY“ + „örstýringar“ + „C++“). Ég notaði tilnefninguna „prófíl“ til að varpa ljósi á prófílgreinar á síðunni, þó kannski sé enska hugtakið profile fyrir þetta ekki alveg rétt.

Í fyrri hlutanum var spurt um „geektime effect“ sem tengist breytingu á greiðslureglum fyrir greinar fyrir nördatíma sem hefjast í sumar. Sýnum geektimes greinarnar sérstaklega:

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()

Niðurstaðan er áhugaverð. Áætlað hlutfall áhorfa á geektimes greinar af heildarfjölda er einhvers staðar í kringum 1:5. En þó að heildarfjöldi áhorfa hafi sveiflast verulega, hélst áhorf á „skemmtigreinar“ á nokkurn veginn sama stigi.

Habrastatistics: kanna mest og minnst heimsóttu hluta síðunnar

Þú getur líka tekið eftir því að heildarfjöldi áhorfa á greinar í „geektime“ hlutanum féll enn eftir að reglunum var breytt, en „með auga“ um ekki meira en 5% af heildargildunum.

Það er áhugavert að skoða meðalfjölda skoðana á hverja grein:

Habrastatistics: kanna mest og minnst heimsóttu hluta síðunnar

Fyrir „skemmtun“ greinar er það um 40% yfir meðallagi. Þetta kemur líklega ekki á óvart. Bilunin í byrjun apríl er mér óljós, kannski er það það sem gerðist, eða það er einhvers konar þáttunarvilla, eða kannski fór einn af geektime höfundunum í frí ;).

Við the vegur, línuritið sýnir tvo fleiri áberandi toppa í fjölda áhorfa á greinar - áramót og maí frí.

Hubs

Við skulum halda áfram að lofaðri greiningu á miðstöðvum. Við skulum lista 20 efstu miðstöðvarnar eftir fjölda áhorfa:

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()

Niðurstaða:

Habrastatistics: kanna mest og minnst heimsóttu hluta síðunnar

Það kemur á óvart að vinsælasta miðstöðin hvað varðar skoðanir var „upplýsingaöryggi“; efstu 5 leiðtogarnir voru einnig „forritun“ og „vinsæld vísindi“.

Antitop hernema Gtk og Kakó.

Habrastatistics: kanna mest og minnst heimsóttu hluta síðunnar

Ég skal segja þér leyndarmál, efstu miðstöðvarnar má líka sjá hér, þó fjöldi skoðana sé ekki sýndur þar.

Einkunn

Og að lokum, lofað einkunn. Með því að nota gagnagrunnsgreiningargögn getum við birt vinsælustu greinarnar fyrir vinsælustu miðstöðvarnar fyrir þetta ár 2019.

Upplýsingaöryggi

Forritun

Vinsæl vísindi

feril

Löggjöf í upplýsingatækni

vef þróun

GTK

Og að lokum, svo að enginn móðgist, mun ég gefa einkunnina fyrir minnst heimsótta miðstöðina „gtk“. Innan árs kom hún út einn Greinin, sem einnig „sjálfkrafa“ tekur fyrstu línu einkunnarinnar.

Ályktun

Það verður engin niðurstaða. Góða lestur allir.

Heimild: www.habr.com

Bæta við athugasemd