טרנספורמציה של נתונים

כפי שראינו בחלק הראשון חלק ניכר מהעבודה של Data Scientists הוא ניקוי וסידור נתונים. חבילות dplyr, tidyr, נבנו כדי לספק סט כלים רחב שמסייע בכלל פעילויות אלו, באופן אינטואיטיבי ויעיל, חבילות אלו הן חלק ממכלול tidyverse איתו עבדנו גם בפרקים הקודמים.

גיליון ה-Cheatsheet שילווה אותנו בחלק זה נמצא בקישור הבא: https://github.com/rstudio/cheatsheets/raw/master/data-transformation.pdf

ראשית, נטען חבילות אלו ונקרא את קובץ הנתונים עמו עבדנו בפרקים הקודמים.

# You can specifically call the two:
#library(dplyr)
#library(tidyr)
# But I usually load tidyverse which takes care of everything:
library(tidyverse)

kaggle.survey17 <- readr::read_csv("data-files/kaggle-survey-2017/multipleChoiceResponses.csv")

glimpse(kaggle.survey17)
## Observations: 16,716
## Variables: 228
## $ GenderSelect                                <chr> "Non-binary, gende...
## $ Country                                     <chr> NA, "United States...
## $ Age                                         <int> NA, 30, 28, 56, 38...
## $ EmploymentStatus                            <chr> "Employed full-tim...
## $ StudentStatus                               <chr> NA, NA, NA, NA, NA...
## $ LearningDataScience                         <chr> NA, NA, NA, NA, NA...
## $ CodeWriter                                  <chr> "Yes", NA, NA, "Ye...
## $ CareerSwitcher                              <chr> NA, NA, NA, NA, NA...
## $ CurrentJobTitleSelect                       <chr> "DBA/Database Engi...
## $ TitleFit                                    <chr> "Fine", NA, NA, "P...
## $ CurrentEmployerType                         <chr> "Employed by a com...
## $ MLToolNextYearSelect                        <chr> "SAS Base", "Pytho...
## $ MLMethodNextYearSelect                      <chr> "Random Forests", ...
## $ LanguageRecommendationSelect                <chr> "F#", "Python", "R...
## $ PublicDatasetsSelect                        <chr> "Dataset aggregato...
## $ LearningPlatformSelect                      <chr> "College/Universit...
## $ LearningPlatformUsefulnessArxiv             <chr> NA, NA, "Very usef...
## $ LearningPlatformUsefulnessBlogs             <chr> NA, NA, NA, "Very ...
## $ LearningPlatformUsefulnessCollege           <chr> NA, NA, "Somewhat ...
## $ LearningPlatformUsefulnessCompany           <chr> NA, NA, NA, NA, NA...
## $ LearningPlatformUsefulnessConferences       <chr> "Very useful", NA,...
## $ LearningPlatformUsefulnessFriends           <chr> NA, NA, NA, "Very ...
## $ LearningPlatformUsefulnessKaggle            <chr> NA, "Somewhat usef...
## $ LearningPlatformUsefulnessNewsletters       <chr> NA, NA, NA, NA, NA...
## $ LearningPlatformUsefulnessCommunities       <chr> NA, NA, NA, NA, NA...
## $ LearningPlatformUsefulnessDocumentation     <chr> NA, NA, NA, "Very ...
## $ LearningPlatformUsefulnessCourses           <chr> NA, NA, "Very usef...
## $ LearningPlatformUsefulnessProjects          <chr> NA, NA, NA, "Very ...
## $ LearningPlatformUsefulnessPodcasts          <chr> "Very useful", NA,...
## $ LearningPlatformUsefulnessSO                <chr> NA, NA, NA, NA, NA...
## $ LearningPlatformUsefulnessTextbook          <chr> NA, NA, NA, NA, "S...
## $ LearningPlatformUsefulnessTradeBook         <chr> "Somewhat useful",...
## $ LearningPlatformUsefulnessTutoring          <chr> NA, NA, NA, NA, NA...
## $ LearningPlatformUsefulnessYouTube           <chr> NA, NA, "Very usef...
## $ BlogsPodcastsNewslettersSelect              <chr> "Becoming a Data S...
## $ LearningDataScienceTime                     <chr> NA, "1-2 years", "...
## $ JobSkillImportanceBigData                   <chr> NA, NA, "Necessary...
## $ JobSkillImportanceDegree                    <chr> NA, "Nice to have"...
## $ JobSkillImportanceStats                     <chr> NA, "Unnecessary",...
## $ JobSkillImportanceEnterpriseTools           <chr> NA, NA, NA, NA, NA...
## $ JobSkillImportancePython                    <chr> NA, "Unnecessary",...
## $ JobSkillImportanceR                         <chr> NA, NA, "Necessary...
## $ JobSkillImportanceSQL                       <chr> NA, "Necessary", N...
## $ JobSkillImportanceKaggleRanking             <chr> NA, NA, NA, NA, NA...
## $ JobSkillImportanceMOOC                      <chr> NA, NA, NA, NA, NA...
## $ JobSkillImportanceVisualizations            <chr> NA, NA, NA, NA, NA...
## $ JobSkillImportanceOtherSelect1              <chr> NA, NA, NA, NA, NA...
## $ JobSkillImportanceOtherSelect2              <chr> NA, NA, NA, NA, NA...
## $ JobSkillImportanceOtherSelect3              <chr> NA, NA, NA, NA, NA...
## $ CoursePlatformSelect                        <chr> NA, NA, "Coursera,...
## $ HardwarePersonalProjectsSelect              <chr> NA, NA, "Basic lap...
## $ TimeSpentStudying                           <chr> NA, "2 - 10 hours"...
## $ ProveKnowledgeSelect                        <chr> NA, "Master's degr...
## $ DataScienceIdentitySelect                   <chr> "Yes", "Yes", "Yes...
## $ FormalEducation                             <chr> "Bachelor's degree...
## $ MajorSelect                                 <chr> "Management inform...
## $ Tenure                                      <chr> "More than 10 year...
## $ PastJobTitlesSelect                         <chr> "Predictive Modele...
## $ FirstTrainingSelect                         <chr> "University course...
## $ LearningCategorySelftTaught                 <int> 0, 10, 20, 30, 60,...
## $ LearningCategoryOnlineCourses               <int> 0, 30, 50, 0, 5, 2...
## $ LearningCategoryWork                        <int> 100, 0, 0, 40, 5, ...
## $ LearningCategoryUniversity                  <dbl> 0, 30, 30, 30, 30,...
## $ LearningCategoryKaggle                      <dbl> 0, 30, 0, 0, 0, 10...
## $ LearningCategoryOther                       <int> 0, 0, 0, 0, 0, 0, ...
## $ MLSkillsSelect                              <chr> "Computer Vision,N...
## $ MLTechniquesSelect                          <chr> "Evolutionary Appr...
## $ ParentsEducation                            <chr> "A doctoral degree...
## $ EmployerIndustry                            <chr> "Internet-based", ...
## $ EmployerSize                                <chr> "100 to 499 employ...
## $ EmployerSizeChange                          <chr> "Increased slightl...
## $ EmployerMLTime                              <chr> "3-5 years", NA, N...
## $ EmployerSearchMethod                        <chr> "I visited the com...
## $ UniversityImportance                        <chr> "Not very importan...
## $ JobFunctionSelect                           <chr> "Build prototypes ...
## $ WorkHardwareSelect                          <chr> "Gaming Laptop (La...
## $ WorkDataTypeSelect                          <chr> "Text data,Relatio...
## $ WorkProductionFrequency                     <chr> "Rarely", NA, NA, ...
## $ WorkDatasetSize                             <chr> "10GB", NA, NA, "1...
## $ WorkAlgorithmsSelect                        <chr> "Neural Networks,R...
## $ WorkToolsSelect                             <chr> "Amazon Web servic...
## $ WorkToolsFrequencyAmazonML                  <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyAWS                       <chr> "Rarely", NA, NA, ...
## $ WorkToolsFrequencyAngoss                    <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyC                         <chr> NA, NA, NA, NA, "M...
## $ WorkToolsFrequencyCloudera                  <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyDataRobot                 <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyFlume                     <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyGCP                       <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyHadoop                    <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyIBMCognos                 <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyIBMSPSSModeler            <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyIBMSPSSStatistics         <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyIBMWatson                 <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyImpala                    <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyJava                      <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyJulia                     <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyJupyter                   <chr> NA, NA, NA, NA, "S...
## $ WorkToolsFrequencyKNIMECommercial           <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyKNIMEFree                 <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyMathematica               <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyMATLAB                    <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyAzure                     <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyExcel                     <chr> NA, NA, NA, "Somet...
## $ WorkToolsFrequencyMicrosoftRServer          <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyMicrosoftSQL              <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyMinitab                   <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyNoSQL                     <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyOracle                    <chr> "Sometimes", NA, N...
## $ WorkToolsFrequencyOrange                    <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyPerl                      <chr> "Most of the time"...
## $ WorkToolsFrequencyPython                    <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyQlik                      <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyR                         <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyRapidMinerCommercial      <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyRapidMinerFree            <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencySalfrod                   <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencySAPBusinessObjects        <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencySASBase                   <chr> NA, NA, NA, "Somet...
## $ WorkToolsFrequencySASEnterprise             <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencySASJMP                    <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencySpark                     <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencySQL                       <chr> NA, NA, NA, "Often...
## $ WorkToolsFrequencyStan                      <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyStatistica                <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyTableau                   <chr> NA, NA, NA, "Rarel...
## $ WorkToolsFrequencyTensorFlow                <chr> NA, NA, NA, NA, "S...
## $ WorkToolsFrequencyTIBCO                     <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencyUnix                      <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencySelect1                   <chr> NA, NA, NA, NA, NA...
## $ WorkToolsFrequencySelect2                   <chr> NA, NA, NA, NA, NA...
## $ WorkFrequencySelect3                        <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsSelect                           <chr> "Association Rules...
## $ `WorkMethodsFrequencyA/B`                   <chr> NA, NA, NA, "Somet...
## $ WorkMethodsFrequencyAssociationRules        <chr> "Rarely", NA, NA, ...
## $ WorkMethodsFrequencyBayesian                <chr> NA, NA, NA, "Somet...
## $ WorkMethodsFrequencyCNNs                    <chr> NA, NA, NA, NA, "M...
## $ WorkMethodsFrequencyCollaborativeFiltering  <chr> "Often", NA, NA, N...
## $ `WorkMethodsFrequencyCross-Validation`      <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencyDataVisualization       <chr> NA, NA, NA, "Somet...
## $ WorkMethodsFrequencyDecisionTrees           <chr> NA, NA, NA, "Often...
## $ WorkMethodsFrequencyEnsembleMethods         <chr> NA, NA, NA, "Somet...
## $ WorkMethodsFrequencyEvolutionaryApproaches  <chr> NA, NA, NA, NA, "S...
## $ WorkMethodsFrequencyGANs                    <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencyGBM                     <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencyHMMs                    <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencyKNN                     <chr> NA, NA, NA, NA, "M...
## $ WorkMethodsFrequencyLiftAnalysis            <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencyLogisticRegression      <chr> NA, NA, NA, "Somet...
## $ WorkMethodsFrequencyMLN                     <chr> NA, NA, NA, "Often...
## $ WorkMethodsFrequencyNaiveBayes              <chr> NA, NA, NA, "Somet...
## $ WorkMethodsFrequencyNLP                     <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencyNeuralNetworks          <chr> "Sometimes", NA, N...
## $ WorkMethodsFrequencyPCA                     <chr> "Often", NA, NA, N...
## $ WorkMethodsFrequencyPrescriptiveModeling    <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencyRandomForests           <chr> "Most of the time"...
## $ WorkMethodsFrequencyRecommenderSystems      <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencyRNNs                    <chr> NA, NA, NA, NA, "S...
## $ WorkMethodsFrequencySegmentation            <chr> NA, NA, NA, NA, "O...
## $ WorkMethodsFrequencySimulation              <chr> NA, NA, NA, "Often...
## $ WorkMethodsFrequencySVMs                    <chr> NA, NA, NA, NA, "M...
## $ WorkMethodsFrequencyTextAnalysis            <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencyTimeSeriesAnalysis      <chr> NA, NA, NA, "Often...
## $ WorkMethodsFrequencySelect1                 <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencySelect2                 <chr> NA, NA, NA, NA, NA...
## $ WorkMethodsFrequencySelect3                 <chr> NA, NA, NA, NA, NA...
## $ TimeGatheringData                           <int> 0, NA, NA, 50, 30,...
## $ TimeModelBuilding                           <int> 100, NA, NA, 20, 2...
## $ TimeProduction                              <int> 0, NA, NA, 0, 15, ...
## $ TimeVisualizing                             <int> 0, NA, NA, 10, 15,...
## $ TimeFindingInsights                         <int> 0, NA, NA, 20, 20,...
## $ TimeOtherSelect                             <int> 0, NA, NA, 0, 0, 0...
## $ AlgorithmUnderstandingLevel                 <chr> "Enough to explain...
## $ WorkChallengesSelect                        <chr> "Company politics ...
## $ WorkChallengeFrequencyPolitics              <chr> "Rarely", NA, NA, ...
## $ WorkChallengeFrequencyUnusedResults         <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyUnusefulInstrumenting <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDeployment            <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDirtyData             <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyExplaining            <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyPass                  <chr> NA, NA, NA, NA, NA...
## $ WorkChallengeFrequencyIntegration           <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyTalent                <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDataFunds             <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDomainExpertise       <chr> NA, NA, NA, "Most ...
## $ WorkChallengeFrequencyML                    <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyTools                 <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyExpectations          <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyITCoordination        <chr> NA, NA, NA, NA, "S...
## $ WorkChallengeFrequencyHiringFunds           <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyPrivacy               <chr> "Often", NA, NA, "...
## $ WorkChallengeFrequencyScaling               <chr> "Most of the time"...
## $ WorkChallengeFrequencyEnvironments          <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyClarity               <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDataAccess            <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyOtherSelect           <chr> NA, NA, NA, NA, NA...
## $ WorkDataVisualizations                      <chr> "26-50% of project...
## $ WorkInternalVsExternalTools                 <chr> "Do not know", NA,...
## $ WorkMLTeamSeatSelect                        <chr> "Standalone Team",...
## $ WorkDatasets                                <chr> NA, NA, NA, "Elect...
## $ WorkDatasetsChallenge                       <chr> NA, NA, NA, "Every...
## $ WorkDataStorage                             <chr> "Document-oriented...
## $ WorkDataSharing                             <chr> "Company Developed...
## $ WorkDataSourcing                            <chr> NA, NA, NA, NA, NA...
## $ WorkCodeSharing                             <chr> "Mercurial,Subvers...
## $ RemoteWork                                  <chr> "Always", NA, NA, ...
## $ CompensationAmount                          <chr> NA, NA, NA, "250,0...
## $ CompensationCurrency                        <chr> NA, NA, NA, "USD",...
## $ SalaryChange                                <chr> "I am not currentl...
## $ JobSatisfaction                             <chr> "5", NA, NA, "10 -...
## $ JobSearchResource                           <chr> NA, NA, "Asking fr...
## $ JobHuntTime                                 <chr> NA, NA, "1-2", NA,...
## $ JobFactorLearning                           <chr> NA, NA, "Very Impo...
## $ JobFactorSalary                             <chr> NA, NA, "Very Impo...
## $ JobFactorOffice                             <chr> NA, NA, "Very Impo...
## $ JobFactorLanguages                          <chr> NA, NA, "Very Impo...
## $ JobFactorCommute                            <chr> NA, NA, "Very Impo...
## $ JobFactorManagement                         <chr> NA, NA, "Very Impo...
## $ JobFactorExperienceLevel                    <chr> NA, NA, "Very Impo...
## $ JobFactorDepartment                         <chr> NA, NA, "Very Impo...
## $ JobFactorTitle                              <chr> NA, NA, "Very Impo...
## $ JobFactorCompanyFunding                     <chr> NA, NA, "Very Impo...
## $ JobFactorImpact                             <chr> NA, NA, "Very Impo...
## $ JobFactorRemote                             <chr> NA, NA, "Very Impo...
## $ JobFactorIndustry                           <chr> NA, NA, "Very Impo...
## $ JobFactorLeaderReputation                   <chr> NA, "Somewhat impo...
## $ JobFactorDiversity                          <chr> NA, NA, "Very Impo...
## $ JobFactorPublishingOpportunity              <chr> NA, NA, "Very Impo...

פקודת glimpse שבה השתמשנו גם שייכת ל-dplyr והיא מספקת “הצצה” לתוך הנתונים. באמצעות הפקודה אנחנו רואים את השדות השונים שנמצאים בקובץ שקראנו, מאיזה סוג הם, ומספר ערכים ראשונים בכל שדה.

פקודת select

הפקודה הבאה שנלמד היא select, פקודה זו מאפשרת לנו לבחור רק משתנים מסוימים, וכך לעבוד עם מבנה נתונים נקי יותר.

work_challenge <- select(kaggle.survey17, starts_with("WorkChallenge"), GenderSelect, Age, EmploymentStatus)
glimpse(work_challenge)
## Observations: 16,716
## Variables: 26
## $ WorkChallengesSelect                        <chr> "Company politics ...
## $ WorkChallengeFrequencyPolitics              <chr> "Rarely", NA, NA, ...
## $ WorkChallengeFrequencyUnusedResults         <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyUnusefulInstrumenting <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDeployment            <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDirtyData             <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyExplaining            <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyPass                  <chr> NA, NA, NA, NA, NA...
## $ WorkChallengeFrequencyIntegration           <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyTalent                <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDataFunds             <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDomainExpertise       <chr> NA, NA, NA, "Most ...
## $ WorkChallengeFrequencyML                    <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyTools                 <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyExpectations          <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyITCoordination        <chr> NA, NA, NA, NA, "S...
## $ WorkChallengeFrequencyHiringFunds           <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyPrivacy               <chr> "Often", NA, NA, "...
## $ WorkChallengeFrequencyScaling               <chr> "Most of the time"...
## $ WorkChallengeFrequencyEnvironments          <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyClarity               <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyDataAccess            <chr> NA, NA, NA, "Often...
## $ WorkChallengeFrequencyOtherSelect           <chr> NA, NA, NA, NA, NA...
## $ GenderSelect                                <chr> "Non-binary, gende...
## $ Age                                         <int> NA, 30, 28, 56, 38...
## $ EmploymentStatus                            <chr> "Employed full-tim...

בקוד המוצג לעיל הפעלנו את פונקצית select כדי לבחור את כל המשתנים מתוך kaggle.survey17, ששמותיהם מתחילים ב-“WorkChallenge”, ביחד עם משתני המגדר, גיל, ומצב תעסוקה. על זה הפעלנו את פקודת glimpse. אנו רואים שכמות המשתנים קטנה מ-228 ל-26 המשתנים הרלוונטיים.

הפקודה select רובוסטית בכך שהיא מאפשרת לנו לבחור על ידי ציון שם המשתנה הספציפי או חלק מההתחלה שלו (starts_with), הסוף שלו (ends_with) או חלק שהוא מכיל (contains).

דרך נוספת להשתמש בפונקציית select היא באמצעות אופרטור המקטרת, pipe, שנראה כך %>%, המאפשר לנו לשרשר פקודות אחת אחרי השניה, והופך את הקוד שלנו להרבה יותר קריא. לדוגמה, שקול לשורת הקוד הקודמת יראה כך:

kaggle.survey17 %>%
   select(starts_with("WorkChallenge")) %>%
   glimpse()

אופרטור המקטרת דואג להעביר לכל פונקציה בשרשרת את התוצאה של הפונקציה הקודמת. כך מבנה הנתונים עובר לתוך select ותוצר הפקודה select עובר לתוך glimpse. מעתה נשתמש באופרטור זה כאשר מדובר בשרשראות של פקודות מ-dplyr ומ-tidyr.

פונקציית העזר start_with עוזרת לנו לדלות את כל המשתנים ששמם מתחיל במחרוזת “WorkChallenge”. פונקציות עזר נוספות כוללות:

starts_with(match)
ends_with(match)
matches(match)
contains(match)
one_of(...) # variables in character vector
matches(regex_str) # match a regular expression

תרגיל

  1. קרא את קובץ הנתונים עמו עבדנו בפרק הקודם (googleplaystore.csv), והצץ בנתונים. כמה משתנים יש בקובץ?
  2. אילו משתנים ישנם בקובץ שהם משתני מחרוזת אבל היו יכולים להיות מספריים?
  3. בחר את כל המשתנים שמסתיימים במילה “Ver”, ביחד עם כל המשתנים שמכילים את האות הגדולה “R”. כמה משתנים קיבלת?

פקודת filter

פקודת filter מאפשרת לנו לסנן נתונים לפי קריטריונים (תנאים לוגיים) לדוגמה, כדי לסנן רק אפליקציות עם דירוג ממוצע מעל 4 או מתחת ל-2 נשתמש בפקודה:

google_play %>%
   filter(Rating > 4 | Rating < 2)

שאלה למחשבה

איך ניתן לשנות את הקוד מעלה כך שיעשה שימוש בפקודה between אבל יפיק את אותה התוצאה?


כדי לסנן רק את האפליקציות מקטגורית משפחה נשתמש בפקודה

google_play %>%
   filter(Category == "FAMILY")

ניתן גם להשתמש בתנאים מורכבים יותר או לשרשר תנאים באופן הבא:

# Best option, but a matter of personal flavour
google_play %>%
  filter(Rating > 4 | Rating <2) %>%
  filter(Category == "FAMILY")
## Warning: package 'bindrcpp' was built under R version 3.4.4
## # A tibble: 1,247 x 13
##    App   Category Rating Reviews Size  Installs Type  Price
##    <chr> <chr>     <dbl>   <int> <chr> <chr>    <chr> <chr>
##  1 YouT~ FAMILY      4.5  470694 Vari~ 50,000,~ Free  0    
##  2 Cand~ FAMILY      4.4   42145 20M   10,000,~ Free  0    
##  3 ROBL~ FAMILY      4.5 4449910 67M   100,000~ Free  0    
##  4 Jewe~ FAMILY      4.4   14774 19M   1,000,0~ Free  0    
##  5 Colo~ FAMILY      4.4   12753 51M   5,000,0~ Free  0    
##  6 Mahj~ FAMILY      4.5   33983 22M   5,000,0~ Free  0    
##  7 Supe~ FAMILY      4.6   20267 46M   1,000,0~ Free  0    
##  8 Toy ~ FAMILY      4.5    5761 21M   1,000,0~ Free  0    
##  9 Educ~ FAMILY      4.3   11618 39M   5,000,0~ Free  0    
## 10 Cand~ FAMILY      4.7   12948 23M   1,000,0~ Free  0    
## # ... with 1,237 more rows, and 5 more variables: `Content Rating` <chr>,
## #   Genres <chr>, `Last Updated` <chr>, `Current Ver` <chr>, `Android
## #   Ver` <chr>
# Also ok, same result. Multiple criteria within filter as seperate arguments, also treated as "and"
google_play %>%
  filter(Rating > 4 | Rating <2, 
         Category == "FAMILY")
## # A tibble: 1,247 x 13
##    App   Category Rating Reviews Size  Installs Type  Price
##    <chr> <chr>     <dbl>   <int> <chr> <chr>    <chr> <chr>
##  1 YouT~ FAMILY      4.5  470694 Vari~ 50,000,~ Free  0    
##  2 Cand~ FAMILY      4.4   42145 20M   10,000,~ Free  0    
##  3 ROBL~ FAMILY      4.5 4449910 67M   100,000~ Free  0    
##  4 Jewe~ FAMILY      4.4   14774 19M   1,000,0~ Free  0    
##  5 Colo~ FAMILY      4.4   12753 51M   5,000,0~ Free  0    
##  6 Mahj~ FAMILY      4.5   33983 22M   5,000,0~ Free  0    
##  7 Supe~ FAMILY      4.6   20267 46M   1,000,0~ Free  0    
##  8 Toy ~ FAMILY      4.5    5761 21M   1,000,0~ Free  0    
##  9 Educ~ FAMILY      4.3   11618 39M   5,000,0~ Free  0    
## 10 Cand~ FAMILY      4.7   12948 23M   1,000,0~ Free  0    
## # ... with 1,237 more rows, and 5 more variables: `Content Rating` <chr>,
## #   Genres <chr>, `Last Updated` <chr>, `Current Ver` <chr>, `Android
## #   Ver` <chr>
# Less readable but still the same
google_play %>%
  filter((Rating > 4 | Rating <2) & (Category == "FAMILY"))
## # A tibble: 1,247 x 13
##    App   Category Rating Reviews Size  Installs Type  Price
##    <chr> <chr>     <dbl>   <int> <chr> <chr>    <chr> <chr>
##  1 YouT~ FAMILY      4.5  470694 Vari~ 50,000,~ Free  0    
##  2 Cand~ FAMILY      4.4   42145 20M   10,000,~ Free  0    
##  3 ROBL~ FAMILY      4.5 4449910 67M   100,000~ Free  0    
##  4 Jewe~ FAMILY      4.4   14774 19M   1,000,0~ Free  0    
##  5 Colo~ FAMILY      4.4   12753 51M   5,000,0~ Free  0    
##  6 Mahj~ FAMILY      4.5   33983 22M   5,000,0~ Free  0    
##  7 Supe~ FAMILY      4.6   20267 46M   1,000,0~ Free  0    
##  8 Toy ~ FAMILY      4.5    5761 21M   1,000,0~ Free  0    
##  9 Educ~ FAMILY      4.3   11618 39M   5,000,0~ Free  0    
## 10 Cand~ FAMILY      4.7   12948 23M   1,000,0~ Free  0    
## # ... with 1,237 more rows, and 5 more variables: `Content Rating` <chr>,
## #   Genres <chr>, `Last Updated` <chr>, `Current Ver` <chr>, `Android
## #   Ver` <chr>

תרגיל

  1. סננו מקובץ googleplaystore.csv את כל האפליקציות שמחירם חיובי, לשם כך השתמשו במשתנה Type.
  2. נסו להשתמש במשתנה Price, האם הצלחתם? למה?
  3. סננו את כל האפליקציות המיועדות לעסקים או שהדירוג שלהם מעל 4.5.

פקודת מיון arrange

כדי למיין את השורות בקובץ נתונים, לפי עמודות מסוימות, ניתן להשתמש בפקודה arrange. כך לדוגמה, כדי למיין את הקובץ google_play לפי דירוג עולה, ושם קטגוריה נשתמש בקוד:

google_play %>%
   arrange(Rating, Category)

כדי למיין משתנה מסוים לפי סדר יורד, עוטפים את המשתנה בפונקציה desc

google_play %>%
   arrange(desc(Rating))
## # A tibble: 10,841 x 13
##    App   Category Rating Reviews Size  Installs Type  Price
##    <chr> <chr>     <dbl>   <int> <chr> <chr>    <chr> <chr>
##  1 Life~ 1.9          19      NA 1,00~ Free     0     Ever~
##  2 Hoji~ COMICS        5      15 37M   1,000+   Free  0    
##  3 Amer~ DATING        5       5 4.4M  1,000+   Free  0    
##  4 Awak~ DATING        5       2 70M   100+     Free  0    
##  5 Spin~ DATING        5       5 9.3M  500+     Free  0    
##  6 Girl~ DATING        5       6 5.0M  100+     Free  0    
##  7 Onli~ DATING        5       5 5.0M  100+     Free  0    
##  8 Spee~ DATING        5       3 25M   100+     Free  0    
##  9 SUMM~ EVENTS        5       4 61M   500+     Free  0    
## 10 Pros~ EVENTS        5      16 2.3M  100+     Free  0    
## # ... with 10,831 more rows, and 5 more variables: `Content Rating` <chr>,
## #   Genres <chr>, `Last Updated` <chr>, `Current Ver` <chr>, `Android
## #   Ver` <chr>

תרגיל

  1. מיינו את הקובץ לפי סדר יורד של הדירוג, ולפי סדר יורד של הביקורות.
  2. סננו ערכים לא חוקיים של דירוג (שאינם בין 1-5), השתמשו בפונקציה between
  3. סננו ערכים שהם NA מתוך כלל המשתנים
    1. רמז ראשון, השתמשו ב-is.na
    2. רמז שני, למתקדמים, כדי לחסוך אפשר להשתמש ב-filter_all
  4. כמה רשומות נותרו בקובץ?

פקודת mutate

פקודה זו משמשת אותנו כדי לבנות משתנים חדשים, וכבר נתקלנו בה בפרקים הקודמים. לדוגמה כדי להגדיר משתנה חדש שהוא הlog של מספר הביקורות נשתמש בפקודה:

google_play_w_log <- google_play %>%
   mutate(log_Reviews = log(Reviews))

glimpse(google_play_w_log)
## Observations: 10,841
## Variables: 14
## $ App              <chr> "Photo Editor & Candy Camera & Grid & ScrapBo...
## $ Category         <chr> "ART_AND_DESIGN", "ART_AND_DESIGN", "ART_AND_...
## $ Rating           <dbl> 4.1, 3.9, 4.7, 4.5, 4.3, 4.4, 3.8, 4.1, 4.4, ...
## $ Reviews          <int> 159, 967, 87510, 215644, 967, 167, 178, 36815...
## $ Size             <chr> "19M", "14M", "8.7M", "25M", "2.8M", "5.6M", ...
## $ Installs         <chr> "10,000+", "500,000+", "5,000,000+", "50,000,...
## $ Type             <chr> "Free", "Free", "Free", "Free", "Free", "Free...
## $ Price            <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", ...
## $ `Content Rating` <chr> "Everyone", "Everyone", "Everyone", "Teen", "...
## $ Genres           <chr> "Art & Design", "Art & Design;Pretend Play", ...
## $ `Last Updated`   <chr> "January 7, 2018", "January 15, 2018", "Augus...
## $ `Current Ver`    <chr> "1.0.0", "2.0.0", "1.2.4", "Varies with devic...
## $ `Android Ver`    <chr> "4.0.3 and up", "4.0.3 and up", "4.0.3 and up...
## $ log_Reviews      <dbl> 5.068904, 6.874198, 11.379508, 12.281384, 6.8...

בתוך פקודת mutate ניתן להפעיל הרבה טרנספורמציות, והתוצר שלה תמיד יהיה וקטור לפי מבנה הנתונים שבו אנו משתמשים. בתוך מבנה הנתונים של google_play יש משתנה הנקרא Last Updated והוא בפורמט מחרוזת (character) למרות שהוא בעצם תאריך. כדי לעדכן אותו לפורמט תאריכי נשלב את פקודת mutate ביחד עם פקודה שיודעת להמיר מחרוזת לתאריך (parse_date_time). לאחר מכן, נבנה משתנה תאריך חדש, המייצג את הרבעון והשנה בלבד.

עבודה עם וקטור המיוצג כתאריך עדיפה על פני מחרוזת (character), משום שהיא מאפשרת לנו להתייחס לתאריך כאל זמן (נניח מיין לפי תאריך, לקבץ לפי רבעונים, וכדומה).

google_play_w_date <- google_play_w_log %>% 
  mutate(log_Reviews = log(Reviews)) %>%
  mutate(`Last Updated` = lubridate::parse_date_time(`Last Updated`, orders = "m, d, y")) %>%
  mutate(`Updated quarter` = lubridate::round_date(`Last Updated`, unit = "quarter")) %>%
  arrange(`Last Updated`)
## Warning: 1 failed to parse.
glimpse(google_play_w_date)
## Observations: 10,841
## Variables: 15
## $ App               <chr> "FML F*ck my life + widget", "CJ Poker Odds ...
## $ Category          <chr> "FAMILY", "GAME", "TOOLS", "GAME", "GAME", "...
## $ Rating            <dbl> 4.2, 4.1, 4.1, 3.7, 4.0, 3.6, 3.9, 4.6, 4.5,...
## $ Reviews           <int> 1415, 207, 981, 38767, 387, 215, 7, 159, 142...
## $ Size              <chr> "209k", "116k", "73k", "4.1M", "1.1M", "2.6M...
## $ Installs          <chr> "100,000+", "50,000+", "100,000+", "5,000,00...
## $ Type              <chr> "Free", "Free", "Free", "Free", "Free", "Fre...
## $ Price             <chr> "0", "0", "0", "0", "0", "0", "$4.99", "$1.4...
## $ `Content Rating`  <chr> "Everyone", "Everyone", "Everyone", "Everyon...
## $ Genres            <chr> "Entertainment", "Card", "Tools", "Action", ...
## $ `Last Updated`    <dttm> 2010-05-21, 2011-01-30, 2011-03-16, 2011-04...
## $ `Current Ver`     <chr> "3.1", "1.2", "1.2.4", "1.4.3", "1.3.3", "1....
## $ `Android Ver`     <chr> "1.5 and up", "1.6 and up", "1.6 and up", "2...
## $ log_Reviews       <dbl> 7.254885, 5.332719, 6.888572, 10.565325, 5.9...
## $ `Updated quarter` <dttm> 2010-07-01, 2011-01-01, 2011-04-01, 2011-04...
ggplot(google_play_w_date, aes(x = factor(`Updated quarter`), y = Reviews)) + 
  geom_boxplot() + 
  scale_y_log10() + 
  theme(axis.text.x = element_text(angle = 90)) + 
  ylab("Reviews (log scale)") + 
  xlab("Quarter")
## Warning: Transformation introduced infinite values in continuous y-axis
## Warning: Removed 597 rows containing non-finite values (stat_boxplot).

פקודות group_by ו-summarise

עוד שתי פקודות משמעותיות בעבודה עם נתונים הן group_by ו-summarise. פקודות אלו משמשות כדי לקבץ נתונים לפי משתנה מסוים, וכדי לבצע פעולות לפי קיבוץ מסוים (לדוגמה חישוב ממוצע לפי קטגוריות).

לדוגמה, נשתמש בהגדרת התאריך של אפליקציה כדי להראות את מספר האפליקציות בקובץ שהעדכון האחרון שלהם היה ברבעון מסוים, וגם כדי לחשב את ממוצע הביקורות שניתנו לכל אפליקציה (בחלוקה לפי רבעון עדכון אחרון).

google_play_summarized <- google_play_w_date %>%
  group_by(`Updated quarter`) %>%
  summarize(mean_reviews = mean(Reviews, na.rm = T),
            num_apps = length(`Updated quarter`))

ggplot(google_play_summarized, aes(x = `Updated quarter`, y = num_apps)) + 
  geom_line() + 
  xlab("Last quarter updated") + 
  ylab("Number of documented apps in googleplay.csv")
## Warning: Removed 1 rows containing missing values (geom_path).


שאלה למחשבה:

האם אתם יודעים להסביר את צורת הגרף? למה הגרף “מתפוצץ” בשנת 2018?


פקודות gather ו-spread

פקודות gather ו-spread משנות את מבנה הנתונים. נשתמש בהם כאשר נאתר משתנים שצריכים להופיע כערכים או לחילופין ערכים הצריכים להופיע כמשתנים נפרדים. דוגמה לשימוש רלוונטי בהם הוא כאשר מבנה הנתונים מסודר בפעולות (transactions) המשויכולת ללקוחות מסוימים, ורוצים לקבץ לפי הפעולות הללו, לבצע פעולות מתמטיות מסוימות (נניח עם summarise), ואז להפוך את הפעולות למשתנים המתארים לקוח מסוים.

הפקודות gather ו-spread הופכיות אחת לשניה.

נמחיש את השימוש ב-gather עם קובץ האפליקציות. בקובץ האפליקציות יש משתנה סוגה (או ז’אנר בלעז, Genres). נחשב את מספר הביקורות הכללי שניתנו לאפליקציות מכל אחת מהסוגות, שהעדכון האחרון שלהן היה בשנת 2018.

במשתנה זה לפעמים מופיעה סוגה אחת ולפעמים שתי סוגות. ראשית, נפצל את המחרוזת לשתי עמודות שיפרטו את הסוגות, באמצעות פקודת separate. נסנן את האפליקציות שעודכנו החל משנת 2018. לאחר מכן נבחר את המשתנים אותם נצטרך: שם האפליקציה (App), משתני הסוגה שיצרנו (Genre1, Genre2), ומספר הביקורות (Reviews).

head(unique(google_play$Genres))
## [1] "Art & Design"                    "Art & Design;Pretend Play"      
## [3] "Art & Design;Creativity"         "Art & Design;Action & Adventure"
## [5] "Auto & Vehicles"                 "Beauty"
google_gathered <- google_play_w_date %>%
  filter(!duplicated(App)) %>%
  filter(lubridate::year(`Last Updated`) >= 2018) %>%
  separate(Genres, sep = ";", into = c("Genre1", "Genre2")) %>%
  select(App, Genre1, Genre2, Reviews) %>%
  gather(Genre12, Genere_class, -App, -Reviews) %>%
filter(!is.na(Genere_class))
## Warning: Expected 2 pieces. Missing pieces filled with `NA` in 6019
## rows [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
## 20, ...].
glimpse(google_gathered) 
## Observations: 6,543
## Variables: 4
## $ App          <chr> "How Old am I?", "Millionaire Quiz Free: Be Rich"...
## $ Reviews      <int> 4635, 66033, 593, 39, 3, 190, 542561, 1475, 334, ...
## $ Genre12      <chr> "Genre1", "Genre1", "Genre1", "Genre1", "Genre1",...
## $ Genere_class <chr> "Entertainment", "Casual", "Education", "Social",...

כפי שניתן לראות, לאחר הפעלת הפקודה gather קיבלנו טבלה שאספה את העמודות Genre# לעמודה אחת, ובצמוד אליה את הפירוט של הסוגות. אפליקציות שלהם היו שני סיווגים, יופיעו בטבלה זו פעמיים (פעם אחת עם Genre1 ופעם אחרת עם Genre2). החישוב הבא מראה שיש בסה“כ 262 אפליקציות שהיה להן סיווג כפול.

google_gathered %>%
  count(App) %>%
  count(n)
## # A tibble: 2 x 2
##       n    nn
##   <int> <int>
## 1     1  6019
## 2     2   262

כעת ניתן לחשב כמה ביקורות ניתנו בכל קטגוריה, כולל התחשבות בביקורות שניתנו לאפליקציות המסווגות ליותר מקטגוריה אחת:

total_reviews_per_genre <- google_gathered %>%
  group_by(Genere_class) %>%
  summarize(total_reviews = sum(Reviews)) %>%
  arrange(desc(total_reviews)) %>%
  mutate(Genere_class = fct_inorder(Genere_class))

ggplot(total_reviews_per_genre, aes(x = Genere_class, y = total_reviews)) + 
  geom_col() + 
  theme(axis.text.x = element_text(angle = 90)) + 
  xlab("Genere") + 
  ylab("Total reviews given in Genere") + 
  ggtitle("Most frequently used?\nNumber of reviews per genere")


תרגיל מסכם - טרנספורמציות נתונים

בתרגיל זה נשתמש בקובץ של מטופלים שנקבעה להם פגישה עם רופא, אך לא הגיעו לפגישה (“הבריזו”). מקור הקובץ מ-Kaggle בקישור: https://www.kaggle.com/joniarroba/noshowappointments.

בהמשך אנו נתאים מודלים לצורך חיזוי מתי מטופלים הם בעלי סבירות גבוהה שלא להגיע לפגישה שנקבעה להם. כרגע נשתמש בקובץ בשביל לתרגל את המרות הנתונים אותם למדנו בפרק זה.

  1. הורד את קובץ הנתונים קרא אותו והצץ בנתונים.
library(tidyverse)
patients <- read_csv("data-files/Medical_Appointments_No_Shows_KaggleV2-May-2016.csv")
## Parsed with column specification:
## cols(
##   PatientId = col_double(),
##   AppointmentID = col_integer(),
##   Gender = col_character(),
##   ScheduledDay = col_datetime(format = ""),
##   AppointmentDay = col_datetime(format = ""),
##   Age = col_integer(),
##   Neighbourhood = col_character(),
##   Scholarship = col_integer(),
##   Hipertension = col_integer(),
##   Diabetes = col_integer(),
##   Alcoholism = col_integer(),
##   Handcap = col_integer(),
##   SMS_received = col_integer(),
##   `No-show` = col_character()
## )
glimpse(patients)
## Observations: 110,527
## Variables: 14
## $ PatientId      <dbl> 2.987250e+13, 5.589978e+14, 4.262962e+12, 8.679...
## $ AppointmentID  <int> 5642903, 5642503, 5642549, 5642828, 5642494, 56...
## $ Gender         <chr> "F", "M", "F", "F", "F", "F", "F", "F", "F", "F...
## $ ScheduledDay   <dttm> 2016-04-29 18:38:08, 2016-04-29 16:08:27, 2016...
## $ AppointmentDay <dttm> 2016-04-29, 2016-04-29, 2016-04-29, 2016-04-29...
## $ Age            <int> 62, 56, 62, 8, 56, 76, 23, 39, 21, 19, 30, 29, ...
## $ Neighbourhood  <chr> "JARDIM DA PENHA", "JARDIM DA PENHA", "MATA DA ...
## $ Scholarship    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,...
## $ Hipertension   <int> 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
## $ Diabetes       <int> 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
## $ Alcoholism     <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
## $ Handcap        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
## $ SMS_received   <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,...
## $ `No-show`      <chr> "No", "No", "No", "No", "No", "No", "Yes", "Yes...
  1. השתמשו במשתנה המזהה מטופל בשביל לחשב את מספר הפעמים שהמטופל הגיע לפגישות, ואת מספר הפעמים שפגישה נקבעה אך המטופל לא הגיע. באפשרותכם להיעזר בשאלות הבאות:
    1. לפי איזה משתנה עליכם לקבץ את הנתונים?
    2. השתמשו בפונקצית count כדי לספור את אי ההופעות.
    3. כעת, השתמשו בפונקצית spread כדי לפרק את העמודה של “No-show”, לשתי עמודות של No ו-Yes.
    4. לפונציית spread יש פרמטר fill. בדקו בעזרה של הפונקציה, מה ערך ברירת המחדל שלו? מה צריך להיות ערכו במקרה זה?
    5. בנו משתנה חדש של סך הבדיקות. לשם כך השתמשו בפונקציה mutate.
    6. בנו משתנה חדש של שיעור הבדיקות אליכם הגיע המטופל, מתוך סך הבדיקות שנקבעו לו.
    7. מה אחוז המטופלים שהגיעו ללפחות 80% מהבדיקות שנקבעו להם?
    8. מה אחוז המטופלים שפספסו לפחות בדיקה אחת?
    9. מה מספר הבדיקות הממוצע שנקבע למטופל? האם ממוצע זה מוטה? למה ולאיזה כיוון?

בפרק זה עסקנו בנושאים “טכניים” שהם כלים הכרחיים בעבודה עם נתונים. כפי שראינו, הרבה פעמים ההתעסקות עם הנתונים אורכת זמן רב הרבה יותר מאשר הסקת מסקנות או הפקת מודלים.

בפרק הבא, נצלול לעולם המודלים הסטטיסטיים ומודלים של חיזוי בבעיות שונות. נציג מעט תיאוריה סטטיסטית, ונתמקד במשפחה של מודלים פשוטים, אך בעלי חשיבות רבה - מודלי רגרסיה.