Cet article est le 19e jour du calendrier de l'Avent du département NTT Docomo SI.
Bonjour, c'est Hashimoto de l'équipe de moteur de lecture anticipée. Dans l'entreprise, nous travaillons au développement de technologies d'analyse de données personnelles pour le service d'agent.
Dans cet article, nous présenterons ** une méthode pour évaluer quantitativement la durée de vie du contenu (publication d'articles en continu) en appliquant une analyse du temps de survie aux données d'articles publiés par Qiita **.
L'analyse du temps de survie est une méthode pour analyser la relation entre la période jusqu'à ce que l'événement se produise et l'événement. Généralement, il est utilisé pour analyser la période jusqu'à l'événement de décès d'un patient (vie humaine) dans le domaine médical et la période jusqu'à un événement de défaillance d'un composant (vie d'une pièce) dans le domaine de l'ingénierie. Cette fois, dans ** Qiita post data, j'analyserai la vie des publications techniques ** en supposant que l'utilisateur a cessé de publier des articles d'une technologie spécifique en continu lorsqu'un événement se produit!: Muscle:
En utilisant l'analyse du temps de survie, il est possible d'évaluer si le contenu a une durée de vie longue / courte ou si le taux d'utilisation du contenu diminue lentement / soudainement. Il existe différentes utilisations possibles des résultats de l'évaluation, telles que la création de la quantité de fonctionnalités de la tâche de classification de contenu, la création de la quantité de fonctionnalités de la tâche de classification des utilisateurs à l'aide de l'historique d'utilisation du contenu ou la prise de décision pour la mesure de recommandation de contenu.
Pour plus d'informations sur l'analyse du temps de survie, veuillez consulter les articles et livres suivants.
Le déroulement approximatif de l'analyse dans cet article est le suivant.
L'environnement d'exécution du programme dans l'article est Python3.6, macOS 10.14.6. Nous utiliserons également une bibliothèque d'analyse des temps de survie appelée lifelines 0.22.9.
Cet article utilise l'ensemble de données Qiita obtenu ci-dessous. Création d'un ensemble de données à partir du post de Qiita
Cet ensemble de données est un ensemble de données de l'historique de publication d'articles de l'utilisateur acquis à partir de l'API fournie par Qiita. Vous pouvez consulter l'historique des publications de 2011 à 2018. En effectuant cette analyse
Ces données ont été adoptées car elles remplissent les deux conditions ci-dessus.
Si vous lisez les données avec pandas dataframe, ce sera comme suit.
import pandas as pd
df = pd.read_csv('qiita_data1113.tsv', sep='\t')
df.head()
created_at | updated_at | id | title | user | likes_count | comments_count | page_views_count | url | tags |
---|---|---|---|---|---|---|---|---|---|
2011-09-30T22:15:42+09:00 | 2015-03-14T06:17:52+09:00 | 95c350bb66e94ecbe55f | Gentoo est mignon Gentoo | {'description': ';-)',... | 1 | 0 | NaN | https://... | [{'name': 'Gentoo', 'versions': []}] |
2011-09-30T21:54:56+09:00 | 2012-03-16T11:30:14+09:00 | 758ec4656f23a1a12e48 | Code du bulletin de tremblement de terre | {'description': 'Emi Tamak... | 2 | 0 | NaN | https://... | [{'name': 'ShellScript', 'versions': []}] |
2011-09-30T20:44:49+09:00 | 2015-03-14T06:17:52+09:00 | 252447ac2ef7a746d652 | parsingdirtyhtmlcodesiskillingmesoftly | {'description': 'N'appelez pas github... | 1 | 0 | NaN | https://... | [{'name': 'HTML', 'versions': []}] |
2011-09-30T14:46:12+09:00 | 2012-03-16T11:30:14+09:00 | d6be6e81aba24f39e3b3 | Objective-Comment la variable suivante x est-elle gérée dans l'implémentation de la classe C?... | {'description': 'Bonjour. Hatena... | 2 | 1 | NaN | https://... | [{'name': 'Objective-C', 'versions': []}] |
2011-09-28T16:18:38+09:00 | 2012-03-16T11:30:14+09:00 | c96f56f31667fd464d40 | HTTP::Request->AnyEvent::HTTP->HTTP::Response | {'description'... | 1 | 0 | NaN | https://... | [{'name': 'Perl', 'versions': []}] |
À propos, dans chaque article, jusqu'à 3 balises sont extraites de la colonne des balises, et le classement basé sur le nombre total est le suivant.
index | tag | |
---|---|---|
0 | JavaScript | 14403 |
1 | Ruby | 14035 |
2 | Python | 13089 |
3 | PHP | 10246 |
4 | Rails | 9274 |
5 | Android | 8147 |
6 | iOS | 7663 |
7 | Java | 7189 |
8 | Swift | 6965 |
9 | AWS | 6232 |
Extrayez les données nécessaires du DataFrame qui a lu l'ensemble de données ci-dessus.
df_base = <get tags>
df_base.head()
user_id | time_stamp | tag |
---|---|---|
kiyoya@github | 2011-09-30 22:15:42+09:00 | Gentoo |
hoimei | 2011-09-30 21:54:56+09:00 | ShellScript |
inutano | 2011-09-30 20:44:49+09:00 | HTML |
hakobe | 2011-09-30 14:46:12+09:00 | Objective-C |
motemen | 2011-09-28 16:18:38+09:00 | Perl |
ichimal | 2011-09-28 14:41:56+09:00 | common-lisp |
l_libra | 2011-09-28 08:51:27+09:00 | common-lisp |
ukyo | 2011-09-27 23:57:21+09:00 | HTML |
g000001 | 2011-09-27 22:29:04+09:00 | common-lisp |
suginoy | 2011-09-27 10:20:28+09:00 | Ruby |
Les \ _at et les balises créés ont été extraits en tant qu'ID utilisateur, heure \ _stamp de chaque enregistrement. Pour ceux qui ont plusieurs balises, nous en avons pris jusqu'à 5 et avons concédé chacune comme un enregistrement. Notez que les fluctuations de notation des balises (golang et Go, Rails et RubyOnRails, etc.) ne sont pas prises en compte.
Convertit le format de données en indicateurs de données à deux colonnes, de durée de vie et d'événement, pour une entrée dans le modèle wive de lignes de vie. Étant donné que ces données ne révèlent pas d'événement clair (arrêt de la publication d'articles) ou de temps de survie (durée de publication continue de l'article), il est nécessaire de le définir indépendamment.
Dans cette section, un événement est défini comme une occurrence d'événement lorsque les deux conditions suivantes sont remplies.
Si le délai de la période d'observation et celui du dernier affichage sont inférieurs à θ jours, l'observation sera abandonnée.
C'est un peu difficile à comprendre, je vais donc l'expliquer avec un chiffre.
La figure ci-dessus montre le moment de la publication des articles par ordre chronologique pour 3 utilisateurs. Pour l'utilisateur A, la date limite de la période d'observation et la période du dernier affichage sont de θ jours ou plus. Par conséquent, l'événement se produira après la publication finale. L'utilisateur B dispose d'une période de θ jours ou plus pour les deux derniers messages. Dans ce cas également, il est considéré comme une occurrence d'événement. Pour l'utilisateur C, la période entre deux postes adjacents est inférieure à θ, et la date limite de la période d'observation et la période du dernier poste sont inférieures à θ jours. Par conséquent, il est traité comme une interruption d'observation. Concernant le temps de survie, la période jusqu'à la survenue de l'événement ou la période jusqu'à la date limite de la période d'observation est définie comme la durée de survie.
Cette fois, nous avons décidé de déterminer si un événement s'est produit ou non et le temps de survie en fonction des règles ci-dessus.
Si la logique ci-dessus est définie et implémentée comme
make_survival_dataset () '' ``, ce sera comme suit. Cette fois, θ = 365 jours. En outre, le 01/12/2018 est spécifié comme date limite d'observation. On suppose qu'un DataFrame filtré par une balise spécifique est entré comme argument.
import datetime
import pytz
def make_survival_dataset(df_qiita_hist, n = 365):
id_list = []
duration_list = []
event_flag_list = []
for index, (userid, df_user) in enumerate(df_qiita_hist.groupby('user_id')):
#Ajouter une date limite d'observation à la fin
dt = datetime.datetime(2018, 12, 1, tzinfo=pytz.timezone("Asia/Tokyo"))
last = pd.Series(['test', dt, 'last'], index=['user_id', 'time_stamp', 'tag'], name='last')
df_user= df_user.append(last)
#Calculez la période entre deux postes adjacents(Le haut de la liste est Aucun.)
day_diff_list = df_user.time_stamp.diff().apply(lambda x: x.days).values
#Les listes d'une longueur de 2 ou moins sont exclues du calcul.
if len(day_diff_list) <= 2:
continue
#Recherchez si un événement se produit ou non.
event_flag = False
#Liste pour calculer la période jusqu'à ce que l'événement se produise
day_list = []
for day in day_diff_list[1:]:
if day >= n:
event_flag = True
break
day_list.append(day)
#Calculez la période jusqu'à ce que l'événement se produise
s = sum(day_list)
#Ceux avec une période de 0 sont exclus
if s == 0:
continue
#Créer un DataFrame
id_list.append(userid)
duration_list.append(s)
event_flag_list.append(event_flag)
return pd.DataFrame({'userid':id_list, 'duration':duration_list, 'event_flag': event_flag_list})
Extrayez l'enregistrement avec la balise Python et entrez-le dans make \ _survival \ _dataset.
df_python = df_base[df_base['tag'] == 'Python'].sort_values('time_stamp')
df_surv = make_survival_dataset(df_python, n=365)
df_surv.head()
userid | duration | event_flag |
---|---|---|
33yuki | 154.0 | False |
5zm | 432.0 | False |
AketiJyuuzou | 57.0 | True |
AkihikoIkeda | 308.0 | False |
Amebayashi | 97.0 | True |
Vous avez maintenant les données à entrer dans le modèle Wible.
Entrez les données créées ci-dessus dans le modèle Wible et effectuez l'ajustement des paramètres et le tracé de la courbe de survie. Ici, en plus de Python, traçons les données avec des balises Ruby.
import lifelines
%matplotlib inline
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'IPAexGothic'
_, ax = plt.subplots(figsize=(12, 8))
# Python
name = 'Python'
df_surv = make_survival_dataset(df_base[df_base['tag'] == name].sort_values('time_stamp'), n=365)
wf = lifelines.WeibullFitter().fit(df_surv['duration'], df_surv['event_flag'], label=name)
wf.plot_survival_function(ax=ax, grid=True)
# Ruby
name = 'Ruby'
df_surv = make_survival_dataset(df_base[df_base['tag'] == name].sort_values('time_stamp'), n=365)
wf = lifelines.WeibullFitter().fit(df_surv['duration'], df_surv['event_flag'], label=name)
wf.plot_survival_function(ax=ax, grid=True)
ax.set_ylim([0, 1])
ax.set_xlabel('Durée de vie(journée)')
ax.set_ylabel('Taux de survie')
L'axe vertical représente le nombre de jours et l'axe vertical le taux de survie (pourcentage d'utilisateurs qui continuent de publier). Dans l'ensemble, on peut voir que le taux de survie diminue au fur et à mesure que le nombre de jours progresse. En nous concentrant sur Python, nous pouvons voir que le taux de survie est juste en dessous de 0,2 au moment de 1500 jours. Cela signifie que 20% des personnes continueront à publier 1500 jours après le début de la publication. D'autre part, les 80% restants signifient arrêter de publier en permanence. Après 1500 jours de comparaison de Python et Ruby, vous pouvez voir qu'il y a une différence d'environ 10%. Pour autant que nous puissions voir, ** Dans l'ensemble, les articles Python ont une durée de survie plus longue que les articles Ruby, et il existe une tendance à la publication d'articles en continu. ** La longévité de Python semble être influencée par l'augmentation récente de la demande en tant qu'outil d'apprentissage automatique / d'analyse de données.
De cette manière, en définissant l'occurrence de l'événement et le temps de survie pour le journal de contenu et en effectuant l'analyse du temps de survie, le temps de survie du contenu peut être comparé.
Selon la documentation lifelines, la courbe de taux de survie est basée sur la formule ci-dessous. Il est tracé basé sur.
La courbe de taux de survie dépend des paramètres λ et ρ, et la fonction d'ajustement de Weibull Fitter se présente sous la forme du calcul des paramètres ci-dessus. Par conséquent, en traçant les valeurs de λ et ρ obtenues à partir de WeibullFitter sur un graphique bidimensionnel, la similitude de la courbe de taux de survie pour chaque étiquette peut être confirmée visuellement.
J'ai réduit les balises avec 1000 utilisateurs ou plus de publication dans l'ensemble de données et les ai tracées.
Λ est tracé sur l'axe vertical et ρ est tracé sur l'axe horizontal.
En général, plus la valeur de λ est élevée, plus le temps de survie est long et plus la valeur de ρ est élevée, plus la pente de la courbe du taux de survie est raide au fil du temps. Si vous classez grossièrement par la taille de λ et ρ, cela ressemble à ceci: penser:
** Grand λ: Longue survie ** --PHP (et Laravel), Ruby (et Rails), C #, iOS, Android, etc. --Impression qu'il est souvent utilisé dans les produits (beaucoup d'utilisateurs?) Et qu'il existe de nombreux langages de programmation (et frameworks) et de développement mobile. ―― Comme il s'agit du langage et du cadre utilisés pour le produit, il existe de nombreuses histoires et il est facile de continuer à publier des articles. ――Il semble lié au degré d'impact des changements fonctionnels dus aux mises à jour
** Petit λ: temps de survie court **
CentOS, Ubuntu, PostgreSQL, Nginx, Git, Slack, etc. --Impression que les outils de plate-forme de développement tels que le système d'exploitation et les intergiciels et les outils de soutien au développement tels que Git et Slack sont concentrés ―― Comme il s'agit d'une partie basique, il y a relativement peu de matériel, donc la publication d'articles a tendance à être à court terme
** ρ est grand: la pente de la courbe de taux de survie s'accentue avec le temps ** --SSH, Chrome, Git, Slack, Mac, Windows, etc. --Impression que les outils de base sont concentrés
De nombreux articles liés aux outils de base sont des articles d'introduction, et après le début de la publication, les publications continues se poursuivent pendant un certain temps, mais diminuent après un certain temps
** ρ est petit: la pente de la courbe du taux de survie s'améliore avec le temps **
Langage de programmation, middleware, système d'exploitation Linux, etc. --Impression que des outils (techniques) relativement hautement spécialisés sont concentrés. ――Il est facile d'arrêter de publier des articles sur des outils (techniques) hautement spécialisés immédiatement après avoir commencé à publier, mais certaines personnes continuent de publier.
Il est résumé dans la figure ci-dessous.
Pour la plupart des choses, j'ai l'impression que cela correspond à l'interprétation (?). Il est intéressant de noter que la différence de paramètres est liée au type de technologie réelle. Il y a quelques subtilités telles que C # et Objective-C, mais ...: penser:
Nous avons effectué une analyse du temps de survie sur les données de l'article Qiita et classé le contenu des deux points de vue de la durée de survie et du degré de changement de la pente de la courbe du taux de survie. C'était une interprétation approximative, mais j'ai trouvé que cela semble être lié à la différence de paramètres et au type de technologie. Je pense que le contenu présenté dans cet article est une méthode qui peut être appliquée à d'autres journaux de contenu. Si vous avez la possibilité de toucher le journal d'utilisation du contenu, veuillez vous y référer. Enfin, je partagerai quelques-uns des résultats d'analyse supplémentaires et terminerai. Eh bien, passez une bonne année ~: raise_hand:
iOS V.S. Android
Emacs V.S. Vim
Recommended Posts