Outils pour utilisateurs

Outils du site


issue142:python

When do children learn words? This month, we are going to look at a different dataset. The dataset we used last month was, for the most part, pristine and perfect. However, that is not the way things work in the real world. Data will be missing from fields, or might not make sense in the scope of what the data is supposed to be. Many times, the data we really get has missing or bad data that will skew the results. I'm going to try to show you how to use Pandas and Python, how to deal with data without ever having to open the dataset in a spreadsheet even if there are some cells that don't contain good data, using some of the tricks we learned over the last two months, and giving you some new skills at the same time.

Quand les enfants apprennent-ils vraiment des mots ?

Ce mois-ci, nous allons regarder un jeu de données différent. Celui que nous avons utilisé le mois dernier était, en majeure partie, parfait et complet. Cependant, ce n'est pas comme ça que ça marche dans le monde réel. Des données manqueront dans des champs, ou n'auront aucun sens par rapport au sujet que les données sont censées couvrir. Souvent, les données que nous trouvons en fait sont manquantes ou mauvaises et elles faussent les résultats.

Je vais essayer de vous montrer comment utiliser Pandas et Python, comment traiter les données sans jamais devoir ouvrir le jeu de données dans un tableur - même si certaines cellules ne contiennent pas des données correctes -, en utilisant quelques astuces que nous avons apprises dans les deux derniers mois, et en vous donnant en même temps quelques nouvelles compétences.

We'll use a dataset with some missing data. This dataset can be found on kaggle.com under the heading 'When Do Children Learn Words - Information on when Norwegian children generally learn words'. The actual URL is https://www.kaggle.com/rtatman/when-do-children-learn-words. When getting data from web sources, sometimes they give you a good amount of information about the dataset, sometimes not so much. In this case, there is a pretty good writeup about the data. If you look at the tabs just under the picture, you will see that the second tab from the left is titled 'Overview'. That tab has a list of the column names and their content. This information is key to understanding what the data is really about and what we can expect to find. We will discuss the various columns in a moment. You should download the file 'main_data.csv' – the other csv file is optional, we won't be looking at it in this article. If you open 'main_data.csv' in your favorite text editor, you will see something like that shown below.

Nous utiliserons un jeu de données avec des données manquantes. Ce jeu de données peut être trouvé sur kaggle.com sous l'entête « When Do Children Learn Words - Information on when Norwegian children generally learn words » (Quand les enfants apprennent-ils vraiment des mots ? - Informations sur la manière dont les enfants norvégiens apprennent des mots en général.) L'URL véritable est https://www.kaggle.com/rtatman/when-do-children-learn-words. En récupérant des données depuis des sources sur le Web, vous aurez parfois une bonne quantité d'informations à propos du jeu de données, parfois beaucoup moins. Dans notre cas, il y a un assez bon texte sur les données. Si vous regardez les onglets juste sous l'image, vous verrez que le deuxième onglet à partir de la gauche est intitulé « Overview » (Présentation). Cet onglet a une liste des noms des colonnes et de leur contenu. C'est une information-clé pour comprendre ce que couvrent vraiment ces données et ce que nous pouvons espérer trouver. Nous présenterons les différentes colonnes dans un moment. Vous devrez télécharger le fichier « main_data.csv », l'autre fichier csv est optionnel et nous ne le regarderons pas dans cet article.

Si vous ouvrez le fichier « main_data.csv » dans votre éditeur de texte favori, vous verrez quelque chose comme ce qui est présenté ci-dessous.

I'm sure you realize that I'm showing only the first 5 lines of the file here, but it gives you a pretty good idea of what we will be looking at. If you have never looked at a .csv file in a text editor before, you will see that (in this case) the first line shows the names of each column, separated by commas, and that there will be 11 columns of data. You can also scroll down to the bottom and see that there are 732 lines, which means that there are 731 lines (rows) of data. If you look at the fourth line of the file, you will see that the next to last data field has '#N/A' in it instead of a number. You can think of the '#N/A' meaning 'Not Available' or 'Not applicable'. (I prefer the former.) Next page, top right, is the breakdown of the columns and their meanings.

Je suis sûr que vous réalisez que je ne vous ai montré ici que les 5 premières lignes du fichier, mais cela vous donne une idée assez bonne de ce que nous regarderons. Si vous n'avez jamais vu de fichier .csv dans un éditeur de texte, vous verrez que (dans ce cas-ci) la première ligne montre les noms des colonnes, séparés par des virgules, et qu'il y aura 11 colonnes de données. Vous pouvez aussi descendre vers le bas de la liste et voir qu'il y a 732 lignes, ce qui veut dire 731 lignes de données.

Si vous regardez la quatrième ligne du fichier, vous verrez « #N/A » dans l'avant-dernier champ au lieu d'un chiffre. Vous pouvez penser que « #N/A » signifie « Not available » (non disponible) ou « Not applicable » (non applicable). (Je préfère le premier.)

À la page suivante, en haut à droite, sont présentés les entêtes de colonnes et leur signification.

So for this particular article, we will be interested in the following columns… 'Word_NW', 'Translation', 'AoA', 'VSoA', 'Lex_cat', 'Freq', 'CDS_freq' which are the Norwegian word, the English translation, the age of the child when they learn this word, how many other words they generally know, the category of the word, how common the word is in Norwegian, and how common the word is when an adult is talking to a child. Now that we know what we have, and what we are interested in, let's get started. Create a folder for your project and copy the main_data.csv file into it, open a terminal, change directory to that folder, and fire up your Python shell. Now, import pandas like we did last month, and create a DataFrame that we can work with… import pandas as pd csvfile = 'main_data.csv' rawdata = pd.read_csv(csvfile) # Create our beginning basic DataFrame df = pd.DataFrame(rawdata) Now that we have our DataFrame in place, we need to know how “bad” the data is. We can do this with the following Python statement… print(df.isnull().sum(axis=0))

Bien ! Pour cet article précis, nous nous intéresserons aux colonnes suivantes…

« Word_NW », « Translation », « AoA », « VSoA », « Lex_cat », « Freq », « CDS_freq »

où se trouvent le mot norvégien, sa traduction en anglais, l'âge de l'enfant quand il apprend le mot, le nombre d'autres mots qu'il connaît généralement, la catégorie du mot, si ce mot est courant en norvégien et si ce mot est souvent utilisé quand un adulte parle à un enfant.

Maintenant que nous savons ce que nous avons, et ce qui va nous intéresser, allons-y. Créez un répertoire pour votre projet et copiez-y le fichier main_data.csv, ouvrez un terminal, changez pour ce répertoire, et lancez votre shell Python. Maintenant, importez pandas comme vous l'avez fait le mois dernier et créez une DataFrame que nous pourrons utiliser :

import pandas as pd

csvfile = 'main_data.csv'

rawdata = pd.read_csv(csvfile)

# Créer notre DataFrame simple du début

df = pd.DataFrame(rawdata)

Maintenant que notre DataFrame est en place, nous devons connaître jusqu'à quel point les données sont « mauvaises ». Nous pouvons le faire avec la déclaration suivante en Python :

print(df.isnull().sum(axis=0))

I went to the Internet to get an easy way to explain the 'axis' parameter and, thanks to a posting in StackOverflow, the “easy” answer is that axis=0 is data along all rows for each column and axis=1 is data for all columns in each row. So the query means: give me the sum of all null values for each column in our DataFrame. That “query” gives us the following output… ID_CDI_I 341 ID_CDI_II 0 Word_NW 0 Word_CDI 0 Translation 0 AoA 36 VSoA 27 Lex_cat 16 Broad_lex 16 Freq 10 CDS_freq 8 dtype: int64 Now, the next question would be what to do with those null values. We can simply replace the null values with the mean or average of the “real” values in each numerical column we are interested in, and ‘unknown’ in the text column. It WILL skew the data a little bit, but we should be able to live with that.

Je suis allé sur Internet pour trouver une explication simple du paramètre « axis » et, grâce à un message sur StackOverFlow, la réponse « facile » est que axis=0 est l'ensemble des données de toutes les lignes dans chaque colonne et que axis=1 est celui des données de toutes les colonnes dans chaque ligne. Ainsi, la requête signifie : donnez-moi la somme de toutes les valeurs nulles de chaque colonne de notre Dataframe.

Cette « requête » nous donne la sortie suivante :

ID_CDI_I 341 ID_CDI_II 0 Word_NW 0 Word_CDI 0 Translation 0 AoA 36 VSoA 27 Lex_cat 16 Broad_lex 16 Freq 10 CDS_freq 8 dtype: int64

Maintenant, la question suivante est : que faire de ces valeurs nulles ? Nous pouvons simplement remplacer les valeurs nulles par la médiane ou la moyenne des valeurs « utiles » dans chaque colonne numérique qui nous intéresse, et par « inconnu » dans les colonnes de texte. Ça faussera un peu les données, mais nous devrions pouvoir vivre avec.

So, rather than mess with our main DataFrame, we'll create one that contains only the columns we are interested in, then fix the data there. First, we'll create a list of the column names we are interested in… cols_to_use = ['Word_NW','Translation','AoA','VSoA','Lex_cat','Freq','CDS_freq'] Now, create a new DataFrame with just those columns… df2 = df[cols_to_use] print(df2) Next, we can fix our numeric columns that have null data. df2['AoA'].fillna(df2['AoA'].mean(),inplace=True) However, this gives us a warning message… 5434: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame

Aussi, au lieu d'utiliser le bazar qu'est notre Dataframe, nous en créerons une qui ne contient que les colonnes qui nous intéressent, puis nous y résoudrons le problème des données. D'abord, créons une liste des noms de colonnes qui nous intéressent :

cols_to_use = ['Word_NW','Translation','AoA','VSoA','Lex_cat','Freq','CDS_freq']

Maintenant, créons une nouvelle DataFrame avec ces seules colonnes :

df2 = df[cols_to_use]

print(df2)

Ensuite, nous pouvons corriger les valeurs nulles dans les colonnes numériques.

df2['AoA'].fillna(df2['AoA'].mean(),inplace=True)

Cependant, ceci nous donne un avertissement :

5434: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame (Une valeur est en train d'être mise sur une copie d'une partie d'une Dataframe)

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy self._update_inplace(new_data) This is due to what is called a chained assignment. Now, we know this is a copy that we are dealing with, so we can safely thank Pandas for the warning, and run the command again. It will work this time. Now do the rest of the numerical columns… df2['AoA'].fillna(df2['AoA'].mean(),inplace=True) df2['VSoA'].fillna(df2['VSoA'].mean(),inplace=True) df2['Freq'].fillna(df2['Freq'].mean(),inplace=True) df2['CDS_freq'].fillna(df2['CDS_freq'].mean(),inplace=True) And ‘unknown’ in the ‘Lex_cat’ column… df2['Lex_cat'].fillna('unknown',inplace=True) However, if we are running this in script from an IDE, this will fail and only the last 5 commands will work. There is a command that we could use…

Voyez les mises en garde dans la documentation : http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

self._update_inplace(new_data)

Ceci est dû à ce qui est appelé une affectation en chaîne. Nous savons que c'est avec une copie que nous allons travailler ; aussi, nous pouvons sans risque remercier Pandas pour son avertissement, et relancer la commande. Cette fois-ci, elle marche. Maintenant, traitons les colonnes numériques restantes :

df2['AoA'].fillna(df2['AoA'].mean(),inplace=True)

df2['VSoA'].fillna(df2['VSoA'].mean(),inplace=True)

df2['Freq'].fillna(df2['Freq'].mean(),inplace=True)

df2['CDS_freq'].fillna(df2['CDS_freq'].mean(),inplace=True)

Et saisissons « unknown » dans la colonne « lex_cat ».

df2['Lex_cat'].fillna('unknown',inplace=True)

Cependant, si nous lançons ceci dans un script depuis un environnement de développement, il plante et seules les 5 dernières commandes fonctionneront. Il y a une commande que nous pouvons utiliser :

df2.is_copy = False But, it's now deprecated, so it might work today, but not tomorrow. And we get another warning message if we do this… site-packages/pandas/core/generic.py:4388: FutureWarning: Attribute 'is_copy' is deprecated and will be removed in a future version. object.getattribute(self, name) site-packages/pandas/core/generic.py:4389: FutureWarning: Attribute 'is_copy' is deprecated and will be removed in a future version. return object.setattr(self, name, value) Again, it WILL work today, but we don't know for how long. So, the easiest way to work around this is to turn off the warnings all together, again, for use in a script.

df2.is_copy = False

Mais, elle est maintenant obsolète ; elle fonctionnera éventuellement aujourd'hui, mais pas demain. Et nous aurons à nouveau un avertissement si on le fait :

site-packages/pandas/core/generic.py:4388: FutureWarning: Attribute 'is_copy' is deprecated and will be removed in a future version. (L'attribut « is_copy » est obsolète et sera supprimé dans une version future.)

object.__getattribute__(self, name)

site-packages/pandas/core/generic.py:4389: FutureWarning: Attribute 'is_copy' is deprecated and will be removed in a future version.

return object.setattr(self, name, value)

À nouveau, cela fonctionne bien aujourd'hui, mais nous ne savons pas pour combien de temps. Aussi, on peut contourner ce problème simplement en désactivant tous les avertissements si c'est pour une utilisation dans un script.

pd.set_option('mode.chained_assignment', None) That having been said, don't use this command unless you are completely sure you understand it. Finally, let's make sure that we got everything covered by running our sum query again… print(df2.isnull().sum(axis=0)) Word_NW 0 Translation 0 AoA 0 VSoA 0 Lex_cat 0 Freq 0 CDS_freq 0 dtype: int64 Now, finally, we have mostly clean data that we can work with. Make your terminal pretty wide so we can see all our data at one time (next page, top) and let's do our first query of the DataFrame and find out how many words the typical Norwegian child knows by the age of 18 months and what they are…

pd.set_option('mode.chained_assignment', None)

Cela étant dit, n'utilisez pas cette commande à moins que vous ne soyez complètement sûr que vous la comprenez.

Enfin, assurez-vous que nous avons tout traité en lançant à nouveau notre requête de somme :

print(df2.isnull().sum(axis=0))

Word_NW 0 Translation 0 AoA 0 VSoA 0 Lex_cat 0 Freq 0 CDS_freq 0 dtype: int64

Maintenant, enfin, nous avons presque entièrement nettoyé les données avec lesquelles nous voulons travailler. Assurez-vous que votre terminal est grandement ouvert de sorte que vous puissiez voir toutes nos données d'un coup (page suivante, en haut) et faisons notre première requête sur la DataFrame pour découvrir combien de mots, et lesquels, un enfant norvégien typique connaît à l'age de 18 mois :

print(df2[df2.AoA < 18]) That's kind of neat, but it would be better if the output were sorted by the average age column ('AoA' - see next page, bottom). We, can do it this way… print(df2[df2.AoA < 18].sort_values('AoA',ascending=True)) That's much better. So, between the age of 12 and 13 months, the average Norwegian child knows somewhere between 20 and 40 words. If we want to sort it by both the 'AoA' column and then by the 'VSoA' column (page after next, top), we could do it this way… print(df2[df2.AoA < 18].sort_values(['AoA','VSoA'],ascending=True)) So all you Daddies out there can take heart that your name is (on average) the third word a child learns, and don't let the fact that 'vroom' usually comes before you get you down. 'Vroom' is SUCH a fun sound to make.

print(df2[df2.AoA < 18])

C'est plutôt sympa, mais ça serait mieux si la sortie était triée d'après la colonne de l'age moyen (« AoA » - voir page suivante, en bas). Nous pouvons le faire de cette façon :

print(df2[df2.AoA < 18].sort_values('AoA',ascending=True))

C'est beaucoup mieux. Ainsi, entre 12 et 13 mois, l'enfant norvégien moyen connaît entre 20 et 40 mots. Si vous voulez la trier à la fois sur la colonne « AoA » et sur la colonne « VSoA » (2 pages plus loin, en haut), vous pouvez le faire ainsi :

print(df2[df2.AoA < 18].sort_values(['AoA','VSoA'],ascending=True))

Comme ça, vous les papas qui traînez par ici, vous pouvez être rassurés car votre nom est (en moyenne) le troisième mot que l'enfant apprend et le fait que « vroom » vienne avant ne doit pas vous décourager. « Vroom » est un son SI amusant à faire.

To make life easier for you all, I've created a full script that does everything we just did and threw in some wait-for-keypress statements, so you can visualize the data. It is on Pastebin at https://pastebin.com/fb4pH23H I'll leave you with this information and let you experiment on your own. Next time, we'll dust off some of our Page skills and create a GUI that will make it easier to play with data using a very powerful custom widget called 'pandastable'. Until then, have fun and keep learning.

Pour vous simplifier la vie, j'ai créé un script complet qui fait tout ce que nous venons de faire et j'ai mis dedans quelques déclarations attendre-l'appui-d'une-touche, pour que vous puissiez voir les données. C'est sur Pastebin à https://pastebin.com/fb4pH23H

Je vous quitte avec cette information et vous laisse faire vos propres expériences. La prochaine fois, nous allons dépoussiérer quelques-unes de nos connaissances sur Page et créer une interface utilisateur graphique (GUI) qui facilitera les essais sur les données en utilisant un très puissant gadget personnalisé appelé « pandastable ». Jusque-là, amusez-vous bien et continuez à apprendre.

Page 21, encart du haut à droite : Main data ID_CDI_I: Word ID from the Norwegian adaptation of the MacArthur-Bates Communicative Development Inventories, version 1 ID_CDI_II: Word ID from the Norwegian adaptation of the MacArthur-Bates Communicative Development Inventories, version 2 Word_NW: The word in Norwegian Word_CDI: The form of the word found in the Norwegian adaptation of the MacArthur-Bates Communicative Development Inventories Translation: the English translation of the Norwegian word AoA: how old a child generally is was when they learn this word, in months ( Estimated from the MacArthur-Bates Communicative Development Inventories) VSoA: how many other words a child generally knows when they learn this word ( rounded up to the nearest 10) Lex_cat: the specific part of speech of the word Broad_lex: the broad part of speech of the word Freq: a measure of how commonly this word occurs in Norwegian CDS_freq: a measure of how commonly this word occurs when a Norwegian adult is talking to a Norwegian child

Page 21, traduction de l'encart du haut à droite :

Données principales ID_CDI_I: Identifiant de mot dans l'adaptation norvégienne de l'inventaire du développement de la communication de MacArthur-Bates (MacArthur-Bates Communicative Development Inventories), version 1 ID_CDI_II: Identifiant de mot dans l'adaptation norvégienne de l'inventaire du développement de la communication de MacArthur-Bates, version 2 Word_NW: Le mot en norvégien Word_CDI: La forme du mot trouvée dans l'adaptation norvégienne de l'inventaire du développement de la communication de MacArthur-Bates Translation: La traduction en anglais du mot norvégien AoA: L'âge qu'a, en général, un enfant quand il apprend ce mot, en mois (estimation d'après l'inventaire du développement de la communication de MacArthur-Bates) VSoA: Nombre d'autres mots généralement connus d'un enfant quand il apprend ce mot (arrondi à la dizaine supérieure) Lex_cat: La nature grammaticale précise du mot Broad_lex: La catégorie grammaticale du mot Freq: Mesure de la fréquence d'apparition de ce mot en norvégien CDS_freq: Mesure de la fréquence d'apparition de ce mot quand un adulte norvégien parle à un enfant norvégien

issue142/python.txt · Dernière modification : 2019/03/06 17:42 de andre_domenech