Habrastatistics: εξερεύνηση των περισσότερων και λιγότερο επισκέψιμων ενοτήτων του ιστότοπου

Γεια σου Χαμπρ.

В προηγούμενο μέρος Η επισκεψιμότητα του Habr αναλύθηκε σύμφωνα με τις κύριες παραμέτρους - τον αριθμό των άρθρων, τις απόψεις και τις αξιολογήσεις τους. Ωστόσο, το θέμα της δημοτικότητας των ενοτήτων του ιστότοπου παρέμεινε ανεξέταστο. Έγινε ενδιαφέρον να το δούμε αυτό με περισσότερες λεπτομέρειες και να βρούμε τους πιο δημοφιλείς και πιο μη δημοφιλείς κόμβους. Τέλος, θα εξετάσω το εφέ geektimes με περισσότερες λεπτομέρειες, τελειώνοντας με μια νέα επιλογή των καλύτερων άρθρων με βάση τις νέες κατατάξεις.

Habrastatistics: εξερεύνηση των περισσότερων και λιγότερο επισκέψιμων ενοτήτων του ιστότοπου

Για όσους ενδιαφέρονται για το τι έγινε, η συνέχεια είναι κάτω από το κόψιμο.

Να σας υπενθυμίσω για άλλη μια φορά ότι τα στατιστικά και οι βαθμολογίες δεν είναι επίσημα, δεν έχω καμία πληροφορία εκ των έσω. Επίσης δεν είναι εγγυημένο ότι δεν έκανα κάπου λάθος ή έχασα κάτι. Αλλά και πάλι, νομίζω ότι βγήκε ενδιαφέρον. Θα ξεκινήσουμε πρώτα με τον κωδικό όσοι δεν ενδιαφέρονται για αυτό μπορούν να παραλείψουν τις πρώτες ενότητες.

Συλλογή δεδομένων

Στην πρώτη έκδοση του αναλυτή, ελήφθησαν υπόψη μόνο ο αριθμός των προβολών, των σχολίων και των αξιολογήσεων των άρθρων. Αυτό είναι ήδη καλό, αλλά δεν σας επιτρέπει να κάνετε πιο σύνθετα ερωτήματα. Ήρθε η ώρα να αναλύσετε τις θεματικές ενότητες του ιστότοπου, αυτό θα σας επιτρέψει να κάνετε αρκετά ενδιαφέρουσα έρευνα, για παράδειγμα, να δείτε πώς έχει αλλάξει η δημοτικότητα της ενότητας "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:

Habrastatistics: εξερεύνηση των περισσότερων και λιγότερο επισκέψιμων ενοτήτων του ιστότοπου

Χώρισα τα άρθρα "geektimes" και "geektimes only" στο γράφημα, επειδή Ένα άρθρο μπορεί να ανήκει και στις δύο ενότητες ταυτόχρονα (για παράδειγμα, "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. Όμως, ενώ ο συνολικός αριθμός των προβολών κυμάνθηκε αισθητά, η προβολή των άρθρων «ψυχαγωγίας» παρέμεινε περίπου στο ίδιο επίπεδο.

Habrastatistics: εξερεύνηση των περισσότερων και λιγότερο επισκέψιμων ενοτήτων του ιστότοπου

Μπορείτε επίσης να παρατηρήσετε ότι ο συνολικός αριθμός των προβολών των άρθρων στην ενότητα "geektimes" εξακολουθεί να μειώνεται μετά την αλλαγή των κανόνων, αλλά "με το μάτι", όχι περισσότερο από το 5% των συνολικών τιμών.

Είναι ενδιαφέρον να δούμε τον μέσο αριθμό προβολών ανά άρθρο:

Habrastatistics: εξερεύνηση των περισσότερων και λιγότερο επισκέψιμων ενοτήτων του ιστότοπου

Για άρθρα «ψυχαγωγίας» είναι περίπου 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()

Το αποτέλεσμα:

Habrastatistics: εξερεύνηση των περισσότερων και λιγότερο επισκέψιμων ενοτήτων του ιστότοπου

Παραδόξως, ο πιο δημοφιλής κόμβος από άποψη προβολών ήταν η «Ασφάλεια Πληροφοριών» στους 5 κορυφαίους ηγέτες περιλάμβαναν επίσης τον «Προγραμματισμό» και τη «Λαϊκή επιστήμη».

Το Antitop καταλαμβάνει το Gtk και το Κακάο.

Habrastatistics: εξερεύνηση των περισσότερων και λιγότερο επισκέψιμων ενοτήτων του ιστότοπου

Θα σου πω ένα μυστικό, φαίνονται και οι κορυφαίοι κόμβοι εδώ, αν και ο αριθμός των προβολών δεν εμφανίζεται εκεί.

Εκτίμηση

Και τέλος, η υποσχεμένη βαθμολογία. Χρησιμοποιώντας δεδομένα ανάλυσης κόμβων, μπορούμε να εμφανίσουμε τα πιο δημοφιλή άρθρα για τους πιο δημοφιλείς κόμβους για φέτος το 2019.

Ασφάλεια Πληροφοριών

Προγραμματισμός

Λαϊκή Επιστήμη

Карьера

Νομοθεσία στην Πληροφορική

Ανάπτυξη διαδικτύου

GTK

Και τέλος, για να μην προσβληθεί κανείς, θα δώσω τη βαθμολογία του λιγότερο επισκέψιμου κόμβου "gtk". Μέσα σε ένα χρόνο δημοσιεύτηκε одна Το άρθρο, το οποίο επίσης «αυτόματα» καταλαμβάνει την πρώτη γραμμή της βαθμολογίας.

Συμπέρασμα

Δεν θα υπάρξει συμπέρασμα. Καλή ανάγνωση σε όλους.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο