Quand j'ai eu l'idée que «la science des données semble être amusante et je veux commencer!», Il y a des informations sur des «méthodes» telles que des packages tels que les pandas et des modèles tels que SVM, mais il y a peu d'introduction de cas familiers. Je le pense. ~~ Je ne suis pas enthousiasmé par la classification d'Ayame. ~~
Par conséquent, le but de cet article est de vous faire découvrir une série de processus d'analyse de données, en utilisant mon passe-temps «Analyse pour augmenter le nombre de vues du premier travail publié de VOCALOID» comme exemple. J'espère que je pourrais avoir une certaine influence sur votre analyse et votre motivation.
Nous procéderons à l'analyse dans l'ordre suivant. Je ne fais référence à rien de spécifique, mais je suis conscient de la forme qui intègre la technologie de programmation basée sur le flux d'articles empiriques utilisant l'économie métrique. [^ 1]
[^ 1]: Cette analyse fait partie du cadre d'analyse de données classique consistant à «faire d'abord une hypothèse, puis la tester avec des données». Je pense que le processus est différent de l'approche d'exploration de données consistant à «trouver des connaissances utiles à partir de données désordonnées».
L'objectif principal de cet article est de vous parler du processus d'analyse des données, mais si vous êtes intéressé par les sujets suivants utilisés pour l'analyse, n'hésitez pas!
--Comment accéder à la vidéo Nico Nico "Snapshot Search API v2" en utilisant Python
Vous avez terminé votre premier travail en tant que nouveau venu Bokaro P. Lorsque je publie une œuvre sur un site vidéo, je pense essayer d'augmenter le plus possible le nombre de vues. La qualité de la chanson elle-même ne peut plus être modifiée, donc je pense à concevoir quelque chose pour le titre et les commentaires de l'affiche.
Le premier message d'une chanson VOCALOID est presque toujours étiqueté comme "VOCALOID maiden work". En revanche, peu de personnes mettent «premier message» dans le titre de leur travail. (Par exemple, "[Hatsune Miku Original] ~ Titre ~ [Premier message]")
Si vous ajoutez "premier message" au titre, quel type d'image les spectateurs auront-ils lorsqu'ils le verront? Il y a deux réactions possibles: "Oh, je vais vous demander si vous êtes un nouveau venu" ou "Je ne peux m'empêcher de vous demander si vous êtes un nouveau venu sans antécédents." Si la première réaction est prédominante, vous pouvez vous attendre à une augmentation du nombre de vues en ajoutant un mot au titre pour le rendre plus accrocheur.
Par conséquent, dans cet article, je voudrais tester l'hypothèse selon laquelle l'ajout de «premier message» au titre des œuvres étiquetées «VOCALOID maiden work» augmentera le nombre de vues.
Les données nécessaires à cette analyse sont
-Le travail avec le tag "VOCALOID maiden work"
Sera. De plus, nous traiterons les données des 4 dernières années (travaux affichés de 2013 à 2016).
Obtenons les informations de travail de la vidéo Nico Nico "Snapshot Search API v2". L'utilisation est organisée dans le guide officiel. http://site.nicovideo.jp/search-api-docs/snapshot.html
Les points sont les suivants.
[^ 2]: Comment utiliser le décalage: Par exemple, si vous triez par le nombre de vues de classement et définissez offset = 30, vous pouvez spécifier des œuvres après le 30e classement.
import urllib
import requests
import time
import pandas as pd
class NiconicoApi():
def __init__(self, keyword):
self.keyword = keyword
def gen_url(self, year, offset):
url_body = 'http://api.search.nicovideo.jp/api/v2/video/contents/search?'
url_query = urllib.parse.urlencode( {
'q': self.keyword,
'filters[startTime][gte]': '%i-01-01T00:00:00' % year,
'filters[startTime][lt]': '%i-01-01T00:00:00' % (year + 1),
'_offset': offset,
'targets': 'tags',
'fields': 'title,viewCounter,startTime',
'_sort': '-viewCounter',
'_limit': 100,
'_context': 'apiguide'
} )
self.url_ = url_body + url_query
return self
def get_json(self):
response = requests.get(self.url_)
self.json_ = response.json()
return self.json_
'''Obtenez des données'''
data = []
nicoApi = NiconicoApi('Œuvre inaugurale de VOCALOID')
for year in range(2013, 2017):
offset = 0
nicoApi.gen_url(year=year, offset=offset)
json = nicoApi.get_json()
while json['data']:
data += json['data']
offset += 100
nicoApi.gen_url(year=year, offset=offset)
json = nicoApi.get_json()
time.sleep(1)
'''Conversion vers DataFrame'''
df = pd.DataFrame.from_dict(data)
df.shape # => (4579, 3)
La taille de l'échantillon est désormais de 4579 [^ 3]. Puisqu'il s'agit de données pour 4 ans, il est calculé que plus de 1000 nouveaux arrivants Bokaro P naissent chaque année.
[^ 3]: au 06/03/2017
Avant de nous lancer dans une analyse à grande échelle, examinons rapidement les données.
Tout d'abord, tracez le nombre de lectures sur l'axe vertical et le classement sur l'axe horizontal. À ce stade, comme on peut prédire qu'il existe une grande différence dans le nombre de vues entre les œuvres populaires et les œuvres inconnues, nous prendrons l'axe vertical sur l'échelle logarithmique.
import numpy as np
import matplotlib.pyplot as plt
df = df.sort_values('viewCounter', ascending=False)
ranking = np.arange(len(df.index))
view_counter = df['viewCounter'].values
plt.scatter(ranking, view_counter)
plt.yscale('log')
plt.grid()
plt.title('2013~2016 Ranking & ViewCounter')
plt.xlabel('Ranking')
plt.ylabel('ViewCounter')
plt.show()
résultat:
――Il semble qu'environ 3/4 des œuvres soient jouées 100 à 1000 fois. ――Le degré de cette distorsion même si l'axe vertical est log. La disparité est terrible ... «Nous avons confirmé le degré de distorsion de la distribution et l'existence de valeurs aberrantes, nous aimerions donc l'utiliser pour des analyses futures.
Pour l'analyse, il est nécessaire de séparer les œuvres qui incluent «premier message» dans le titre et les œuvres qui n'en contiennent pas. Utilisez le groupe de pandas par méthode.
Groupby transmet souvent un nom de colonne comme argument, mais vous pouvez également transmettre une fonction. Passer une fonction facilite le regroupement dans des conditions arbitraires.
Cette fois, nous voulons regrouper par "si le titre inclut ou non" premier message "", définissons donc la fonction de la condition de jugement. Nous inclurons également "travail vierge", qui a la même signification que "premier post", dans l'analyse.
Définissez une fonction avec une valeur de retour différente selon que l'argument contient «premier post» ou «travail vierge» ou ni l'un ni l'autre.
def include_keyword(title):
if 'Premier poste' in title:
return 'Premier poste'
elif 'Premier livre' in title:
return 'Premier livre'
else:
return 'Groupe de contrôle'
Passez la fonction définie comme argument de groupby. Ensuite, la fonction est appliquée à chaque élément d'index de df1 et groupée selon la valeur de retour. C'est similaire au filtre.
#Changer l'index en colonne de titre
df1 = df[['viewCounter', 'title']].set_index('title')
#regroupement
df1_grouped = df1.groupby(include_keyword)
Maintenant que le regroupement est terminé, passons à une analyse détaillée.
Si vous calculez la valeur moyenne et la valeur médiane de chaque groupe et que vous les comparez avec "fonctionne avec des mots-clés (ci-après, groupe de traitement)" et "fonctionne sans mots-clés (groupe de contrôle)", "effets de l'inclusion de mots-clés (effets en incluant des mots-clés) Effet du traitement) »peut être mesuré.
Puis pour chaque groupe
Demandons.
Agg est utile pour trouver plusieurs statistiques descriptives à la fois. En passant plusieurs méthodes sous forme de tableau à l'argument de agg, ces méthodes peuvent être appliquées collectivement à df1_grouped.
functions = ['count', 'mean', 'median', 'std']
df1_summary = df1_grouped.agg(functions)
résultat: ―― Sur les 4579 échantillons, 109 œuvres ont «premier message» dans le titre, et 144 œuvres dont «œuvre vierge». ――Les résultats ont montré que le groupe de traitement avait plus de régénérations que le groupe témoin, à la fois en termes de valeurs moyennes et médianes. En d'autres termes, en ajoutant un mot «premier message» au titre, il semble qu'il ait pu attirer l'attention.
A partir de maintenant, considérons deux groupes, le «groupe de traitement» et le «groupe de contrôle», pour simplifier l'analyse. Modifiez df1_grouped comme suit.
def include_keyword(title):
if 'Premier poste' in title or 'Premier livre' in title:
return 'Groupe de traitement'
else:
return 'Groupe de contrôle'
df1_grouped = df1.groupby(include_keyword)
df1_summary = df1_grouped.agg(functions)
df1_summary
résultat:
Maintenant, regardons la différence entre les deux groupes dans un graphique.
X_treated = np.log(df1_grouped.get_group('Groupe de traitement').values)
X_untreated = np.log(df1_grouped.get_group('Groupe de contrôle').values)
plt.hist(X_treated, normed=True, bins=20, label='Groupe de traitement', color='r', alpha=0.5)
plt.hist(X_untreated, normed=True, bins=20, label='Groupe de contrôle', color='b', alpha=0.5)
plt.show()
résultat:
Le graphique montre également la différence de distribution entre le groupe de traitement et le groupe témoin.
Soit dit en passant, le résultat souhaité (le nombre de vues augmente en incluant le "premier message" dans le titre) a été suggéré jusqu'à présent, mais la "différence dans le nombre de vues entre le groupe de traitement et le groupe témoin" obtenue dans la section précédente est statistique. Vérifions si c'est significatif (n'est-ce pas une différence qui peut s'expliquer par le hasard)?
Comme mentionné précédemment, la distribution des lectures est sévèrement déformée, vous devriez donc regarder la médiane plutôt que la moyenne. Ce n'est pas la comparaison médiane des deux groupes, mais une alternative est le test U de Mann-Whitney [^ 4].
Le test U de Mann-Whitney pose l'hypothèse nulle que la forme de la distribution entre les deux groupes est la même [^ 5]. Si cette hypothèse nulle est rejetée, le nombre de rediffusions dans les groupes de traitement et de contrôle se trouve être inexplicablement différent.
Le test U est fourni dans le module de statistiques de scipy. Testons-le.
from scipy import stats
result = stats.mannwhitneyu(X_treated, X_untreated)
print(result.pvalue) # => 0.00137327945838
Puisque la valeur p est de 0,0014, on peut dire que la distribution entre les deux groupes est significativement différente. Tu l'as fait!
[^ 5]: Pour effectuer le test U de Mann-Whitney, il est nécessaire de supposer la dispersion égale des deux groupes, mais ceci est omis pour des raisons de simplicité. J'ai également essayé le test de Brunner-Munzel, qui ne nécessite pas de processus équidistant, et j'ai trouvé des résultats significatifs, donc les résultats semblent robustes. (Pour le test Brunner-Munzel, reportez-vous ici: http://oku.edu.mie-u.ac.jp/~okumura/stat/brunner-munzel.html)
Une chose qui doit être notée dans une telle analyse est la "fausse corrélation". On peut dire que «corrélation ≠ effet causal».
Tout ce que nous avons fait jusqu'à présent, c'est qu'il existe une corrélation entre l'ajout d'un "premier message" au titre et le nombre de vues. Nous examinerons si cette corrélation peut être interprétée comme une relation causale.
Par exemple, il existe une corrélation entre les ventes de glaces et les accidents d'eau. A partir de là, il semble violent de conclure que "manger de la glace vous rend plus vulnérable aux accidents d'eau", non?
La vraie cause est la «saison». Oublier de considérer la «saison» et conduire à la fausse corrélation mentionnée ci-dessus est appelé «biais de variable manquante» en termes d'économie métrique. (Dans ce cas, variable manquante = saison)
Revenons à la chanson VOCALOID. S'il y a des «variables manquantes» dans cette analyse, quels sont les facteurs possibles?
Je suis venu avec le cas où «date de publication» est une variable manquante. Supposons que la situation suivante se vérifie.
――La culture VOCALOID est entrée dans une période de déclin et le nombre de vues est en baisse de 2013 à 2016. --VOCALOID C'est une vieille pratique d'ajouter "premier message" au titre d'une chanson, et il a disparu récemment.
Dans ce cas, les deux phénomènes «l'année d'affichage est ancienne -> de nombreuses vues» et «l'année d'affichage est ancienne» -> l'ajout de «premier message» au titre «se chevauchent, créant une fausse corrélation. Je comprends ça.
Vérifions s'il existe une fausse corrélation comme celle ci-dessus. Deux colonnes représentant l '«année de cotisation» et le «groupe de traitement ou groupe témoin» sont créées à l'avance et le regroupement est effectué sur la base de ces deux colonnes.
df2 = df.copy()
df2['title'] = df2['title'].apply(include_keyword)
df2['startTime'] = pd.DatetimeIndex(df2['startTime'])
# tz_Pour appliquer localize'startTime'Est spécifié dans l'index
df2 = df2.set_index('startTime')
df2.index = df2.index.tz_localize('UTC').tz_convert('Asia/Tokyo')
df2['startTime'] = df2.index
df2['startTime'] = df2['startTime'].apply(lambda x: x.year)
df2_grouped = df2.groupby(['startTime', 'title']).viewCounter
df2_summary = df2_grouped.agg(functions)
df2_summary
Résultat: même groupés par année comptable, on constate que le nombre de vues du groupe de traitement et du groupe témoin est différent sauf en 2013.
Maintenant que nous avons grossièrement confirmé dans le tableau ci-dessus que l'année de publication n'est pas une variable manquante, analysons-la plus rigoureusement en utilisant la régression multiple.
Supposons que le nombre de vues soit déterminé comme suit:
Ici, les détails de chaque variable sont les suivants.
Ensuite, j'expliquerai les avantages de l'utilisation de la régression multiple. Avec la régression multiple, il est possible d'estimer «combien le nombre de lectures diffère entre le groupe de traitement et le groupe témoin lorsque la tendance temporelle est fixe ($ \ beta_1 $)». Par conséquent, il est possible d'éliminer la corrélation apparente due aux tendances temporelles.
L'inconvénient ici est qu'il utilise le nombre moyen de lectures pour estimer $ \ beta_1 $, ce qui le rend plus sensible aux valeurs aberrantes.
Lançons-le.
import statsmodels.formula.api as smf
def include_keyword(title):
if 'Premier poste' in title or 'Premier livre' in title:
return 1
else:
return 0
df3 = df.copy()
df3['title'] = df3['title'].apply(include_keyword)
df3['startTime'] = pd.DatetimeIndex(df3['startTime'])
df3['timeTrend'] = df3['startTime'].apply(lambda x: (df3['startTime'].max() - x).days)
df3['lviewCounter'] = np.log(df3['viewCounter'])
mod = smf.ols('lviewCounter ~ title + timeTrend', data=df3).fit()
mod.summary()
résultat:
On peut dire que ce résultat d'analyse est plus robuste car il a été confirmé que «post date et heure» ne créait pas de biais variable manquant. Tu l'as fait!
Ceci conclut "l'évaluation de la validité de l'analyse", mais si vous pensez "Est-il préférable de vérifier également ce facteur?", Veuillez commenter!
Cela fait longtemps, mais merci beaucoup d'avoir lu jusqu'ici.
Au fait, sur la base de cette analyse, j'ai ajouté le "premier message" au titre et l'ai posté sur Nikodo, mais le nombre de vues était inférieur à 200. Notez que les tendances statistiques ne s'appliquent pas aux cas individuels.
Cet article se termine lorsque j'obtiens une ligne de punch. Je serais heureux si je pouvais vous dire quelque chose sur le flux de l'analyse, ce à quoi vous devez faire attention et la technologie dont vous avez besoin.
Recommended Posts