Габрастистика: сайттың ең көп және ең аз кірген бөлімдерін зерттеу

Эй Хабр.

В алдыңғы бөлім Хабрдың трафигі негізгі параметрлерге - мақалалар санына, олардың көріністеріне және рейтингтеріне сәйкес талданды. Дегенмен, сайт бөлімдерінің танымалдылығы мәселесі зерттелмей қалды. Мұны толығырақ қарастыру және ең танымал және ең танымал емес хабтарды табу қызықты болды. Соңында, мен жаңа рейтингтерге негізделген ең жақсы мақалалардың жаңа таңдауымен аяқталатын geektimes әсерін толығырақ қарастырамын.

Габрастистика: сайттың ең көп және ең аз кірген бөлімдерін зерттеу

Оқиғаға қызығатындар үшін жалғасы қысқартылған.

Тағы бір рет еске сала кетейін, статистика мен рейтингтер ресми емес, менде инсайдерлік ақпарат жоқ. Сондай-ақ бір жерде қателеспегеніме немесе бірдеңені жіберіп алғаныма кепілдік берілмейді. Дегенмен, менің ойымша, бұл қызықты болды. Біз алдымен кодтан бастаймыз, оған қызығушылық танытпайтындар бірінші бөлімдерді өткізіп жібере алады.

Деректер жинау

Талдаушының бірінші нұсқасында тек көру саны, пікірлер және мақала рейтингтері ескерілді. Бұл қазірдің өзінде жақсы, бірақ ол сізге күрделі сұраулар жасауға мүмкіндік бермейді. Сайттың тақырыптық бөлімдерін талдаудың уақыты келді, бұл сізге өте қызықты зерттеулер жүргізуге мүмкіндік береді, мысалы, бірнеше жыл ішінде «C++» бөлімінің танымалдылығы қалай өзгергенін көріңіз.

Мақала талдаушысы жетілдірілді, енді ол мақала тиесілі хабтарды, сонымен қатар автордың лақап аты мен оның рейтингін қайтарады (мұнда да көптеген қызықты нәрселерді жасауға болады, бірақ бұл кейінірек келеді). Деректер csv файлында сақталады, ол келесідей көрінеді:

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

Біз сайттың негізгі тақырыптық хабтарының тізімін аламыз.

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 функциясы мен Str класы екі тег арасындағы жолды таңдайды, мен оларды қолдандым бұрын. Тақырыптық хабтар "*" белгісімен белгіленеді, сондықтан оларды оңай бөлектеуге болады, сонымен қатар басқа санаттардың бөлімдерін алу үшін сәйкес жолдарға түсініктемелерді алып тастауға болады.

get_hubs функциясының нәтижесі - біз сөздік ретінде сақтайтын өте әсерлі тізім. Мен оның көлемін бағалау үшін тізімді толығымен ұсынамын.

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

Салыстыру үшін, geektimes бөлімдері қарапайым көрінеді:

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

Қалған тораптар дәл осылай сақталды. Енді мақаланың geektimes немесе профиль хабына жататынына қарамастан нәтижені қайтаратын функцияны жазу оңай.

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

Осыған ұқсас функциялар басқа бөлімдер үшін де жасалған («әзірлеу», «басқару» және т.б.).

Өңдеу

Талдауды бастау уақыты келді. Деректер жинағын жүктейміз және хаб деректерін өңдейміз.

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)

Енді біз деректерді күн бойынша топтап, әртүрлі хабтар үшін жарияланымдар санын көрсете аламыз.

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

Біз Matplotlib көмегімен жарияланған мақалалардың санын көрсетеміз:

Габрастистика: сайттың ең көп және ең аз кірген бөлімдерін зерттеу

Мен диаграммадағы «geektimes» және «geektimes» мақалаларын бөлдім, өйткені Мақала бір уақытта екі бөлімге де тиесілі болуы мүмкін (мысалы, «DIY» + «микроконтроллерлер» + «C++»). Мен сайттағы профильдік мақалаларды бөлектеу үшін «профиль» белгісін қолдандым, бірақ бұл үшін ағылшын тіліндегі профиль термині мүлдем дұрыс емес.

Алдыңғы бөлімде біз осы жаздан бастап geektimes мақалалары үшін төлем ережелерінің өзгеруіне байланысты «geektimes эффектісі» туралы сұрадық. Geektimes мақалаларын бөлек көрсетейік:

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

Нәтиже қызықты. Geektimes мақалаларын көру санының жалпыға шамамен қатынасы шамамен 1:5 құрайды. Қараулардың жалпы саны айтарлықтай өзгергенімен, «ойын-сауық» мақалаларын қарау шамамен бірдей деңгейде қалды.

Габрастистика: сайттың ең көп және ең аз кірген бөлімдерін зерттеу

Сондай-ақ, «geektimes» бөліміндегі мақалаларды қараудың жалпы саны ережелерді өзгерткеннен кейін де төмендегенін байқай аласыз, бірақ «көзбен» жалпы мәндердің 5% -нан аспайды.

Бір мақаланы көрудің орташа санын қарау қызықты:

Габрастистика: сайттың ең көп және ең аз кірген бөлімдерін зерттеу

«Көңіл көтеру» мақалалары үшін бұл орташадан 40% жоғары. Бұл таңқаларлық емес шығар. Сәуір айының басындағы сәтсіздік маған түсініксіз, мүмкін солай болған шығар, немесе бұл қандай да бір талдау қатесі шығар немесе geektimes авторларының бірі демалысқа кеткен шығар;).

Айтпақшы, графикте мақалалардың қаралу санының тағы екі байқалатын шыңы көрсетілген - Жаңа жыл және мамыр мерекелері.

Хабтар

Уәде етілген хабтарды талдауға көшейік. Көру саны бойынша ең жақсы 20 хабты тізімдейміз:

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

нәтижесі:

Габрастистика: сайттың ең көп және ең аз кірген бөлімдерін зерттеу

Бір қызығы, көзқарастар бойынша ең танымал хаб «Ақпараттық қауіпсіздік» болды, көшбасшылардың бестігіне «Бағдарламалау» және «Танымал ғылым» да кірді.

Антитоп Gtk және Какаоны алады.

Габрастистика: сайттың ең көп және ең аз кірген бөлімдерін зерттеу

Мен сізге бір құпияны айтайын, жоғарғы хабтарды да көруге болады осында, бірақ көру саны онда көрсетілмеген.

рейтинг

Ақырында, уәде етілген рейтинг. Хаб талдау деректерін пайдалана отырып, біз осы 2019 жылғы ең танымал хабтар үшін ең танымал мақалаларды көрсете аламыз.

Ақпараттық қауіпсіздік

Бағдарламалау

Танымал ғылым

Мансап

АТ саласындағы заңнама

Веб әзірлеу

GTK

Ақырында, ешкім ренжітпеуі үшін мен ең аз кіретін «gtk» хабының рейтингін беремін. Бір жылдың ішінде ол жарық көрді одна Рейтингтің бірінші жолын «автоматты түрде» алатын мақала.

қорытынды

Қорытынды болмайды. Барлығына бақытты оқу.

Ақпарат көзі: www.habr.com

пікір қалдыру