[PYTHON] Analyse de la vie de la technologie avec les données d'articles Qiita ~ Analyse du temps de survie à l'aide du journal de contenu ~

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.

Flux d'analyse

Le déroulement approximatif de l'analyse dans cet article est le suivant.

  1. ** Prétraitement des données **: Calcule la période de temps pendant laquelle les articles Qiita avec une balise spécifique ont été postés à tous les utilisateurs et l'indicateur indiquant si la publication a été arrêtée ou non.
  2. ** Application au modèle Wyble **: En utilisant les données ci-dessus comme données d'entrée, ajustez le modèle Wyble (estimez les paramètres du modèle Wyble) et sortez la courbe de taux de survie obtenue à partir du modèle Wyble.
  3. ** Comparaison du taux de survie pour chaque étiquette **: Effectuez ce qui précède pour plusieurs étiquettes (techniques) et comparez les paramètres de la courbe de taux de survie.

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.

À propos de l'ensemble de données

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

Traitement analytique

1. Prétraitement

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.

  1. L'événement se produit lorsque la période entre deux messages adjacents est de θ jours ou plus
  2. Un événement survient lorsque la date limite de la période d'observation et la période du dernier affichage sont de θ jours ou plus.

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

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.

2. Application au 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')

python_ruby_surv.png

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

3. Comparaison des paramètres de la courbe de taux de survie pour chaque étiquette

Selon la documentation lifelines, la courbe de taux de survie est basée sur la formule ci-dessous. Il est tracé basé sur.

S(t) = \exp(-(t/\lambda)^{\rho}) \ where\ \lambda > 0, \rho > 0

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.

param_plot_1000.png

Λ 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:

Il est résumé dans la figure ci-dessous. param_plot_comment.png

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:

Résumé

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:

prime

iOS V.S. Android ios_android_surv.png

Emacs V.S. Vim emacs_vim_surv.png

Cadre typique de Deep Learning

deep_learning.png

Diagramme de paramètres avec plus de 500 utilisateurs de publication

param_plot_500.png

Recommended Posts

Analyse de la vie de la technologie avec les données d'articles Qiita ~ Analyse du temps de survie à l'aide du journal de contenu ~
Raccourcir le temps d'analyse d'Openpose à l'aide du son
Recommandation d'analyse des données à l'aide de MessagePack
Analyse des séries chronologiques 3 Prétraitement des données des séries chronologiques
Illustrez instantanément la période prédominante dans les données de séries chronologiques à l'aide de l'analyse spectrale
Une introduction à l'analyse de données à l'aide de Python - Pour augmenter le nombre de vues vidéo -
Comment obtenir des données d'article à l'aide de l'API Qiita
Voir les détails des données de séries chronologiques dans Remotte
Vérifiez l'état des données à l'aide de pandas_profiling
Gratter les données gagnantes de Numbers à l'aide de Docker
Prédire le temps objectif d'un marathon complet avec l'apprentissage automatique-③: j'ai essayé de visualiser les données avec Python-
[Didacticiel d'analyse Python dans la base de données avec SQL Server 2017] Étape 4: Extraction de fonctionnalités de données à l'aide de T-SQL
Je voulais juste extraire les données de la date et de l'heure souhaitées avec Django