Cadres de données avec le logiciel R

Comme pour les listes, vous pouvez utiliser les fonctions 1app1y et sappliy avec les images de données.


Utilisation de lapply () et sapply () sur les cadres de données
Gardez à l'esprit que les trames ou cadres de données sont des cas particuliers de listes, les composantes de la liste étant constituées des colonnes de la trame de données. Ainsi, si vous appelez lapply () sur un cadre de données avec une fonction f () spécifiée, alors f () sera appelé sur chacune des colonnes de la trame, avec les valeurs de retour placées dans une liste.
Par exemple, avec notre exemple précédent, nous pouvons utiliser lapply comme suit:

  1. > d
  2. kids ages
  3. 1 Jack 12
  4. 2 Jill 10
  5. > dl <- lapply(d,sort)
  6. > dl
  7. $kids
  8. [1] "Jack" "Jill"
  9. $ages
  10. [1] 10 12
Source code

Donc, dl est une liste composée de deux vecteurs, les versions triées des enfants et des âges.
Notez que dl est juste une liste, pas une image de données. Nous pourrions le contraindre à un cadre de données, comme ceci:

  1. kids ages
  2. 1 Jack 10
  3. 2 Jill 12
Source code

Mais cela n'aurait aucun sens, car la correspondance entre les noms et les âges a été perdue. Jack, par exemple, est maintenant classé comme 10 ans au lieu de 12. (Mais si nous voulions trier le cadre de données par rapport à l'une des colonnes, en préservant les correspondances, nous pourrions suivre l'approche présentée à la page 135.)

Dans le monde de la base de données relationnelle, l'une des opérations les plus importantes est celle d'une jointure, dans laquelle deux tables peuvent être combinées selon les valeurs d'une variable commune. Dans R, deux trames de données peuvent être combinées de manière similaire à l'aide de la fonction merge().
La forme la plus simple est la suivante:

  1. merge(x,y)
Source code
Cela fusionne les images x et y. Il suppose que les deux trames de données ont une ou plusieurs colonnes avec des noms en commun. Voici un exemple:

  1. > d1
  2. kids states
  3. 1 Jack CA
  4. 2 Jill MA
  5. 3 Jillian MA
  6. 4 John HI
  7. > d2
  8. ages kids
  9. 1 10 Jill
  10. 2 7 Lillian
  11. 3 12 Jack
  12. > d <- merge(d1,d2)
  13. > d
  14. kids states ages
  15. 1 Jack CA 12
  16. 2 Jill MA 10
Source code

Ici, les deux cadres de données ont en commun les enfants comme variables. R a trouvé les lignes dans lesquelles cette variable avait la même valeur d'enfants dans les deux cadres de données (ceux de Jack et Jill). Il a ensuite créé un cadre de données avec des lignes correspondantes et avec des colonnes issues de cadres de données (enfants, états et âges).
La fonction merge() a nommé les arguments by.x et by.y qui gèrent les cas dans lesquels les variables ont des informations similaires mais des noms différents dans les deux trames de données. Voici un exemple:

  1. > d3
  2. ages pals
  3. 1 12 Jack
  4. 2 10 Jill
  5. 3 7 Lillian
  6. > merge(d1,d3,by.x="kids",by.y="pals")
  7. kids states ages
  8. 1 Jack CA 12
  9. 2 Jill MA 10
Source code
Même si notre variable s'appelait les enfants dans un cadre de données et les pals dans l'autre, il était destiné à stocker la même information, et donc la fusion avait du sens.
Les correspondances en double apparaîtront pleinement dans le résultat, éventuellement de manière non souhaitable.

  1. > d1
  2. kids states
  3. 1 Jack CA
  4. 2 Jill MA
  5. 3 Jillian MA
  6. 4 John HI
  7. > d2a <- rbind(d2,list(15,"Jill"))
  8. > d2a
  9. ages kids
  10. 1 12 Jack
  11. 2 10 Jill
  12. 3 7 Lillian
  13. 4 15 Jill
  14. > merge(d1,d2a)
  15. kids states ages
  16. 1 Jack CA 12
  17. 2 Jill MA 10
  18. 3 Jill MA 15
Source code

Il y a deux Jills dans d2a. Il y a un Jill dans d1 qui vit à Massachu -setts et un autre Jill avec une résidence inconnue. Dans notre exemple précédent, merge (d1, d2), il n'y avait qu'un Jill, qui a été supposé être le même dans les deux cadres de données. Mais ici, dans la fusion de l'appel (d1, d2a), il se pourrait que l'un des Jills soit un résident du Massachusetts. Il ressort clairement de ce petit exemple que vous devez choisir les variables correspondantes avec beaucoup de soin.

 

 

Exemple étendu: une base de données sur les employés
Voici une adaptation de l'un de mes projets de consultation. Il s'agissait de savoir si les travailleurs âgés étaient aussi nombreux que les plus jeunes. J'ai eu des données sur plusieurs variables, telles que l'âge et les notes de rendement, que j'ai utilisées dans ma comparaison des employés plus âgés et plus jeunes. J'ai également eu des numéros d'identification des employés, ce qui était crucial pour pouvoir connecter les deux fichiers de données: DA et DB.
Le fichier DA avait cet en-tête:
  1. "EmpID","Perf 1","Perf 2","Perf 3","Job Title"
Source code
Ce sont les noms de l'ID de l'employé, trois notes de performance et le titre du poste. DB n'avait pas d'en-tête. Les variables ont de nouveau commencé avec l'ID, suite aux dates de début et de fin d'emploi.
Les deux fichiers étaient au format CSV. Une partie de ma phase de nettoyage des données consistait à vérifier que chaque enregistrement contenait le nombre approprié de champs. DA, par exemple, devrait avoir cinq champs par enregistrement. Voici le contrôle:
  1. > count.fields ("DA", sep = ",")
  2. [1] 5555555555555555555555555555555555
  3. 5 5 5 5
  4. ...
Source code
Ici, j'ai précisé que le dossier DA avait des champs séparés par des virgules. La fonction a ensuite signalé le nombre de champs dans chaque enregistrement du fichier, ce qui, heureusement, était de 5 s.
J'aurais pu utiliser all () pour vérifier cela, plutôt que de le vérifier visuellement, via cet appel:
  1. all(count.fields("DA",sep=",") >= 5)
Source code
Une valeur de retour de TRUE signifierait que tout va bien. Alternativement, j'aurais pu utiliser ce formulaire:
  1. table(count.fields("DA",sep=","))
Source code
Je voudrais alors compter le nombre d'enregistrements avec cinq champs, quatre champs, six champs, etc.
Après cette vérification, j'ai ensuite lu dans les fichiers en tant que données:
  1. da <- read.csv("DA",header=TRUE,stringsAsFactors=FALSE)
  2. db <- read.csv("DB",header=FALSE,stringsAsFactors=FALSE)
Source code
Je voulais vérifier les éventuelles erreurs d'orthographe dans les différents champs, alors j'ai exécuté le code suivant:
  1. for (col in 1:6)
Source code
Cela m'a donné une liste des valeurs distinctes dans chaque colonne afin que je puisse explorer visuellement les mauvaises orthographes.
J'avais besoin de fusionner les deux trames de données, correspondant à l'ID de l'employé, alors j'ai exécuté le code suivant:
  1. mrg <- merge(da,db,by.x=1,by.y=1)
Source code
J'ai précisé que la première colonne serait la variable de fusion dans les deux cas. (Comme on l'a remarqué plus tôt, j'aurais aussi pu utiliser les noms de champs plutôt que les chiffres ici.)

 

 

 

Diverses opérations matricielles s'appliquent également aux cadres de données. Plus particulièrement et d'une manière utile, nous pouvons faire un filtrage pour extraire différents cadres de sous-données intéressants.


5.2.1 Extraction de cadres de sous-données
Comme mentionné, un cadre de données peut être visualisé en termes de lignes et de colonnes. En particulier, nous pouvons extraire des images de sous-données par des lignes ou des colonnes. Voici un exemple:

  1. > examsquiz[2:5,]
  2. Exam.1 Exam.2 Quiz
  3. 2 3.3 2 3.7
  4. 3 4.0 4 4.0
  5. 4 2.3 0 3.3
  6. 5 2.3 1 3.3
  7. > examsquiz[2:5,2]
  8. [1] 2 4 0 1
  9. > class(examsquiz[2:5,2])
  10. [1] "numeric"
  11. > examsquiz[2:5,2,drop=FALSE]
  12. Exam.2
  13. 2 2
  14. 3 4
  15. 4 0
  16. 5 1
  17. > class(examsquiz[2:5,2,drop=FALSE])
  18. [1] "data.frame"
Source code

Notez que dans ce deuxième appel, puisque examsquiz [2: 5,2] est un vecteur, R a créé un vecteur au lieu d'un autre cadre de données. En spécifiant drop = FALSE, comme décrit pour le cas matriciel à la section 3.6, nous pouvons le conserver en tant que cadre de données (une colonne). Nous pouvons également faire un filtrage. Voici comment extraire le sous-châssis de tous les élèves dont le premier résultat de l'examen était d'au moins 3,8:

  1. > examsquiz [examsquiz $ Exam.1> = 3.8,]
  2. Exam.1 Exam.2 Quiz
  3. 3 4 4.0 4.0
  4. 9 4 3.3 4.0
  5. 11 4 4.0 4.0
  6. 14 4 0.0 4.0
  7. 16 4 3.7 4.0
  8. 19 4 4.0 4.0
  9. 22 4 4.0 4.0
  10. 25 4 4,0 3,3
  11. 29 4 3.0 3.7
Source code

 

5.2.2 Plus sur le traitement des valeurs NA
Supposons que le deuxième score d'examen pour le premier étudiant ait été manquant. Ensuite, nous aurions tapé ce qui suit dans cette ligne lorsque nous préparions le fichier de données:

  1. 2.0 NA 4.0
Source code
Dans toutes les analyses statistiques ultérieures, R ferait de son mieux pour faire face aux données manquantes. Cependant, dans certaines situations, nous devons définir l'option na.rm = TRUE, expliquant explicitement à R d'ignorer les valeurs de NA. Par exemple, avec le score d'examen manquant, le calcul du score moyen sur l'examen 2 en appelant la fonction moyenne (R) de R sauterait le premier étudiant dans la recherche de la moyenne. Sinon, R signalerait simplement NA pour la moyenne.
Voici un petit exemple:
  1. > x <- c(2,NA,4)
  2. > mean(x)
  3. [1] NA
  4. > mean(x,na.rm=TRUE)
  5. [1] 3
Source code

Dans la section 2.8.2, vous avez été présenté à la fonction subset(), ce qui vous permet de ne pas spécifier na.rm = TRUE. Vous pouvez l'appliquer dans des images de données pour la sélection des lignes. Les noms des colonnes sont pris dans le contexte du cadre de données donné. Dans notre exemple, au lieu de taper ceci:

  1. > examsquiz[examsquiz$Exam.1 >= 3.8,]
Source code
nous pourrions exécuter ceci:
  1. > subset(examsquiz,Exam.1 >= 3.8)
Source code
Notez que nous n'avons pas besoin d'écrire ceci:
  1. > subset(examsquiz,examsquiz$Exam.1 >= 3.8)
Source code
Dans certains cas, nous voudrions peut-être débarrasser notre cadre de données de toute observation ayant au moins une valeur de NA. Une fonction pratique à cette fin est complete.cases ().
  1. > d4
  2. kids states
  3. 1 Jack CA
  4. 2 <NA> MA
  5. 3 Jillian MA
  6. 4 John <NA>
  7. [1] TRUE FALSE TRUE FALSE
  8. > d5 <- d4[complete.cases(d4),]
  9. > d5
  10. kids states
  11. 1 Jack CA
  12. 3 Jillian MA
Source code
Les cas 2 et 4 étaient incomplets; d'où les valeurs FALSE dans la sortie de comp1ete.cases (d4). Nous utilisons ensuite cette sortie pour sélectionner les lignes intactes.

 

 

3 Utilisation des fonctions bb () et cbind () et fonctions alternatives
Les fonctions de matrice rbind () et cbind () introduites dans la section 3.4 fonctionnent également avec des images de données, à condition que vous ayez des tailles compatibles, bien sûr. Par exemple, vous pouvez utiliser cbind () pour ajouter une nouvelle colonne qui a la même longueur que les colonnes existantes.
En utilisant rbind () pour ajouter une ligne, la ligne ajoutée se présente généralement sous la forme d'un autre cadre ou liste de données.

  1. > d
  2. kids ages
  3. 1 Jack 12
  4. 2 Jill 10
  5. > rbind(d,list("Laura",19))
  6. kids ages
  7. 1 Jack 12
  8. 2 Jill 10
  9. 3 Laura 19
Source code

Vous pouvez également créer de nouvelles colonnes des anciennes. Par exemple, nous pouvons ajouter une variable qui est la différence entre les examens 1 et 2:

  1. > eq <- cbind(examsquiz,examsquiz$Exam.2-examsquiz$Exam.1)
  2. > class(eq)
  3. [1] "data.frame"
  4. > head(eq)
  5. Exam.1 Exam.2 Quiz examsquiz$Exam.2 - examsquiz$Exam.1
  6. 1 2.0 3.3 4.0 1.3
  7. 2 3.3 2.0 3.7 -1.3
Source code

Le nouveau nom est assez difficile à gérer: il est long et il a des espaces blancs intégrés. Nous pourrions le modifier en utilisant la fonction names (), mais il serait mieux d'exploiter la base de données de la base de données et d'ajouter une colonne  à la trame de données pour ce résultat:

  1. > examsquiz$ExamDiff <- examsquiz$Exam.2 - examsquiz$Exam.1
  2. > head(examsquiz)
  3. Exam.1 Exam.2 Quiz ExamDiff
  4. 1 2.0 3.3 4.0 1.3
  5. 2 3.3 2.0 3.7 -1.3
  6. 3 4.0 4.0 4.0 0.0
  7. 4 2.3 0.0 3.3 -2.3
  8. 5 2.3 1.0 3.3 -1.3
  9. 6 3.3 3.7 4.0 0.4
Source code

Que s'est-il passé ici? Étant donné que l'on peut ajouter un nouveau composant à une liste déjà existante à tout moment, nous l'avons fait: Nous avons ajouté un composant ExamDiff à la liste / cadre de données examensquiz.
Nous pouvons même exploiter le recyclage pour ajouter une colonne qui a une longueur différente de celle du cadre de données:

  1. > d
  2. kids ages
  3. 1 Jack 12
  4. 2 Jill 10
  5. > d$one <- 1
  6. > d
  7. kids ages one
  8. 1 Jack 12 1
  9. 2 Jill 10 1
Source code

4 La fonction apply ()
Vous pouvez utiliser apply () sur les trames de données, si les colonnes sont toutes du même type. Par exemple, nous pouvons trouver la note maximale pour chaque élève, comme suit:

  1. > apply(examsquiz,1,max)
  2. [1] 4.0 3.7 4.0 3.3 3.3 4.0 3.7 3.3 4.0 4.0 4.0 3.3 4.0 4.0 3.7 4.0 3.3 3.7 4.0
  3. [20] 3.7 4.0 4.0 3.3 3.3 4.0 4.0 3.3 3.3 4.0 3.7 3.3 3.3 3.7 2.7 3.3 4.0 3.7 3.7
  4. [39] 3.7
Source code


 

 

Pour commencer, regardons l’exemple suivant:

  1. > kids <- c("Jack","Jill")
  2. > ages <- c(12,10)
  3. > d <- data.frame(kids,ages,stringsAsFactors=FALSE)
  4. > d # matrix-like viewpoint
  5. kids ages
  6. 1 Jack 12
  7. 2 Jill 10
Source code

Les deux premiers arguments dans la fonction data.frame () sont clairs (nous souhaitons produire un cadre de données avec nos deux vecteurs: les enfants et les âges). Cependant, le troisième argument, stringsAsFactors = FALSE nécessite plus de commentaires. Si l'argument nommé stringsAsFactors n'est pas spécifié, par défaut StringsAsFactors sera TRUE. Cela signifie que si nous créons un cadre de données, R va le convertir en un facteur. Nous allons définir stringsAsFactors à FALSE parce que notre  travail avec les données de caractères sera généralement avec des vecteurs et non des facteurs. Nous allons couvrir les facteurs au prochain chapitre.


1 Accès aux cadres de données
Maintenant que nous avons un cadre de données, explorons un peu. Puisque d est une liste, nous pouvons extraire les éléments:

  1. > kids <- c("Jack","Jill")
  2. > ages <- c(12,10)
  3. > d <- data.frame(kids,ages,stringsAsFactors=FALSE)
  4. > d # point de vue matriciel
  5. kids ages
  6. 1 Jack 12
  7. 2 Jill 10
Source code

Mais nous pouvons le traiter de manière matricielle aussi. Par exemple, nous pouvons voir la colonne 1:
  1. > d [, 1]
  2. [1] "Jack" "Jill"
Source code

Cette qualité semblable à une matrice est également observée lorsque nous supprimons d en utilisant str ():

  1. > str(d)
  2. 'data.frame': 2 obs. of 2 variables:
  3. $ kids: chr "Jack" "Jill"
  4. $ ages: num 12 10
Source code

R nous dit ici que d se compose de deux observations. Envisagez trois façons d'accéder à la première colonne de notre cadre de données ci-dessus: d [[1]], d [, 1] et d $ kids. Parmi ceux-ci, le troisième serait généralement considéré comme étant plus clair et, plus important encore, plus sûr que les deux premiers. Cela identifie mieux la colonne et rend moins probable que vous fassiez référence à la mauvaise colonne. Mais, en écriture, le code général, par exemple, l'écriture des paquets R, la notation matricielle d [, 1] est nécessaire, et il est particulièrement pratique si vous extrayez des images sous-données (comme vous le verrez lorsque nous parlons d'extraire des images de sous-données dans Section 5.2).


5.1.2 Exemple étendu: Analyse de régression des notes d'examen Suite
Rappelons nos données d'examen de cours dans la section 1.5. Là, nous n'avons pas d'en-tête, mais pour cet exemple, nous faisons, et les premiers enregistrements dans le fichier sont les suivants:
Quiz "examen 2" examen "examen 2"
2.0 3.3 4.0
3.3 2.0 3.7
4.0 4.0 4.0
2,3 0,0 3,3
2,3 1,0 3,3
3.3 3.7 4.0

 

Comme vous pouvez le voir, chaque ligne contient les trois résultats de tests pour un étudiant. C'est la notion classique de fichier bidimensionnel, comme cela a été mentionné dans la sortie précédente de str (). Ici, chaque ligne de notre fichier contient les données pour une observation dans un ensemble de données statistiques. L'idée d'un cadre de données est d'encapsuler ces données, ainsi que des noms de variables, en un seul objet.
Notez que nous avons séparé les champs ici par des espaces. D'autres délimiteurs peuvent être spécifiés, notamment des virgules pour les fichiers de valeur séparée par des virgules (CSV) (comme vous le verrez dans la section 5). Les noms de variables spécifiés dans le premier enregistrement doivent être séparés par le même délimiteur utilisé pour les données, ce qui est un espace dans ce cas. Si les noms eux-mêmes contiennent des espaces intégrés, comme nous l'avons fait ici, ils doivent être cités.
Nous lisons dans le fichier comme précédemment, mais dans ce cas, nous déclarons qu'il y a un enregistrement d'en-tête:

  1. examsquiz <- read.table ("examens", header = TRUE)
Source code
Les noms des colonnes apparaissent maintenant, avec des périodes remplaçant les blancs:

  1. > head (examsquiz) Exam.1 Exam.2 Quiz
  2. 1 2.0 3.3 4.0
  3. 2 3.3 2.0 3.7
  4. 3 4.0 4.0 4.0
  5. 4 2,3 0,0 3,3
  6. 5 2,3 1,0 3,3
  7. 6 3.3 3.7 4.0
Source code