Pull to refresh

Хабрастатистика: как живет Хабр без geektimes

HabrPythonWeb analyticsStatistics in ITSocial networks and communities
Привет, Хабр.

Данная статья является логическим продолжением рейтинга Лучших статей Хабра за 2018 год. И хотя год еще не закончился, но как известно, летом произошли изменения в правилах, соответственно, стало интересно посмотреть, повлияло ли это на что-нибудь.



Кроме собственно статистики, будет приведен и обновленный рейтинг статей, а также немного исходников для тех кому интересно, как это работает.

Для тех, кому интересно что получилось, продолжение под катом. Те, кому интересен более подробный анализ разделов сайта, могут также посмотреть следующую часть.

Исходные данные


Данный рейтинг неофициальный, и никаких инсайдерских данных у меня нет. Как нетрудно видеть, посмотрев в адресную строку браузера, все статьи на Хабре имеют сквозную нумерацию. Дальше дело техники, просто в цикле читаем все статьи подряд (в один поток и с паузами, чтобы не нагружать сервер). Сами значения были получены несложным парсером на Python (исходники есть здесь) и сохранены в csv-файле примерно такого вида:

2019-08-11T22:36Z,https://habr.com/ru/post/463197/,"Blazor + MVVM = Silverlight наносит ответный удар, потому что древнее зло непобедимо",votes:11,votesplus:17,votesmin:6,bookmarks:40,views:5300,comments:73
2019-08-11T05:26Z,https://habr.com/ru/news/t/463199/,"В NASA испытали систему автономного управления одного микроспутника другим",votes:15,votesplus:15,votesmin:0,bookmarks:2,views:1700,comments:7


Обработка


Для парсинга мы будем использовать Python, Pandas и Matplotlib. Те кому статистика неинтересна, эту часть могут пропустить и сразу перейти к статьям.

Сначала нужно загрузить датасет в память и выделить данные за нужный год.

import pandas as pd
import datetime
import matplotlib.dates as mdates
from matplotlib.ticker import FormatStrFormatter
from pandas.plotting import register_matplotlib_converters


df = pd.read_csv("habr.csv", sep=',', encoding='utf-8', error_bad_lines=True, quotechar='"', comment='#')
dates = pd.to_datetime(df['datetime'], format='%Y-%m-%dT%H:%MZ')
df['datetime'] = dates
year = 2019
df = df[(df['datetime'] >= pd.Timestamp(datetime.date(year, 1, 1))) & (df['datetime'] < pd.Timestamp(datetime.date(year+1, 1, 1)))]

print(df.shape)

Оказывается, за этот год (хотя он еще не закончен) на момент написания текста было опубликовано 12715 статей. Для сравнения, за весь 2018й — 15904. В общем, немало — это примерно 43 статьи в день (и это только с положительным рейтингом, сколько загружается всего статей, которые ушли в минус или были удалены, можно только гадать или примерно прикинуть по пропускам среди идентификаторов).

Выделим из датасета необходимые поля. В качестве метрик мы будем использовать количество просмотров, комментариев, значения рейтинга и количества добавлений в закладки.

def to_float(s):
    # "bookmarks:22" => 22.0
    num = ''.join(i for i in s if i.isdigit())
    return float(num)

def to_int(s):
    # "bookmarks:22" => 22
    num = ''.join(i for i in s if i.isdigit())
    return int(num)

def to_date(dt):
    return dt.date() 

date = dates.map(to_date, na_action=None)
views = df["views"].map(to_int, na_action=None)
bookmarks = df["bookmarks"].map(to_int, na_action=None)
votes = df["votes"].map(to_float, na_action=None)
votes_up = df["up"].map(to_float, na_action=None)
votes_down = df["down"].map(to_float, na_action=None)
comments = df["comments"].map(to_int, na_action=None)

df['date'] = date
df['views'] = views
df['votes'] = votes
df['bookmarks'] = bookmarks
df['up'] = votes_up
df['down'] = votes_down

Теперь данные добавлены в датасет, и мы можем их использовать. Сгруппируем данные по дням и возьмем усредненные значения.

g = df.groupby(['date'])
days_count = g.size().reset_index(name='counts')
year_days = days_count['date'].values
grouped = g.median().reset_index()
grouped['counts'] = days_count['counts']
counts_per_day = grouped['counts'].values
counts_per_day_avg = grouped['counts'].rolling(window=20).mean()
view_per_day = grouped['views'].values
view_per_day_avg = grouped['views'].rolling(window=20).mean()
votes_per_day = grouped['votes'].values
votes_per_day_avg = grouped['votes'].rolling(window=20).mean()
bookmarks_per_day = grouped['bookmarks'].values
bookmarks_per_day_avg = grouped['bookmarks'].rolling(window=20).mean()

Теперь самое интересное, мы можем посмотреть на графики.

Посмотрим количество публикаций на Хабре в 2019 году.

import matplotlib.pyplot as plt

plt.rcParams["figure.figsize"] = (16, 8)
fig, ax = plt.subplots()

plt.bar(year_days, counts_per_day, label='Articles/day')
plt.plot(year_days, counts_per_day_avg, 'g-', label='Articles avg/day')
plt.xticks(rotation=45)
ax.xaxis.set_major_formatter(mdates.DateFormatter("%d-%m-%Y"))  
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=1))
plt.legend(loc='best')
plt.tight_layout()
plt.show()

Результат интересный. Как можно видеть, Хабр в течении года слегка «колбасило». Причину я не знаю.



Для сравнения, 2018 выглядит несколько «ровнее»:



В целом, какого либо кардинального уменьшения числа публикуемых статей в 2019м я на графике не увидел. Более того, наоборот, оно с лета похоже даже немного выросло.

Но вот следующие два графика удручают меня немного больше.

Среднее число просмотров на статью:



Средний рейтинг на статью:



Как можно видеть, среднее число просмотров в течении года немного снижается. Это можно объяснить тем, что новые статьи еще не проиндексированы поисковиками, и их находят не так часто. А вот снижение среднего рейтинга на статью более непонятно. Ощущение такое, что читатели или просто не успевают просматривать такое количество статей или не обращают внимание на рейтинги. С точки зрения программы поощрения авторов, это тенденция весьма неприятная.

Кстати, в 2018 такого не было, и график более-менее ровный.



В общем, владельцам ресурса есть над чем подумать.

Но не будем о грустном. В целом можно сказать, что летние изменения Хабр «пережил» вполне успешно, и число статей на сайте не сократилось.

Рейтинг


Теперь собственно, рейтинг. Поздравляю тех, кто в него попал. Еще раз напомню, что рейтинг неофициальный, возможно я что-то упустил, и если какая-то статья здесь точно должна быть, а её нет, пишите, добавлю вручную. В качестве рейтинга я использую рассчитанные метрики, которые как мне кажется, получились достаточно интересными.

Топ статей по числу просмотров


Топ статей по соотношению рейтинга к просмотрам


Топ статей по соотношению комментариев к просмотрам


Топ самых спорных статей


Топ статей по рейтингу


Топ статей по числу добавлений в закладки


Топ по соотношению добавлений в закладки к просмотрам


Топ статей по числу комментариев


И наконец, последний Антитоп по числу дизлайков


Уфф. У меня есть еще несколько интересных выборок, но не буду утомлять читателей.

Заключение


При построении рейтинга я обратил внимание на два момента, которые показались интересными.

Во-первых, все-таки 60% топа — это статьи жанра «geektimes». Будет ли их меньше в следующем году, и как будет Хабр выглядеть без статей про пиво, космос, медицину и прочее — я не знаю. Определенно, читатели что-то потеряют. Посмотрим.

Во-вторых, неожиданно качественным оказался топ по закладкам. Это психологически понятно, на рейтинг читатели могут и не обратить внимание, а если статья нужна, то в закладки её добавят. И здесь как раз наибольшая концентрация полезных и серьезных статей. Думаю, владельцам сайта стоит как-то продумать связь числа добавлений в закладки с программой поощрения, если они хотят увеличения именно этой категории статей здесь на Хабре.

Как-то так. Надеюсь, было познавательно.

Список статей получился длинный, ну оно наверно и к лучшему. Всем приятного чтения.
Tags:habrgeektimesстатистикаpythonpandasmatplotlib
Hubs: Habr Python Web analytics Statistics in IT Social networks and communities
Total votes 90: ↑88 and ↓2 +86
Views17K

Comments 32

Only those users with full accounts are able to leave comments. Log in, please.

Popular right now

Разработчик-алгоритмист (Python, C++)
from 100,000 to 150,000 ₽Российский квантовый центрRemote job
Python разработчик
from 120,000 ₽Онлайн школа ТетрикаМоскваRemote job
Маркетинговый аналитик
from 110,000 ₽YCLIENTSСанкт-ПетербургRemote job
Разработчик Python
from 100,000 to 100,000 ₽СберСанкт-Петербург
Senior Python Backend Engineer (Remote / Office)
from 4,000 $AdjustСанкт-ПетербургRemote job