Chapter 3 数据整理和总结

在本次研讨会中,我将向您介绍许多关键包,Tidyverse这些包包含大量用于处理整齐格式数据的函数。通过使我们的数据整理可重现(即,通过用 R 进行编码),我们可以在添加新数据时轻松地重新运行分析流程。数据整理阶段的可重复性是分析过程的关键部分,但在需要确保其可重复性方面经常被忽视。本次研讨会分为两个部分。第一个重点是数据整理,第二部分是数据总结。

数据整理

概述

我们将首先了解Tidyverse中的一些关键工具,这些工具使我们能够整理和整理数据,使其达到我们可视化和建模所需的格式。Tidyverse 是一个相互“很好地配合”的软件包的集合。它们基于一个共同的理念,即数据以矩形格式(即行和列)表示。这些矩形结构在 Tidyverse 中被称为tibbles。如果您有兴趣,可以在此处tibbles阅读R4DS 书籍中的更多信息。

请观看以下视频,我将在其中引导您完成此工作表。然后我希望您通过在自己的计算机上编写(并运行)脚本来完成内容。

加载Tidyverse

让我们首先看一下数据整理。我们将从 Tidyverse 附带的数据集开始。该数据集mpg包含 1999 年至 2008 年美国 38 种流行车型的燃油经济性数据。

首先,我们需要tidyverse使用以下内容加载库:

library(tidyverse)

如果您在没有先在计算机上安装 Tidyverse 的情况下运行此行,您将遇到错误。R 包只需要安装一次,因此如果您想第一次将其加载到库中,则需要使用install.packages(*"packagename"*)

对于tidyverse我们需要安装它:

install.packages("tidyverse")

安装tidyverse后,您可以使用library()功能将其加载到您的库中。您只需在计算机上安装一次软件包(除非您已更新 R 或者您想要安装特定软件包的最新版本)。当您编写 R 脚本时,您永远不想在脚本主体中拥有该函数install.packages(),就好像其他人运行您的脚本一样,这会更新他们计算机上的包(他们可能不想要)。

数据集mpg

mpg数据集作为Tidyverse包帮助文件的一部分被加载,可以使用help(mpg)或者?mpg来查看,我们可以看到下面的说明:

Description
This dataset contains a subset of the fuel economy data that the EPA makes available on http://fueleconomy.gov. It contains only models which had a new release every year between 1999 and 2008 - this was used as a proxy for the popularity of the car.

A data frame with 234 rows and 11 variables.

manufacturer - manufacturer
model - model name
displ - engine displacement, in litres
year - year of manufacture
cyl - number of cylinders
trans -type of transmission
drv-f = front-wheel drive, r = rear wheel drive, 4 = 4wd
cty - city miles per gallon
hwy - highway miles per gallon
fl - fuel type
class - “type” of car

使用head()str()

我们可以通过多种方式探索 Tidyverse 加载的数据集mpg。如果我们想查看数据集的前 6 行,我们可以使用该head()函数。

head(mpg)
## # A tibble: 6 × 11
##   manufacturer model displ  year   cyl trans      drv     cty   hwy fl    class 
##   <chr>        <chr> <dbl> <int> <int> <chr>      <chr> <int> <int> <chr> <chr> 
## 1 audi         a4      1.8  1999     4 auto(l5)   f        18    29 p     compa…
## 2 audi         a4      1.8  1999     4 manual(m5) f        21    29 p     compa…
## 3 audi         a4      2    2008     4 manual(m6) f        20    31 p     compa…
## 4 audi         a4      2    2008     4 auto(av)   f        21    30 p     compa…
## 5 audi         a4      2.8  1999     6 auto(l5)   f        16    26 p     compa…
## 6 audi         a4      2.8  1999     6 manual(m5) f        18    26 p     compa…

我们看到它是一个tibble或者说一个矩形数据框,由行和列组成。这是每个观察对应一行的格式tidy。我们将在 R 中运行的大多数分析都涉及tidy数据。在 Tidyverse 中,tibble是表示数据的标准方式。您将花费大量时间整理和整理数据以将其转换为这种格式!通过使用您编写的脚本在 R 中执行此操作,您可以使这个关键阶段可重现。您可以在更新的或不同的数据集上再次运行脚本,因此可能会节省您大量时间!

我们还可以使用 询问有关数据集结构的信息str()。这将告诉我们有关列的信息、每个变量的类型、行数等。

str(mpg)
## tibble [234 × 11] (S3: tbl_df/tbl/data.frame)
##  $ manufacturer: chr [1:234] "audi" "audi" "audi" "audi" ...
##  $ model       : chr [1:234] "a4" "a4" "a4" "a4" ...
##  $ displ       : num [1:234] 1.8 1.8 2 2 2.8 2.8 3.1 1.8 1.8 2 ...
##  $ year        : int [1:234] 1999 1999 2008 2008 1999 1999 2008 1999 1999 2008 ...
##  $ cyl         : int [1:234] 4 4 4 4 6 6 6 4 4 4 ...
##  $ trans       : chr [1:234] "auto(l5)" "manual(m5)" "manual(m6)" "auto(av)" ...
##  $ drv         : chr [1:234] "f" "f" "f" "f" ...
##  $ cty         : int [1:234] 18 21 20 21 16 18 18 18 16 20 ...
##  $ hwy         : int [1:234] 29 29 31 30 26 26 27 26 25 28 ...
##  $ fl          : chr [1:234] "p" "p" "p" "p" ...
##  $ class       : chr [1:234] "compact" "compact" "compact" "compact" ...

select()选择列

如果我们愿意,我们可以使用该select()函数选择其中一列。下面我们只选择标题为manufacturer的列。

mpg %>%
  select(manufacturer)
## # A tibble: 234 × 1
##    manufacturer
##    <chr>       
##  1 audi        
##  2 audi        
##  3 audi        
##  4 audi        
##  5 audi        
##  6 audi        
##  7 audi        
##  8 audi        
##  9 audi        
## 10 audi        
## # ℹ 224 more rows

select()功能相关的是rename()和您想的一样,它重命名一列。

我们还可以使用该distinct()函数查看数据集中的不同汽车制造商。这为我们提供了不同的制造商名称。如果您想检查数据集是否有(例如)参与者 ID 的重复项,此功能会非常方便。

mpg %>%
  distinct(manufacturer)
## # A tibble: 15 × 1
##    manufacturer
##    <chr>       
##  1 audi        
##  2 chevrolet   
##  3 dodge       
##  4 ford        
##  5 honda       
##  6 hyundai     
##  7 jeep        
##  8 land rover  
##  9 lincoln     
## 10 mercury     
## 11 nissan      
## 12 pontiac     
## 13 subaru      
## 14 toyota      
## 15 volkswagen

filter()选择行

有时我们可能只想选择数据集中的行子集。我们可以使用该filter()函数来做到这一点。例如,在这里我们过滤数据集以仅包含“honda”制造的汽车。

mpg %>%
  filter(manufacturer == "honda")
## # A tibble: 9 × 11
##   manufacturer model displ  year   cyl trans      drv     cty   hwy fl    class 
##   <chr>        <chr> <dbl> <int> <int> <chr>      <chr> <int> <int> <chr> <chr> 
## 1 honda        civic   1.6  1999     4 manual(m5) f        28    33 r     subco…
## 2 honda        civic   1.6  1999     4 auto(l4)   f        24    32 r     subco…
## 3 honda        civic   1.6  1999     4 manual(m5) f        25    32 r     subco…
## 4 honda        civic   1.6  1999     4 manual(m5) f        23    29 p     subco…
## 5 honda        civic   1.6  1999     4 auto(l4)   f        24    32 r     subco…
## 6 honda        civic   1.8  2008     4 manual(m5) f        26    34 r     subco…
## 7 honda        civic   1.8  2008     4 auto(l5)   f        25    36 r     subco…
## 8 honda        civic   1.8  2008     4 auto(l5)   f        24    36 c     subco…
## 9 honda        civic   2    2008     4 manual(m6) f        21    29 p     subco…

请注意,我们使用的运算符==表示“等于”。这是一个逻辑运算符,其他逻辑运算符包括小于<、大于>、小于等于<=、大于等于>=和不等于!=

下面我们过滤制造商为“honda”且制造年份为“1999”的情况。

mpg %>% 
  filter(manufacturer == "honda" & year == "1999")
## # A tibble: 5 × 11
##   manufacturer model displ  year   cyl trans      drv     cty   hwy fl    class 
##   <chr>        <chr> <dbl> <int> <int> <chr>      <chr> <int> <int> <chr> <chr> 
## 1 honda        civic   1.6  1999     4 manual(m5) f        28    33 r     subco…
## 2 honda        civic   1.6  1999     4 auto(l4)   f        24    32 r     subco…
## 3 honda        civic   1.6  1999     4 manual(m5) f        25    32 r     subco…
## 4 honda        civic   1.6  1999     4 manual(m5) f        23    29 p     subco…
## 5 honda        civic   1.6  1999     4 auto(l4)   f        24    32 r     subco…

组合功能

我们可以结合使用filter()select()来过滤制造商为“honda”、制造年份为“1999”的情况,并且我们只想显示这两列以及告诉我们燃油经济性的列(ctyhwy)。

mpg %>% 
  filter(manufacturer == "honda" & year == "1999") %>%
  select(manufacturer, year, cty, hwy)
## # A tibble: 5 × 4
##   manufacturer  year   cty   hwy
##   <chr>        <int> <int> <int>
## 1 honda         1999    28    33
## 2 honda         1999    24    32
## 3 honda         1999    25    32
## 4 honda         1999    23    29
## 5 honda         1999    24    32

通过组合几个函数,您可以想象我们可以非常简单地构建一些相当复杂的数据整理规则。

管道操作符%>%

请注意,在上面的这些示例中,我们使用了%>%运算符 - 这称为管道,允许我们将信息从管道的一侧传递到另一侧。您可以将其读作“然后”。Tidyverse 中的所有函数(例如select()filter())都称为动词(verbs),它们本身描述了自己的作用。管道是 Tidyverse 中最常用的运算符之一,它允许我们将不同的代码行链接在一起 - 每行的输出作为输入传递到下一行。在此示例中,数据集mpg被传递到distinct()函数,我们在其中请求不同(即唯一)制造商的列表。这个输出本身就是一个向量。向量是一种基本数据结构,包含相同类型的元素 - 例如,一堆数字。我们可以在管道链中添加另一行来告诉我们这个向量中有多少个元素。我们可以将其大声朗读为“获取数据集 mpg,然后计算出不同的制造商名称,然后对它们进行计数”。

mpg %>% 
  distinct(manufacturer) %>%
  count()
## # A tibble: 1 × 1
##       n
##   <int>
## 1    15

整理数据集

整理变量名称

目前,汽车制造商名称均为小写。如果它们采用标题大小写(即每个单词的第一个字母大写),看起来会好得多。我们可以使用该mutate()函数创建一个新列 - 这次,新列的名称,即是我们要使用该str_to_title()函数修改旧列的名称。这将覆盖该列并将manufacturer其替换为首字母大写的新版本。

mpg %>%
  mutate(manufacturer = str_to_title(manufacturer))
## # A tibble: 234 × 11
##    manufacturer model      displ  year   cyl trans drv     cty   hwy fl    class
##    <chr>        <chr>      <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
##  1 Audi         a4           1.8  1999     4 auto… f        18    29 p     comp…
##  2 Audi         a4           1.8  1999     4 manu… f        21    29 p     comp…
##  3 Audi         a4           2    2008     4 manu… f        20    31 p     comp…
##  4 Audi         a4           2    2008     4 auto… f        21    30 p     comp…
##  5 Audi         a4           2.8  1999     6 auto… f        16    26 p     comp…
##  6 Audi         a4           2.8  1999     6 manu… f        18    26 p     comp…
##  7 Audi         a4           3.1  2008     6 auto… f        18    27 p     comp…
##  8 Audi         a4 quattro   1.8  1999     4 manu… 4        18    26 p     comp…
##  9 Audi         a4 quattro   1.8  1999     4 auto… 4        16    25 p     comp…
## 10 Audi         a4 quattro   2    2008     4 manu… 4        20    28 p     comp…
## # ℹ 224 more rows

model也是小写的。我们也来让他首字母大写。我们可以使用该mutate()函数同时处理多个列,如下所示:

mpg %>%
  mutate(manufacturer = str_to_title(manufacturer), model = str_to_title(model))
## # A tibble: 234 × 11
##    manufacturer model      displ  year   cyl trans drv     cty   hwy fl    class
##    <chr>        <chr>      <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
##  1 Audi         A4           1.8  1999     4 auto… f        18    29 p     comp…
##  2 Audi         A4           1.8  1999     4 manu… f        21    29 p     comp…
##  3 Audi         A4           2    2008     4 manu… f        20    31 p     comp…
##  4 Audi         A4           2    2008     4 auto… f        21    30 p     comp…
##  5 Audi         A4           2.8  1999     6 auto… f        16    26 p     comp…
##  6 Audi         A4           2.8  1999     6 manu… f        18    26 p     comp…
##  7 Audi         A4           3.1  2008     6 auto… f        18    27 p     comp…
##  8 Audi         A4 Quattro   1.8  1999     4 manu… 4        18    26 p     comp…
##  9 Audi         A4 Quattro   1.8  1999     4 auto… 4        16    25 p     comp…
## 10 Audi         A4 Quattro   2    2008     4 manu… 4        20    28 p     comp…
## # ℹ 224 more rows

数据集里有很多列,所以我们只选择manufacturer, model, year, transmission 和 hwy列:

mpg %>%
  mutate(manufacturer = str_to_title(manufacturer), model = str_to_title(model)) %>%
  select(manufacturer, model, year, trans, hwy)
## # A tibble: 234 × 5
##    manufacturer model       year trans        hwy
##    <chr>        <chr>      <int> <chr>      <int>
##  1 Audi         A4          1999 auto(l5)      29
##  2 Audi         A4          1999 manual(m5)    29
##  3 Audi         A4          2008 manual(m6)    31
##  4 Audi         A4          2008 auto(av)      30
##  5 Audi         A4          1999 auto(l5)      26
##  6 Audi         A4          1999 manual(m5)    26
##  7 Audi         A4          2008 auto(av)      27
##  8 Audi         A4 Quattro  1999 manual(m5)    26
##  9 Audi         A4 Quattro  1999 auto(l5)      25
## 10 Audi         A4 Quattro  2008 manual(m6)    28
## # ℹ 224 more rows

重新编码变量

在现实世界中,数据集(Data Frames)并不总是以整齐的格式到达我们的计算机。通常,您需要先进行一些数据整理,然后才能对它们进行任何有用的操作。我们将看一个示例,说明如何从杂乱的数据变为整洁的数据。使用的数据集可以在这里下载

my_messy_data <- read_csv("Dataset/my_data.csv")
my_messy_data

我们对 24 名参与者和 4 个条件进行了反应时间实验,他们在我们的数据文件中编号为 1-4。

head(my_messy_data)
## # A tibble: 6 × 3
##   participant condition    rt
##         <dbl>     <dbl> <dbl>
## 1           1         1   879
## 2           1         2  1027
## 3           1         3  1108
## 4           1         4   765
## 5           2         1  1042
## 6           2         2  1050

这是一种重复测量设计,其中一个因素(启动类型,即Prime Type)具有两个水平(A 与 B),第二个因素(目标类型,即Target Type)具有两个水平(A 与 B)。我们想要重新编码我们的数据框,以便它更好地匹配我们的实验设计。首先我们需要像这样重新编码 4 个情况(Condition):

重新编码Condition列如下:
- Condition 1 = Prime A, Target A
- Condition 2 = Prime A, Target B
- Condition 3 = Prime B, Target A
- Condition 4 = Prime B, Target B

my_messy_data %>% 
  mutate(condition = recode(condition,
                            "1" = "PrimeA_TargetA",
                            "2" = "PrimeA_TargetB", 
                            "3" = "PrimeB_TargetA", 
                            "4" = "PrimeB_TargetB")) %>%
  head()
## # A tibble: 6 × 3
##   participant condition         rt
##         <dbl> <chr>          <dbl>
## 1           1 PrimeA_TargetA   879
## 2           1 PrimeA_TargetB  1027
## 3           1 PrimeB_TargetA  1108
## 4           1 PrimeB_TargetB   765
## 5           2 PrimeA_TargetA  1042
## 6           2 PrimeA_TargetB  1050

我们现在需要将我们的条件列分成两个 - 一个用于我们的第一个因素(Prime),另一个用于我们的第二个因素(Target)。separate() 函数正是做这个的 — 当与管道化的tibble一起使用时,它需要知道我们想要分离哪一列,通过分离原始列来创建什么新列,以及我们想要基于什么来进行分离。在下面的示例中,我们告诉 separate() 我们想要将标记为 condition 的列分成两个新列,称为 PrimeTarget,并且我们想要在要被分离的列中出现 _ 的任何地方进行这种分离。

my_messy_data %>% 
  mutate(condition = recode(condition,
                            "1" = "PrimeA_TargetA",
                            "2" = "PrimeA_TargetB", 
                            "3" = "PrimeB_TargetA", 
                            "4" = "PrimeB_TargetB")) %>%
  separate(col = "condition", into = c("Prime", "Target"), sep = "_")
## # A tibble: 96 × 4
##    participant Prime  Target     rt
##          <dbl> <chr>  <chr>   <dbl>
##  1           1 PrimeA TargetA   879
##  2           1 PrimeA TargetB  1027
##  3           1 PrimeB TargetA  1108
##  4           1 PrimeB TargetB   765
##  5           2 PrimeA TargetA  1042
##  6           2 PrimeA TargetB  1050
##  7           2 PrimeB TargetA   942
##  8           2 PrimeB TargetB   945
##  9           3 PrimeA TargetA   943
## 10           3 PrimeA TargetB   910
## # ℹ 86 more rows
my_messy_data %>% 
  mutate(condition = recode(condition,
                            "1" = "PrimeA_TargetA",
                            "2" = "PrimeA_TargetB", 
                            "3" = "PrimeB_TargetA", 
                            "4" = "PrimeB_TargetB")) %>%
  separate(col = "condition", into = c("Prime", "Target"), sep = "_") %>%
  mutate(Prime = factor(Prime), Target = factor(Target))
## # A tibble: 96 × 4
##    participant Prime  Target     rt
##          <dbl> <fct>  <fct>   <dbl>
##  1           1 PrimeA TargetA   879
##  2           1 PrimeA TargetB  1027
##  3           1 PrimeB TargetA  1108
##  4           1 PrimeB TargetB   765
##  5           2 PrimeA TargetA  1042
##  6           2 PrimeA TargetB  1050
##  7           2 PrimeB TargetA   942
##  8           2 PrimeB TargetB   945
##  9           3 PrimeA TargetA   943
## 10           3 PrimeA TargetB   910
## # ℹ 86 more rows

pivot 函数

我们将在 R 中进行的大多数分析都要求数据处于整洁或长格式。在这样的数据集中,一行对应一个观测值。在现实世界中,数据很少处于适合分析的正确格式。在 R 中,pivot_wider()pivot_longer() 函数被设计用来重塑我们的数据文件。首先,让我们加载一个处于宽格式的数据文件(即,每行有多个观测值)。它来自一个我们进行了四种条件(标记为 Condition1、Condition2、Condition3 和 Condition4)的实验。除了有四种条件的每一列之外,我们还有一列对应于参与者 ID。数据集中的每个单元格对应一个反应时间(以毫秒为单位)。数据可以在这里下载

my_wide_data <- read_csv("Dataset/my_wide_data.csv")
## Rows: 32 Columns: 5
## ── Column specification ─────────────────────────────────────────
## Delimiter: ","
## dbl (5): ID, Condition1, Condition2, Condition3, Condition4
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

pivot_longer() 函数

head(my_wide_data)
## # A tibble: 6 × 5
##      ID Condition1 Condition2 Condition3 Condition4
##   <dbl>      <dbl>      <dbl>      <dbl>      <dbl>
## 1     1        487        492        499        488
## 2     2        502        494        517        508
## 3     3        510        483        488        509
## 4     4        476        488        513        521
## 5     5        504        478        513        504
## 6     6        505        486        503        495

所以,我们可以看到数据文件是宽格式的。我们想要将其重塑为长格式。我们可以使用 pivot_longer() 函数来做到这一点。

最低限度地,我们需要指定我们想要重塑的数据框架,我们想要转换为长格式的列,我们正在创建的新列的名称,以及将保存我们重塑数据框架(data frame)的值的列的名称。我们将输出映射到一个我称之为 my_longer_data 的变量。

my_longer_data <- my_wide_data %>%
  pivot_longer(cols = c(Condition1, Condition2, Condition3, Condition4), 
               names_to = "Condition", 
               values_to = "RT")

现在我们来看看重塑后的数据框架的样子

head(my_longer_data)
## # A tibble: 6 × 3
##      ID Condition     RT
##   <dbl> <chr>      <dbl>
## 1     1 Condition1   487
## 2     1 Condition2   492
## 3     1 Condition3   499
## 4     1 Condition4   488
## 5     2 Condition1   502
## 6     2 Condition2   494

所以你可以看到我们的数据现在是长格式(或tidy格式),每行一个观察。注意我们的Condition列没有被编码为因子。由于我们的数据集需要反映我们实验的结构,因此让我们将该列转换为因子 - 注意在以下代码中我们现在正在“保存”更改,因为我们没有将输出映射到变量名上。

my_longer_data %>%
  mutate(Condition = factor(Condition)) %>%
  head()
## # A tibble: 6 × 3
##      ID Condition     RT
##   <dbl> <fct>      <dbl>
## 1     1 Condition1   487
## 2     1 Condition2   492
## 3     1 Condition3   499
## 4     1 Condition4   488
## 5     2 Condition1   502
## 6     2 Condition2   494

pivot_wider()函数

我们可以使用 pivot_wider() 函数来重塑长数据框,使其从长格式转换为宽格式。它的工作方式类似于 pivot_longer()。让我们拿我们新的、长的、数据框并将其转回宽格式。使用 pivot_wider() 时,我们最低需要指定我们想要重塑的数据框,并指定一对参数(names_fromvalues_from),这些参数描述了从哪个列获取输出列的名称,以及从哪个列获取单元格值。

my_wider_data <- my_longer_data %>%
  pivot_wider(names_from = "Condition", 
              values_from = "RT")

我们可以检查我们的数据集是否已经回到宽格式。

head(my_wider_data)
## # A tibble: 6 × 5
##      ID Condition1 Condition2 Condition3 Condition4
##   <dbl>      <dbl>      <dbl>      <dbl>      <dbl>
## 1     1        487        492        499        488
## 2     2        502        494        517        508
## 3     3        510        483        488        509
## 4     4        476        488        513        521
## 5     5        504        478        513        504
## 6     6        505        486        503        495

合并两个数据集

有时你可能需要合并两个数据集。例如,你可能有一个包含阅读时间数据的数据集(就像上面那个)和另一个包含第一个数据集中参与者的个体差异测量的数据集。我们如何才能合并这两个数据集,以便最终得到一个既包括阅读时间数据又包括个体差异测量(我们可能稍后想要协变掉)的数据集?幸运的是,dplyr 包包含了许多连接函数,允许你将不同的tibbles连接在一起。首先,让我们加载包含个体差异测量的数据。该数据集可以在这里下载

individual_diffs <- read_csv("Dataset/individual_diffs.csv")

让我们看看个体差异数据的前几行。这个数据集包含了我们参与者的ID号以及智商(iq列)和工作记忆(wm列)的测量值。

head(individual_diffs)
## # A tibble: 6 × 3
##      ID    iq    wm
##   <dbl> <dbl> <dbl>
## 1     1   100     9
## 2     2   108     8
## 3     3   116     9
## 4     4    95     9
## 5     5    83    11
## 6     6    73    10

完全合并

我们可以使用其中一个连接函数来组合。有多种选择,包括 full_join(),它包括了我们想要连接的第一个或第二个 tibble 中的所有行。其他选项包括 inner_join(),它包括了第一个和第二个 tibble 中的所有行,以及 left_join()right_join()

combined_data <- full_join(my_longer_data, individual_diffs, by = "ID")

我们现在看到我们的数据集按照我们的预期组合在一起了。

combined_data
## # A tibble: 128 × 5
##       ID Condition     RT    iq    wm
##    <dbl> <chr>      <dbl> <dbl> <dbl>
##  1     1 Condition1   487   100     9
##  2     1 Condition2   492   100     9
##  3     1 Condition3   499   100     9
##  4     1 Condition4   488   100     9
##  5     2 Condition1   502   108     8
##  6     2 Condition2   494   108     8
##  7     2 Condition3   517   108     8
##  8     2 Condition4   508   108     8
##  9     3 Condition1   510   116     9
## 10     3 Condition2   483   116     9
## # ℹ 118 more rows

左合并

当然,你可能会想,我们可以简单地使用Excel对我们想要的列进行剪切和粘贴,从一个数据集转移到另一个数据集。但是,如果我们的个体差异文件包含了10,000个参与者的ID(以随机顺序排列),而我们只对在两个数据集匹配的情况下进行合并感兴趣呢?数据可以在这里下载

large_ind_diffs <- read_csv("Dataset/large_ind_diffs.csv")
head(large_ind_diffs)
## # A tibble: 6 × 3
##      ID    iq    wm
##   <dbl> <dbl> <dbl>
## 1  6057    93     7
## 2  2723    86     7
## 3  1088    97     9
## 4  8687    87     8
## 5  4223    77    11
## 6   369    95     9

我们实际上可以使用另一个连接函数(left_join())来组合这两个数据集,但只在第一个数据集(函数调用中的my_longer_data)的ID与另一个数据集匹配的情况下进行组合。

left_join(my_longer_data, large_ind_diffs, by = "ID")
## # A tibble: 128 × 5
##       ID Condition     RT    iq    wm
##    <dbl> <chr>      <dbl> <dbl> <dbl>
##  1     1 Condition1   487   100     9
##  2     1 Condition2   492   100     9
##  3     1 Condition3   499   100     9
##  4     1 Condition4   488   100     9
##  5     2 Condition1   502   108     8
##  6     2 Condition2   494   108     8
##  7     2 Condition3   517   108     8
##  8     2 Condition4   508   108     8
##  9     3 Condition1   510   116     9
## 10     3 Condition2   483   116     9
## # ℹ 118 more rows

作业

尝试通过使用 RStudio Desktop 编写你的第一个脚本来重现上面的内容。

概括你的数据

概述

一旦数据集被整理好,我们通常想要做的第一件事之一就是生成摘要统计数据。在这个研讨会中,我们将使用内置于 tidyverse 中的 mpg 数据集。这个数据集包含了许多不同制造商生产的汽车的信息(如发动机大小、燃油经济性等)。我们如何生成(例如)按汽车制造商分组的某个变量的平均值和标准偏差?请观看以下视频,我将引导你完成这个工作表。然后,我希望你通过在自己的机器上编写(并运行)脚本来完成内容。

在继续之前,请记得为这节课设置一个 .Rproj 文件。在你的脚本中,你首先需要加载 tidyverse

library(tidyverse)

使用 group_by()summarise()

我们将使用group_by()函数对数据集进行分组,然后使用summarise()函数计算hwy变量的均值和标准差。summarise()函数可以使用许多不同的函数来提供摘要统计信息。要了解更多不同选项,请在控制台窗口中键入?summarise。常用的函数包括mean()median()sd()

mpg %>%
  group_by(manufacturer) %>%
  summarise(mean_hwy = mean(hwy), sd_hwy = sd(hwy), number = n())
## # A tibble: 15 × 4
##    manufacturer mean_hwy sd_hwy number
##    <chr>           <dbl>  <dbl>  <int>
##  1 audi             26.4   2.18     18
##  2 chevrolet        21.9   5.11     19
##  3 dodge            17.9   3.57     37
##  4 ford             19.4   3.33     25
##  5 honda            32.6   2.55      9
##  6 hyundai          26.9   2.18     14
##  7 jeep             17.6   3.25      8
##  8 land rover       16.5   1.73      4
##  9 lincoln          17     1         3
## 10 mercury          18     1.15      4
## 11 nissan           24.6   5.09     13
## 12 pontiac          26.4   1.14      5
## 13 subaru           25.6   1.16     14
## 14 toyota           24.9   6.17     34
## 15 volkswagen       29.2   5.32     27

请注意,此输出当前按第一列 manufacturer 的字母顺序排列。如果我们想按高速公路平均燃油经济性从高到低的顺序排列呢?我们可以使用 arrange() 函数。

使用arrange()重新排序输出

mpg %>%
  group_by(manufacturer) %>%
  summarise(mean_hwy = mean(hwy), sd_hwy = sd(hwy), number = n()) %>%
  arrange(mean_hwy)
## # A tibble: 15 × 4
##    manufacturer mean_hwy sd_hwy number
##    <chr>           <dbl>  <dbl>  <int>
##  1 land rover       16.5   1.73      4
##  2 lincoln          17     1         3
##  3 jeep             17.6   3.25      8
##  4 dodge            17.9   3.57     37
##  5 mercury          18     1.15      4
##  6 ford             19.4   3.33     25
##  7 chevrolet        21.9   5.11     19
##  8 nissan           24.6   5.09     13
##  9 toyota           24.9   6.17     34
## 10 subaru           25.6   1.16     14
## 11 pontiac          26.4   1.14      5
## 12 audi             26.4   2.18     18
## 13 hyundai          26.9   2.18     14
## 14 volkswagen       29.2   5.32     27
## 15 honda            32.6   2.55      9

emmmmmmmm,这不是我们想要的,这是从最低到最高的顺序,这是R的默认顺序。我们可以通过在参数前加上-符号来改变这一点。

mpg %>%
  group_by(manufacturer) %>%
  summarise(mean_hwy = mean(hwy), sd_hwy = sd(hwy), number = n()) %>%
  arrange(-mean_hwy)
## # A tibble: 15 × 4
##    manufacturer mean_hwy sd_hwy number
##    <chr>           <dbl>  <dbl>  <int>
##  1 honda            32.6   2.55      9
##  2 volkswagen       29.2   5.32     27
##  3 hyundai          26.9   2.18     14
##  4 audi             26.4   2.18     18
##  5 pontiac          26.4   1.14      5
##  6 subaru           25.6   1.16     14
##  7 toyota           24.9   6.17     34
##  8 nissan           24.6   5.09     13
##  9 chevrolet        21.9   5.11     19
## 10 ford             19.4   3.33     25
## 11 mercury          18     1.15      4
## 12 dodge            17.9   3.57     37
## 13 jeep             17.6   3.25      8
## 14 lincoln          17     1         3
## 15 land rover       16.5   1.73      4

这看起来更好了。

summarise_at() 的变体

除了使用summarise()之外,您还可以使用相关的函数,例如summarise_at()。这是summarise()函数的作用范围版本,可以应用于多个列。请注意,在使用summarise_at()时,您需要用引号将要进行汇总的列括起来。您还需要提供汇总函数 - 在本例中为mean。最后,如果我们的数据集包含任何缺失值(由NA表示),我们将设置参数na.rm = TRUE。这将确保在应用操作之前移除缺失的数据点。如果我们有缺失的数据,但没有告诉R我们想要做什么,它会抛出一个错误。

mpg %>% 
  group_by(manufacturer) %>%
  summarise_at(c("displ", "cty", "hwy"), mean, na.rm = TRUE)
## # A tibble: 15 × 4
##    manufacturer displ   cty   hwy
##    <chr>        <dbl> <dbl> <dbl>
##  1 audi          2.54  17.6  26.4
##  2 chevrolet     5.06  15    21.9
##  3 dodge         4.38  13.1  17.9
##  4 ford          4.54  14    19.4
##  5 honda         1.71  24.4  32.6
##  6 hyundai       2.43  18.6  26.9
##  7 jeep          4.58  13.5  17.6
##  8 land rover    4.3   11.5  16.5
##  9 lincoln       5.4   11.3  17  
## 10 mercury       4.4   13.2  18  
## 11 nissan        3.27  18.1  24.6
## 12 pontiac       3.96  17    26.4
## 13 subaru        2.46  19.3  25.6
## 14 toyota        2.95  18.5  24.9
## 15 volkswagen    2.26  20.9  29.2

summarise_if() 的变体

假设我们有一个非常庞大的数据集,并且希望总结所有特定类型的列。我们可以使用summarise_if()函数来计算每个汽车制造商的平均值,如下所示:

mpg %>% 
  group_by(manufacturer) %>%
  summarise_if(is.numeric, mean, na.rm = TRUE)
## # A tibble: 15 × 6
##    manufacturer displ  year   cyl   cty   hwy
##    <chr>        <dbl> <dbl> <dbl> <dbl> <dbl>
##  1 audi          2.54 2004.  5.22  17.6  26.4
##  2 chevrolet     5.06 2005.  7.26  15    21.9
##  3 dodge         4.38 2004.  7.08  13.1  17.9
##  4 ford          4.54 2003.  7.2   14    19.4
##  5 honda         1.71 2003   4     24.4  32.6
##  6 hyundai       2.43 2004.  4.86  18.6  26.9
##  7 jeep          4.58 2006.  7.25  13.5  17.6
##  8 land rover    4.3  2004.  8     11.5  16.5
##  9 lincoln       5.4  2002   8     11.3  17  
## 10 mercury       4.4  2004.  7     13.2  18  
## 11 nissan        3.27 2004.  5.54  18.1  24.6
## 12 pontiac       3.96 2003.  6.4   17    26.4
## 13 subaru        2.46 2004.  4     19.3  25.6
## 14 toyota        2.95 2003.  5.12  18.5  24.9
## 15 volkswagen    2.26 2003.  4.59  20.9  29.2

summarise_if()中的第一个参数是应用于每一列的逻辑测试 - 在这种情况下,如果一列是数值(即,一个数字) - 那么测试结果为TRUE,然后应用第二个函数mean。同样,我们告诉R忽略缺失的(NA)数据值,使用na.rm = TRUE参数。

R函数在参数方面有所不同。我经常忘记它们,如果你开始输入一个函数名,你会在你输入的位置上方得到一个小气泡,提醒你需要哪些参数。如果你记不住细节,你可以在控制台中键入help(function_name)?function_name来获取任何需要帮助的函数的帮助。使用R(或Python或任何其他语言)进行大量的数据分析通常需要大量的搜索。这是正常的。有些东西我永远记不住,总是不得不查一下!

使用mutate()添加列

我们可以使用mutate()函数像这样添加一个新的列,我称之为mean_hwy。

mpg %>% 
  group_by(manufacturer) %>%
  mutate(mean_hwy = mean(hwy), sd_hwy = sd(hwy))
## # A tibble: 234 × 13
## # Groups:   manufacturer [15]
##    manufacturer model      displ  year   cyl trans drv     cty   hwy fl    class
##    <chr>        <chr>      <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
##  1 audi         a4           1.8  1999     4 auto… f        18    29 p     comp…
##  2 audi         a4           1.8  1999     4 manu… f        21    29 p     comp…
##  3 audi         a4           2    2008     4 manu… f        20    31 p     comp…
##  4 audi         a4           2    2008     4 auto… f        21    30 p     comp…
##  5 audi         a4           2.8  1999     6 auto… f        16    26 p     comp…
##  6 audi         a4           2.8  1999     6 manu… f        18    26 p     comp…
##  7 audi         a4           3.1  2008     6 auto… f        18    27 p     comp…
##  8 audi         a4 quattro   1.8  1999     4 manu… 4        18    26 p     comp…
##  9 audi         a4 quattro   1.8  1999     4 auto… 4        16    25 p     comp…
## 10 audi         a4 quattro   2    2008     4 manu… 4        20    28 p     comp…
## # ℹ 224 more rows
## # ℹ 2 more variables: mean_hwy <dbl>, sd_hwy <dbl>

我们在这个页面上有太多的列要显示,所以我们可以通过稍微不同地使用select()函数来删除一些列。通过在select()中的列名前面加上-符号,我们最终删除了它。

mpg %>% 
  group_by(manufacturer) %>%
  mutate(mean_hwy = mean(hwy), sd_hwy = sd(hwy)) %>%
  select(-class, -trans)
## # A tibble: 234 × 11
## # Groups:   manufacturer [15]
##    manufacturer model  displ  year   cyl drv     cty   hwy fl    mean_hwy sd_hwy
##    <chr>        <chr>  <dbl> <int> <int> <chr> <int> <int> <chr>    <dbl>  <dbl>
##  1 audi         a4       1.8  1999     4 f        18    29 p         26.4   2.18
##  2 audi         a4       1.8  1999     4 f        21    29 p         26.4   2.18
##  3 audi         a4       2    2008     4 f        20    31 p         26.4   2.18
##  4 audi         a4       2    2008     4 f        21    30 p         26.4   2.18
##  5 audi         a4       2.8  1999     6 f        16    26 p         26.4   2.18
##  6 audi         a4       2.8  1999     6 f        18    26 p         26.4   2.18
##  7 audi         a4       3.1  2008     6 f        18    27 p         26.4   2.18
##  8 audi         a4 qu…   1.8  1999     4 4        18    26 p         26.4   2.18
##  9 audi         a4 qu…   1.8  1999     4 4        16    25 p         26.4   2.18
## 10 audi         a4 qu…   2    2008     4 4        20    28 p         26.4   2.18
## # ℹ 224 more rows

请注意,这不会永久更改mpg数据集 - 除非我们将此代码的输出映射到新变量,否则不会保存更改。 下面我通过使用赋值运算符<-将其映射到我称为mpg_with_mean新变量来执行此操作。 请注意,我们在最后删除了分组,因为我们不希望分组规则保留在新的数据框中。

mpg_with_mean <- mpg %>% 
  group_by(manufacturer) %>%
    mutate(mean_hwy = mean(hwy), sd_hyw = sd(hwy)) %>%
  ungroup() %>%
  select(-class, -trans) 

然后我们可以使用head()和str()检查这个新变量。

head(mpg_with_mean)
## # A tibble: 6 × 11
##   manufacturer model displ  year   cyl drv     cty   hwy fl    mean_hwy sd_hyw
##   <chr>        <chr> <dbl> <int> <int> <chr> <int> <int> <chr>    <dbl>  <dbl>
## 1 audi         a4      1.8  1999     4 f        18    29 p         26.4   2.18
## 2 audi         a4      1.8  1999     4 f        21    29 p         26.4   2.18
## 3 audi         a4      2    2008     4 f        20    31 p         26.4   2.18
## 4 audi         a4      2    2008     4 f        21    30 p         26.4   2.18
## 5 audi         a4      2.8  1999     6 f        16    26 p         26.4   2.18
## 6 audi         a4      2.8  1999     6 f        18    26 p         26.4   2.18
str(mpg_with_mean)
## tibble [234 × 11] (S3: tbl_df/tbl/data.frame)
##  $ manufacturer: chr [1:234] "audi" "audi" "audi" "audi" ...
##  $ model       : chr [1:234] "a4" "a4" "a4" "a4" ...
##  $ displ       : num [1:234] 1.8 1.8 2 2 2.8 2.8 3.1 1.8 1.8 2 ...
##  $ year        : int [1:234] 1999 1999 2008 2008 1999 1999 2008 1999 1999 2008 ...
##  $ cyl         : int [1:234] 4 4 4 4 6 6 6 4 4 4 ...
##  $ drv         : chr [1:234] "f" "f" "f" "f" ...
##  $ cty         : int [1:234] 18 21 20 21 16 18 18 18 16 20 ...
##  $ hwy         : int [1:234] 29 29 31 30 26 26 27 26 25 28 ...
##  $ fl          : chr [1:234] "p" "p" "p" "p" ...
##  $ mean_hwy    : num [1:234] 26.4 26.4 26.4 26.4 26.4 ...
##  $ sd_hyw      : num [1:234] 2.18 2.18 2.18 2.18 2.18 ...

作业

Tidyverse还有许多其他内置数据集。 另一个是starwars数据集。 您可以通过输入starwars或输入view(starwars)来查看它。 第二个选项将在新窗口中打开数据集。 尝试一下吧。 计算出星球大战宇宙中人类的平均身高。 可能存在一些缺失数据(由NA指示)。 您可以在summarise()函数中使用na.rm = TRUE参数来在生成汇总统计信息时忽略这些值。

过滤掉NA值的另一种方法是在管道中使用filter()函数。 函数is.na()返回逻辑值 TRUEFALSE。 操作符! 表示 NOT,因此当高度值存在时,表达式!is.na(height)将返回 TRUE,如果不存在,则返回 FALSE。 通过将其与filter()相结合,我们得到了行filter(!is.na(height)) ,它将仅过滤我们有高度数据的情况(即!is.na(height)TRUE)。 所以你的代码可能如下所示:

starwars %>%
  filter(!is.na(height)) %>%
  filter(species == "Human") %>%
  summarise(mean_height = mean(height))
## # A tibble: 1 × 1
##   mean_height
##         <dbl>
## 1        177.

summarise()行中的单词mean替换为median 。 你还可以用什么其他东西来代替它? 提示:在控制台中输入?summarise 。 您还可以从此数据集中提取哪些其他摘要信息?

帮助我们改进本节课程

线上自学课程问卷

线上工作坊问卷