Aujourd'hui, il existe 100500 cours sur le Data Science et il est bien connu que le plus d'argent dans ce domaine provient justement des cours de Data Science (pourquoi creuser quand on peut vendre des pelles ?). Le principal inconvénient de ces cours est qu'ils n'ont rien à voir avec le travail réel : personne ne vous fournira des données propres, traitées au format souhaité. Et quand vous terminez un cours et commencez à résoudre un problÚme réel, de nombreux nuances émergent.
C'est pourquoi nous commençons une série de notes intitulée « Qu'est-ce qui peut mal tourner avec le Data Science », basées sur des événements réels qui se sont produits avec moi, mes amis et collÚgues. Nous allons examiner à travers des exemples concrets des tùches typiques en Data Science : comment cela se passe réellement. Commençons aujourd'hui par la tùche de collecte de données.
Et le premier obstacle que rencontrent les gens en commençant à travailler avec des données réelles est justement la collecte de ces données pertinentes. Le message clé de cet article :
Nous sous-estimons systématiquement le temps, les ressources et les efforts nécessaires à la collecte, au nettoyage et à la préparation des données.
Et surtout, nous discuterons de ce qu'il faut faire pour éviter cela.
Selon différentes estimations, le nettoyage, la transformation, le traitement des données, l'ingénierie des caractéristiques, etc., prennent 80 à 90 % du temps, tandis que l'analyse ne représente que 10 à 20 %, alors que tout le matériel éducatif se concentre exclusivement sur l'analyse.
Analysons, Ă titre d'exemple, une tĂąche analytique simple en trois variantes et voyons quelles peuvent ĂȘtre les « circonstances aggravantes ».
Et pour l'exemple, nous allons encore examiner de telles variations de la tùche de collecte de données et de comparaison entre communautés pour :
- Deux sous-reddits Reddit
- Deux sections de Habr
- Deux groupes Odnoklassniki
Approche conditionnelle en théorie
Ouvrir le site et lire des exemples, si c'est clair, consacrer quelques heures à lire, quelques heures à coder selon les exemples et à déboguer. Ajouter plusieurs heures pour la collecte. Prévoir quelques heures supplémentaires (multiplier par deux et ajouter N heures).
Point clé : l'estimation temporelle repose sur des hypothÚses et des conjectures sur le temps que cela prendra.
Commencer l'analyse temporelle nécessite d'évaluer les paramÚtres suivants pour la tùche conditionnelle décrite ci-dessus :
- Quelle est la taille des données et combien il faut les collecter physiquement (*voir ci-dessous*).
- Quel temps de collecte est nécessaire pour un enregistrement et combien de temps faut-il attendre avant de pouvoir en collecter un second.
- Prévoir l'écriture d'un code qui sauvegarde l'état et redémarre lorsque (et non si) tout échoue.
- Déterminer si nous avons besoin d'une autorisation et prévoir le temps d'accÚs via l'API.
- PrĂ©voir le nombre d'erreurs comme une fonction de la complexitĂ© des donnĂ©es â Ă©valuer en fonction de la tĂąche spĂ©cifique : la structure, le nombre de transformations, ce que nous extrayons et comment.
- Prévoir les erreurs réseau et les problÚmes de comportement anormal du projet.
- Ăvaluer si les fonctions nĂ©cessaires sont dans la documentation et si non, combien de temps et comment il faudra pour un contournement.
Le plus important pour Ă©valuer le temps est que vous devez rĂ©ellement consacrer du temps et des efforts Ă une 'reconnaissance' â ce n'est qu'alors que votre planification sera adĂ©quate. Donc, peu importe combien on vous pousse Ă dire 'combien de temps faut-il pour collecter les donnĂ©es' â accordez-vous du temps pour une analyse prĂ©liminaire et argumentez par rapport au fait que le temps variera en fonction des paramĂštres rĂ©els de la tĂąche.
Et maintenant, nous allons prĂ©senter des exemples concrets oĂč ces paramĂštres changeront.
Point clé : l'évaluation est basée sur l'analyse des facteurs clés influençant le volume et la complexité du travail.
Une Ă©valuation basĂ©e sur des hypothĂšses est une bonne approche lorsque les Ă©lĂ©ments fonctionnels sont assez petits et qu'il n'y a pas beaucoup de facteurs pouvant influencer significativement la structure de la tĂąche. Mais dans le cas de certaines tĂąches de Data Science, ces facteurs deviennent extrĂȘmement nombreux et cette approche devient inadĂ©quate.
Comparaison des communautés Reddit
Commençons par le cas le plus simple (comme il s'avĂ©rera par la suite). En fait, si nous parlons honnĂȘtement, nous avons pratiquement un cas idĂ©al, vĂ©rifions notre liste de contrĂŽle de complexitĂ© :
- Il existe une API soignée, claire et documentée.
- Le token est extrĂȘmement simple Ă obtenir et, surtout, s'obtient automatiquement.
- Oui â avec de nombreux exemples.
- La communauté qui s'occupe de l'analyse et de la collecte de données sur Reddit (jusqu'à des vidéos YouTube expliquant comment utiliser le wrapping Python) .
- Les méthodes dont nous avons besoin existent probablement dans l'API. De plus, le code semble compact et propre, ci-dessous un exemple de fonction collectant les commentaires d'un post.
def get_comments(submission_id):
reddit = Reddit(check_for_updates=False, user_agent=AGENT)
submission = reddit.submission(id=submission_id)
more_comments = submission.comments.replace_more()
if more_comments:
skipped_comments = sum(x.count for x in more_comments)
logger.debug('Skipped %d MoreComments (%d comments)',
len(more_comments), skipped_comments)
return submission.comments.list()
Extrait de une sélection d'outils pratiques pour l'encapsulation.
Bien que nous soyons devant le meilleur des cas, il convient cependant de prendre en compte plusieurs facteurs importants de la vie réelle :
- Limites de l'API â nous sommes contraints de prendre des donnĂ©es par lots (faire des pauses entre les requĂȘtes, etc.).
- Temps de collecte â pour une analyse et une comparaison complĂštes, il faudra prĂ©voir un temps considĂ©rable simplemente pour que le crawler parcourt le subreddit.
- Le bot doit tourner sur un serveur â vous ne pouvez pas simplement le lancer sur un ordinateur portable, le mettre dans un sac Ă dos et partir faire vos affaires. C'est pourquoi j'ai tout lancĂ© sur un VPS. Avec le code promo habrahabr10, vous pouvez Ă©conomiser encore 10 % du coĂ»t.
- InaccessibilitĂ© physique de certaines donnĂ©es (elles sont visibles pour les admins ou sont trop difficiles Ă collecter) â cela doit ĂȘtre pris en compte, toutes les donnĂ©es ne peuvent pas ĂȘtre collectĂ©es dans un temps raisonnable.
- Erreurs de fonctionnement du réseau : travailler avec le réseau est compliqué.
- Ce sont des donnĂ©es rĂ©elles et vivantes â elles ne sont jamais propres.
Bien sĂ»r, il est nĂ©cessaire de prendre en compte ces nuances dans le dĂ©veloppement. Les heures/jours spĂ©cifiques dĂ©pendent de l'expĂ©rience en dĂ©veloppement ou de l'expĂ©rience sur des tĂąches similaires, nĂ©anmoins nous voyons que cette tĂąche est purement technique et ne nĂ©cessite pas de mouvements supplĂ©mentaires pour ĂȘtre rĂ©solue â tout peut ĂȘtre bien Ă©valuĂ©, dĂ©crit et rĂ©alisĂ©.
Comparaison des sections de Habr
Passons à un cas plus intéressant et non trivial, la comparaison des flux et/ou des sections de Habr.
VĂ©rifions notre liste de contrĂŽle de la complexitĂ© â ici, pour comprendre chaque point, il faudra dĂ©jĂ un peu s'essayer Ă la tĂąche elle-mĂȘme et expĂ©rimenter.
- Au dĂ©but, vous pensez qu'il existe une API, mais il n'y en a pas. Oui, Habr a une API, mais elle n'est accessible qu'aux admins (ou peut-ĂȘtre qu'elle ne fonctionne pas du tout).
- Ensuite, vous commencez simplement Ă parser le html â «import requests», que peut-il mal se passer ?
- Et comment parser, en fait ? L'approche la plus simple et la plus couramment utilisĂ©e consiste Ă itĂ©rer par ID, Ă noter que ce n'est pas forcĂ©ment la plus efficace et qu'il faudra gĂ©rer diffĂ©rents cas â voici par exemple la densitĂ© des ID rĂ©els parmi tous les ID existants.

Extrait de articles. - Les donnĂ©es brutes enveloppĂ©es dans du HTML sur le rĂ©seau sont un vrai casse-tĂȘte. Par exemple, si vous souhaitez collecter et sauvegarder la note d'un article : vous extrayez le score du HTML et dĂ©cidez de le conserver comme un nombre pour un traitement ultĂ©rieur.Â
1) int(score) gĂ©nĂšre une erreur : car sur Habr, le moins, comme dans la ligne "â5" â c'est un tiret court, pas un signe moins (surprenant, n'est-ce pas ?), donc Ă un moment, il a fallu nous redonner vie au parseur avec une solution aussi affreuse.
try: score_txt = post.find(class_="score").text.replace(u"â","-").replace(u"+","+") score = int(score_txt) if check_date(date): post_score += scoreLes dates, les plus et les moins peuvent totalement manquer (comme nous le voyons ci-dessus avec la fonction check_date, et cela s'est produit).
2) Les caractĂšres spĂ©ciaux non Ă©chappĂ©s â ils arriveront, il faut ĂȘtre prĂȘt.
3) La structure varie en fonction du type de post.
4) Les anciens posts peuvent avoir une **structure étrange**.
- En rĂ©alitĂ©, le traitement des erreurs et ce qui peut ou ne peut pas se produire devront ĂȘtre gĂ©rĂ©s et il est impossible de prĂ©voir avec certitude ce qui peut mal tourner et quelle pourrait ĂȘtre la structure, et oĂč cela pourrait Ă©chouer â il faudra juste essayer et prendre en compte les erreurs que le parseur renvoie.
- Puis vous comprenez qu'il faut parser en plusieurs threads sinon le parsing en un seul prendra 30+ heures (c'est purement le temps d'exécution d'un parseur à thread unique, qui dort et n'encourt aucune interdiction). Dans l'article, cela a conduit à un moment donné à schémas comme celui-ci :

Au final, une checklist par rapport à la complexité :
- Travailler avec le réseau et le parsing HTML avec itération et parcours par ID.
- Documents de structure hétérogÚne.
- De nombreux endroits oĂč le code peut facilement Ă©chouer.
- Il est nécessaire d'écrire || du code.
- Documentation manquante, exemples de code et/ou communauté.
L'évaluation conditionnelle du temps pour cette tùche sera de 3 à 5 fois plus élevée que pour la collecte de données sur Reddit.
Comparaison des groupes de Odnoklassniki
Passons au cas techniquement le plus intĂ©ressant parmi ceux dĂ©crits. Pour moi, il Ă©tait fascinant en raison du fait qu'Ă premiĂšre vue, il semble assez trivial, mais il ne l'est pas du tout â dĂšs que vous le poussez avec un bĂąton.
Commençons avec notre checklist de complexité et notons que beaucoup d'entre elles se révéleront beaucoup plus compliquées qu'elles n'en ont l'air au départ :
- L'API existe, mais elle est presque entiÚrement dépourvue des fonctions nécessaires.
- Pour certaines fonctions, il faut demander un accÚs par e-mail, ce qui signifie que l'octroi d'accÚs n'est pas instantané.
- Il est horriblement documentĂ© (pour commencer, les termes russes et anglais s'entremĂȘlent partout, de maniĂšre totalement incohĂ©rente â parfois, il faut simplement deviner ce qui est attendu) et, de plus, il n'est pas conçu pour obtenir des donnĂ©es, par exemple, .
- Il nĂ©cessite une session dans la documentation, mais dans les faits, elle n'est pas utilisĂ©e â et il n'y a aucun moyen de comprendre les subtilitĂ©s des modes d'API, sauf Ă tĂątonner et espĂ©rer que quelque chose fonctionne.
- Il manque des exemples et une communauté, le seul point de référence pour recueillir des informations étant un petit en Python (avec peu d'exemples d'utilisation).
- La solution la plus efficace semble ĂȘtre Selenium, car de nombreuses donnĂ©es nĂ©cessaires sont sous clĂ©.
1) Cela signifie qu'une authentification est effectuée via un utilisateur fictif (et une inscription manuelle).2) Cependant, avec Selenium, aucune garantie de fonctionnement correct et répétable (en tout cas dans le cas de ok.ru, c'est sûr).
3) Le site ok.ru contient des erreurs JavaScript et se comporte parfois de maniÚre étrange et incohérente.
4) Il faut gérer la pagination, le chargement des éléments, etc.
5) Les erreurs d'API renvoyĂ©es par le wrapper devront ĂȘtre traitĂ©es de maniĂšre artisanale, par exemple, comme ceci (un extrait de code expĂ©rimental) :
def get_comments(args, context, discussions): pause = 1 if args.extract_comments: all_comments = set() #makes sense to keep track of already processed discussions for discussion in tqdm(discussions): try: comments = get_comments_from_discussion_via_api(context, discussion) except odnoklassniki.api.OdnoklassnikiError as e: if "NOT_FOUND" in str(e): comments = set() else: print(e) bp() pass all_comments |= comments time.sleep(pause) return all_commentsMon erreur préférée était :
OdnoklassnikiError("Erreur(code: 'None', description: 'Erreur HTTP', method: 'discussions.getComments', params: âŠ)")6) En fin de compte, la combinaison Selenium + API semble ĂȘtre l'option la plus rationnelle.
- Un Ă©tat de conservation et un redĂ©marrage du systĂšme sont nĂ©cessaires, le traitement de nombreuses erreurs, y compris le comportement incohĂ©rent du site â ces erreurs Ă©tant assez difficiles Ă imaginer (si vous ne rĂ©digez pas des parseurs de maniĂšre professionnelle, bien sĂ»r).
L'évaluation conditionnelle du temps pour cette tùche sera de 3 à 5 fois plus élevée que pour la collecte de données depuis Habr. Bien que dans le cas de Habr, nous utilisions une approche directe avec le parsing HTML, alors que dans le cas de OK, nous pouvons intervenir avec l'API dans des endroits critiques.
Conclusions
Peu importe la maniĂšre dont on vous demande une estimation des dĂ©lais « sur place » (aprĂšs tout, nous sommes en phase de planification aujourd'hui !), Ă©valuer le temps de rĂ©alisation d'un module volumineux de pipeline de traitement de donnĂ©es est pratiquement impossible, mĂȘme qualitativement, sans une analyse approfondie des paramĂštres de la tĂąche.
Pour parler de maniÚre un peu plus philosophique, les stratégies d'évaluation en agile conviennent assez bien aux tùches d'ingénierie, mais lorsqu'il s'agit de tùches plus expérimentales et, en quelque sorte, « créatives » et de recherche, c'est-à -dire, moins prévisibles, des difficultés apparaissent, comme dans les exemples que nous avons analysés ici.
Bien sĂ»r, la collecte de donnĂ©es est un exemple illustratif Ă©vident â cette tĂąche paraĂźt habituellement incroyablement simple et techniquement peu complexe, et c'est lĂ que se cache le diable, dans les dĂ©tails. C'est prĂ©cisĂ©ment dans cette tĂąche que l'on peut dĂ©montrer tout le spectre des scĂ©narios oĂč les choses peuvent mal tourner et combien le travail peut rĂ©ellement s'Ă©terniser.
Si l'on jette un Ćil aux caractĂ©ristiques de la tĂąche sans expĂ©rimentations supplĂ©mentaires, Reddit et OK semblent similaires : il y a une API, un wrapper python, mais en rĂ©alitĂ©, la diffĂ©rence est Ă©norme. Sur la base de ces paramĂštres, parser Habr paraĂźt plus complexe que OK â alors qu'en pratique, c'est tout le contraire, et cela peut ĂȘtre dĂ©terminĂ© en menant de simples expĂ©rimentations sur l'analyse des paramĂštres de la tĂąche.
D'aprĂšs mon expĂ©rience, l'approche la plus efficace est de faire une estimation approximative du temps nĂ©cessaire pour la prĂ©-analyse et les premiĂšres expĂ©rimentations, ainsi que pour la lecture de la documentation â c'est cela qui vous permettra de donner une estimation prĂ©cise pour l'ensemble du travail. En termes de mĂ©thodologie agile populaire, je demande Ă ouvrir un ticket pour « l'Ă©valuation des paramĂštres de la tĂąche », sur la base duquel je peux fournir une estimation de ce qui peut ĂȘtre rĂ©alisĂ© dans le cadre d'un « sprint » et donner une estimation plus prĂ©cise pour chaque tĂąche.
Par conséquent, l'argument qui semble le plus efficace est celui qui montre à un spécialiste « non technique » à quel point le temps et les ressources varieront en fonction des paramÚtres qui restent à évaluer.
Source : habr.com

