版权声明:本套课程材料开源,使用和分享必须遵守「创作共用许可协议 CC BY-NC-SA」(来源引用-非商业用途使用-以相同方式共享)。


数据操作类R包概述与比较

【知识点】data.table核心要素

【探索发现】data.table vs. dplyr (tidyverse) 数据操作代码风格比较

【探索发现】性能大PK:data.table (R) vs. dplyr (R) vs. pandas (Python)

分组汇总速度 (0.5 GB)

(数据规模:1000万行 × 9个变量)

分组汇总速度 (5 GB)

(数据规模:1亿行 × 9个变量)

分组汇总速度 (50 GB)

(数据规模:10亿行 × 9个变量)

增删查改(data.table)

【实践1】增删查改

## 数据准备:大五人格问卷BFI(部分数据)
data = as.data.table(psych::bfi)
d = data[31:50, c("gender", "education", "age")]
d
    gender education   age
     <int>     <int> <int>
 1:      2        NA    17
 2:      2         3    41
 3:      1         5    23
 4:      2        NA    17
 5:      1         3    20
 6:      1         3    23
 7:      1         3    20
 8:      1         3    21
 9:      1        NA    30
10:      2         5    48
11:      2         3    40
12:      2         4    27
13:      1         1    18
14:      1         4    20
15:      2         5    24
16:      1         3    25
17:      1         2    22
18:      2         1    18
19:      2         1    43
20:      1         3    20
    gender education   age
     <int>     <int> <int>
str(d)
Classes 'data.table' and 'data.frame':  20 obs. of  3 variables:
 $ gender   : int  2 2 1 2 1 1 1 1 1 2 ...
 $ education: int  NA 3 5 NA 3 3 3 3 NA 5 ...
 $ age      : int  17 41 23 17 20 23 20 21 30 48 ...
 - attr(*, ".internal.selfref")=<externalptr> 
1. 增加
## 方式 1: 单变量 $ 操作符
d$Gender = factor(d$gender, levels=1:2, labels=c("Male", "Female"))
d
    gender education   age Gender
     <int>     <int> <int> <fctr>
 1:      2        NA    17 Female
 2:      2         3    41 Female
 3:      1         5    23   Male
 4:      2        NA    17 Female
 5:      1         3    20   Male
 6:      1         3    23   Male
 7:      1         3    20   Male
 8:      1         3    21   Male
 9:      1        NA    30   Male
10:      2         5    48 Female
11:      2         3    40 Female
12:      2         4    27 Female
13:      1         1    18   Male
14:      1         4    20   Male
15:      2         5    24 Female
16:      1         3    25   Male
17:      1         2    22   Male
18:      2         1    18 Female
19:      2         1    43 Female
20:      1         3    20   Male
    gender education   age Gender
     <int>     <int> <int> <fctr>
## 方式 2: 单变量 := 运算符 (原地更新)
d[, Gender := factor(gender, levels=1:2, labels=c("Male", "Female"))]
d
    gender education   age Gender
     <int>     <int> <int> <fctr>
 1:      2        NA    17 Female
 2:      2         3    41 Female
 3:      1         5    23   Male
 4:      2        NA    17 Female
 5:      1         3    20   Male
 6:      1         3    23   Male
 7:      1         3    20   Male
 8:      1         3    21   Male
 9:      1        NA    30   Male
10:      2         5    48 Female
11:      2         3    40 Female
12:      2         4    27 Female
13:      1         1    18   Male
14:      1         4    20   Male
15:      2         5    24 Female
16:      1         3    25   Male
17:      1         2    22   Male
18:      2         1    18 Female
19:      2         1    43 Female
20:      1         3    20   Male
    gender education   age Gender
     <int>     <int> <int> <fctr>
## 方式 3: 多变量 let() 函数 (原地更新)
d[, let(
  Gender = factor(gender, levels=1:2, labels=c("Male", "Female")),
  Age = as.numeric(age),
  Edu = as.factor(education)
)]
d
    gender education   age Gender   Age    Edu
     <int>     <int> <int> <fctr> <num> <fctr>
 1:      2        NA    17 Female    17   <NA>
 2:      2         3    41 Female    41      3
 3:      1         5    23   Male    23      5
 4:      2        NA    17 Female    17   <NA>
 5:      1         3    20   Male    20      3
 6:      1         3    23   Male    23      3
 7:      1         3    20   Male    20      3
 8:      1         3    21   Male    21      3
 9:      1        NA    30   Male    30   <NA>
10:      2         5    48 Female    48      5
11:      2         3    40 Female    40      3
12:      2         4    27 Female    27      4
13:      1         1    18   Male    18      1
14:      1         4    20   Male    20      4
15:      2         5    24 Female    24      5
16:      1         3    25   Male    25      3
17:      1         2    22   Male    22      2
18:      2         1    18 Female    18      1
19:      2         1    43 Female    43      1
20:      1         3    20   Male    20      3
    gender education   age Gender   Age    Edu
     <int>     <int> <int> <fctr> <num> <fctr>
str(d)
Classes 'data.table' and 'data.frame':  20 obs. of  6 variables:
 $ gender   : int  2 2 1 2 1 1 1 1 1 2 ...
 $ education: int  NA 3 5 NA 3 3 3 3 NA 5 ...
 $ age      : int  17 41 23 17 20 23 20 21 30 48 ...
 $ Gender   : Factor w/ 2 levels "Male","Female": 2 2 1 2 1 1 1 1 1 2 ...
 $ Age      : num  17 41 23 17 20 23 20 21 30 48 ...
 $ Edu      : Factor w/ 5 levels "1","2","3","4",..: NA 3 5 NA 3 3 3 3 NA 5 ...
 - attr(*, ".internal.selfref")=<externalptr> 

(本小节进度:1/4)

2. 删除
## 单变量
d$Age = d$Edu = NULL
d
    gender education   age Gender
     <int>     <int> <int> <fctr>
 1:      2        NA    17 Female
 2:      2         3    41 Female
 3:      1         5    23   Male
 4:      2        NA    17 Female
 5:      1         3    20   Male
 6:      1         3    23   Male
 7:      1         3    20   Male
 8:      1         3    21   Male
 9:      1        NA    30   Male
10:      2         5    48 Female
11:      2         3    40 Female
12:      2         4    27 Female
13:      1         1    18   Male
14:      1         4    20   Male
15:      2         5    24 Female
16:      1         3    25   Male
17:      1         2    22   Male
18:      2         1    18 Female
19:      2         1    43 Female
20:      1         3    20   Male
    gender education   age Gender
     <int>     <int> <int> <fctr>
## 多变量
d[, let(
  gender = NULL,
  education = NULL,
  age = NULL
)]
d
    Gender
    <fctr>
 1: Female
 2: Female
 3:   Male
 4: Female
 5:   Male
 6:   Male
 7:   Male
 8:   Male
 9:   Male
10: Female
11: Female
12: Female
13:   Male
14:   Male
15: Female
16:   Male
17:   Male
18: Female
19: Female
20:   Male
    Gender
    <fctr>

(本小节进度:2/4)

3. 查找
d = data[31:50, c("gender", "education", "age", paste0("A", 1:5))]
d
    gender education   age    A1    A2    A3    A4    A5
     <int>     <int> <int> <int> <int> <int> <int> <int>
 1:      2        NA    17     1     6     5     6     3
 2:      2         3    41     2     5     6     6     6
 3:      1         5    23     1     5     6     5     4
 4:      2        NA    17     2     4     5     6     5
 5:      1         3    20     4     4     4     4     4
 6:      1         3    23     5     3     5     4     2
 7:      1         3    20     1     6     4     6     4
 8:      1         3    21     1     4     4     2     3
 9:      1        NA    30     1     6     6     6     6
10:      2         5    48     1     5     4     3     5
11:      2         3    40     1     5     5     6     5
12:      2         4    27     5     4     3     6     4
13:      1         1    18     1     5     4     4     5
14:      1         4    20     5     6     4     3     5
15:      2         5    24     2     6     6     6     6
16:      1         3    25     1     6     6     6     6
17:      1         2    22     5     5     3     4     3
18:      2         1    18     2     6     4     5     5
19:      2         1    43     1     5     3     2     3
20:      1         3    20     1     6     6     6     6
    gender education   age    A1    A2    A3    A4    A5
     <int>     <int> <int> <int> <int> <int> <int> <int>
str(d)
Classes 'data.table' and 'data.frame':  20 obs. of  8 variables:
 $ gender   : int  2 2 1 2 1 1 1 1 1 2 ...
 $ education: int  NA 3 5 NA 3 3 3 3 NA 5 ...
 $ age      : int  17 41 23 17 20 23 20 21 30 48 ...
 $ A1       : int  1 2 1 2 4 5 1 1 1 1 ...
 $ A2       : int  6 5 5 4 4 3 6 4 6 5 ...
 $ A3       : int  5 6 6 5 4 5 4 4 6 4 ...
 $ A4       : int  6 6 5 6 4 4 6 2 6 3 ...
 $ A5       : int  3 6 4 5 4 2 4 3 6 5 ...
 - attr(*, ".internal.selfref")=<externalptr> 
d[1:5, "gender"]  # DT[i, j]
   gender
    <int>
1:      2
2:      2
3:      1
4:      2
5:      1
d[1:5, gender]  # DT[i, j]
[1] 2 2 1 2 1
d[1:5, c("gender", "age")]  # DT[i, j]
   gender   age
    <int> <int>
1:      2    17
2:      2    41
3:      1    23
4:      2    17
5:      1    20
d[1:5, .(gender, age)]  # DT[i, j]
   gender   age
    <int> <int>
1:      2    17
2:      2    41
3:      1    23
4:      2    17
5:      1    20
d[1:3]  # DT[i]
   gender education   age    A1    A2    A3    A4    A5
    <int>     <int> <int> <int> <int> <int> <int> <int>
1:      2        NA    17     1     6     5     6     3
2:      2         3    41     2     5     6     6     6
3:      1         5    23     1     5     6     5     4
d[1:3, ]  # DT[i, ]
   gender education   age    A1    A2    A3    A4    A5
    <int>     <int> <int> <int> <int> <int> <int> <int>
1:      2        NA    17     1     6     5     6     3
2:      2         3    41     2     5     6     6     6
3:      1         5    23     1     5     6     5     4
d[, 2:3]  # DT[i, ]
    education   age
        <int> <int>
 1:        NA    17
 2:         3    41
 3:         5    23
 4:        NA    17
 5:         3    20
 6:         3    23
 7:         3    20
 8:         3    21
 9:        NA    30
10:         5    48
11:         3    40
12:         4    27
13:         1    18
14:         4    20
15:         5    24
16:         3    25
17:         2    22
18:         1    18
19:         1    43
20:         3    20
    education   age
        <int> <int>
d[, age:A3]  # DT[, j](变量名范围,不会数数字)
      age    A1    A2    A3
    <int> <int> <int> <int>
 1:    17     1     6     5
 2:    41     2     5     6
 3:    23     1     5     6
 4:    17     2     4     5
 5:    20     4     4     4
 6:    23     5     3     5
 7:    20     1     6     4
 8:    21     1     4     4
 9:    30     1     6     6
10:    48     1     5     4
11:    40     1     5     5
12:    27     5     4     3
13:    18     1     5     4
14:    20     5     6     4
15:    24     2     6     6
16:    25     1     6     6
17:    22     5     5     3
18:    18     2     6     4
19:    43     1     5     3
20:    20     1     6     6
      age    A1    A2    A3
    <int> <int> <int> <int>

(本小节进度:3/4)

4. 修改
d = data[2536:2540, c("gender", "education", "age")]
d
   gender education   age
    <int>     <int> <int>
1:      2         5    56
2:      1         5     3
3:      1         2    65
4:      2         3    34
5:      2         4    29
d[2, "age"] = NA  # 无效年龄(3岁),替换为NA缺失值
d
   gender education   age
    <int>     <int> <int>
1:      2         5    56
2:      1         5    NA
3:      1         2    65
4:      2         3    34
5:      2         4    29
  • Q:如何自动筛选、替换无效年龄?
    • A:请看下一部分

(本小节进度:4/4)

行列筛选(data.table)

【实践2】行列筛选

## 数据准备:大五人格问卷BFI(部分数据)
data = as.data.table(psych::bfi)
data[, let(
  Gender = factor(gender, levels=1:2, labels=c("Male", "Female")),
  Age = as.numeric(age),
  Edu = as.factor(education)
)]
d = data[2535:2546, c("Gender", "Age", "Edu", paste0("A", 1:5))]
d
    Gender   Age    Edu    A1    A2    A3    A4    A5
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>
 1: Female    20      3     1     6     6     6     6
 2: Female    56      5     3     5     3     5     5
 3:   Male     3      5     2     5     5     4     5
 4:   Male    65      2     5     4     2     6     4
 5: Female    34      3     2     4     3     4     4
 6: Female    29      4     1     6     5     3     5
 7: Female    21      4     4     4     5     4     5
 8: Female    32      2     3     5     4    NA     6
 9:   Male    26      2     2     6     5     4     4
10:   Male    27      4     2     2     1     2     3
11: Female    45      4     1     5     5     6     6
12:   Male    17   <NA>     2     4     4     3     4
str(d)
Classes 'data.table' and 'data.frame':  12 obs. of  8 variables:
 $ Gender: Factor w/ 2 levels "Male","Female": 2 2 1 1 2 2 2 2 1 1 ...
 $ Age   : num  20 56 3 65 34 29 21 32 26 27 ...
 $ Edu   : Factor w/ 5 levels "1","2","3","4",..: 3 5 5 2 3 4 4 2 2 4 ...
 $ A1    : int  1 3 2 5 2 1 4 3 2 2 ...
 $ A2    : int  6 5 5 4 4 6 4 5 6 2 ...
 $ A3    : int  6 3 5 2 3 5 5 4 5 1 ...
 $ A4    : int  6 5 4 6 4 3 4 NA 4 2 ...
 $ A5    : int  6 5 5 4 4 5 5 6 4 3 ...
 - attr(*, ".internal.selfref")=<externalptr> 

1. 行筛选
d[Gender == "Female"]
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1: Female    20      3     1     6     6     6     6
2: Female    56      5     3     5     3     5     5
3: Female    34      3     2     4     3     4     4
4: Female    29      4     1     6     5     3     5
5: Female    21      4     4     4     5     4     5
6: Female    32      2     3     5     4    NA     6
7: Female    45      4     1     5     5     6     6
d[Gender == "Male"]
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1:   Male     3      5     2     5     5     4     5
2:   Male    65      2     5     4     2     6     4
3:   Male    26      2     2     6     5     4     4
4:   Male    27      4     2     2     1     2     3
5:   Male    17   <NA>     2     4     4     3     4
d[Gender == "Male" & Age >= 16]
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1:   Male    65      2     5     4     2     6     4
2:   Male    26      2     2     6     5     4     4
3:   Male    27      4     2     2     1     2     3
4:   Male    17   <NA>     2     4     4     3     4
d[Gender == "Male" & Age >= 16 & !is.na(Edu)]
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1:   Male    65      2     5     4     2     6     4
2:   Male    26      2     2     6     5     4     4
3:   Male    27      4     2     2     1     2     3
d[Gender == "Male" & Age %in% 20:45]
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1:   Male    26      2     2     6     5     4     4
2:   Male    27      4     2     2     1     2     3
d[Gender == "Male" & Age %notin% 20:45]
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1:   Male     3      5     2     5     5     4     5
2:   Male    65      2     5     4     2     6     4
3:   Male    17   <NA>     2     4     4     3     4
d[Gender == "Male" & (Age < 20 | Age > 45)]
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1:   Male     3      5     2     5     5     4     5
2:   Male    65      2     5     4     2     6     4
3:   Male    17   <NA>     2     4     4     3     4
d[Age < 15]
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1:   Male     3      5     2     5     5     4     5
d[Age < 15, "Age"] = NA  # 自动筛选、替换无效年龄
d
    Gender   Age    Edu    A1    A2    A3    A4    A5
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>
 1: Female    20      3     1     6     6     6     6
 2: Female    56      5     3     5     3     5     5
 3:   Male    NA      5     2     5     5     4     5
 4:   Male    65      2     5     4     2     6     4
 5: Female    34      3     2     4     3     4     4
 6: Female    29      4     1     6     5     3     5
 7: Female    21      4     4     4     5     4     5
 8: Female    32      2     3     5     4    NA     6
 9:   Male    26      2     2     6     5     4     4
10:   Male    27      4     2     2     1     2     3
11: Female    45      4     1     5     5     6     6
12:   Male    17   <NA>     2     4     4     3     4

(本小节进度:1/3)

2. 列筛选
d = data[2535:2546, c("Gender", "Age", "Edu", paste0("A", 1:5))]

## 直接筛选列
d[, Age:A3]  # DT[, j](变量名范围,不会数数字)
      Age    Edu    A1    A2    A3
    <num> <fctr> <int> <int> <int>
 1:    20      3     1     6     6
 2:    56      5     3     5     3
 3:     3      5     2     5     5
 4:    65      2     5     4     2
 5:    34      3     2     4     3
 6:    29      4     1     6     5
 7:    21      4     4     4     5
 8:    32      2     3     5     4
 9:    26      2     2     6     5
10:    27      4     2     2     1
11:    45      4     1     5     5
12:    17   <NA>     2     4     4
d[, .(A1, A2, A3, Edu, Age)]
       A1    A2    A3    Edu   Age
    <int> <int> <int> <fctr> <num>
 1:     1     6     6      3    20
 2:     3     5     3      5    56
 3:     2     5     5      5     3
 4:     5     4     2      2    65
 5:     2     4     3      3    34
 6:     1     6     5      4    29
 7:     4     4     5      4    21
 8:     3     5     4      2    32
 9:     2     6     5      2    26
10:     2     2     1      4    27
11:     1     5     5      4    45
12:     2     4     4   <NA>    17
## 间接筛选列
vars = c("Age", "Edu")
try({
  d[, vars]  # 报错,vars不是data.table内部环境中的变量名
})
Error in `[.data.table`(d, , vars) : 
  j(在 [...] 中的第二个参数)是单一符号,但未找到列名 'vars'。如果你打算在调用环境中使用变量选择列,请尝试 DT[, ..vars]。.. 前缀表示上一级,类似于文件系统路径。
d[, ..vars]  # ..表示从data.table内部环境返回到全局环境,使用变量选择列
      Age    Edu
    <num> <fctr>
 1:    20      3
 2:    56      5
 3:     3      5
 4:    65      2
 5:    34      3
 6:    29      4
 7:    21      4
 8:    32      2
 9:    26      2
10:    27      4
11:    45      4
12:    17   <NA>
## 还可以使用 dplyr::select() 函数,搭配 tidyselect 系列函数
select(d, starts_with("A"))
      Age    A1    A2    A3    A4    A5
    <num> <int> <int> <int> <int> <int>
 1:    20     1     6     6     6     6
 2:    56     3     5     3     5     5
 3:     3     2     5     5     4     5
 4:    65     5     4     2     6     4
 5:    34     2     4     3     4     4
 6:    29     1     6     5     3     5
 7:    21     4     4     5     4     5
 8:    32     3     5     4    NA     6
 9:    26     2     6     5     4     4
10:    27     2     2     1     2     3
11:    45     1     5     5     6     6
12:    17     2     4     4     3     4
select(d, matches("A\\d"))  # 正则表达式
       A1    A2    A3    A4    A5
    <int> <int> <int> <int> <int>
 1:     1     6     6     6     6
 2:     3     5     3     5     5
 3:     2     5     5     4     5
 4:     5     4     2     6     4
 5:     2     4     3     4     4
 6:     1     6     5     3     5
 7:     4     4     5     4     5
 8:     3     5     4    NA     6
 9:     2     6     5     4     4
10:     2     2     1     2     3
11:     1     5     5     6     6
12:     2     4     4     3     4
select(d, num_range("A", 1:5))  # 题序号范围
       A1    A2    A3    A4    A5
    <int> <int> <int> <int> <int>
 1:     1     6     6     6     6
 2:     3     5     3     5     5
 3:     2     5     5     4     5
 4:     5     4     2     6     4
 5:     2     4     3     4     4
 6:     1     6     5     3     5
 7:     4     4     5     4     5
 8:     3     5     4    NA     6
 9:     2     6     5     4     4
10:     2     2     1     2     3
11:     1     5     5     6     6
12:     2     4     4     3     4
d %>% select(num_range("A", 1:5))  # 管道操作符
       A1    A2    A3    A4    A5
    <int> <int> <int> <int> <int>
 1:     1     6     6     6     6
 2:     3     5     3     5     5
 3:     2     5     5     4     5
 4:     5     4     2     6     4
 5:     2     4     3     4     4
 6:     1     6     5     3     5
 7:     4     4     5     4     5
 8:     3     5     4    NA     6
 9:     2     6     5     4     4
10:     2     2     1     2     3
11:     1     5     5     6     6
12:     2     4     4     3     4

拓展了解:tidyselect变量选择语法

(本小节进度:2/3)

3. 综合练习
data[Age >= 18 & Edu == 5]
        A1    A2    A3    A4    A5    C1    C2    C3    C4    C5    E1    E2
     <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
  1:     1     5     6     5     6     4     3     2     4     5     2     1
  2:     2     4     4     4     3     6     5     6     1     1     2     4
  3:     1     5     6     5     4     1     5     6     4     6     6     6
  4:     1     5     4     3     5     6     5     5     2     2     3     2
  5:     2     6     6     6     6     5     4     5     3     4     2     2
 ---                                                                        
413:     1     6     6     5     6     5     5     3     2     4     1     5
414:     1     6     6     6     6     6     6     6     2     1     4     3
415:     2     5     4     5     4     6     5     5     2     4     6     5
416:     2     6     5     4     5     4     4     1     4     1     1     5
417:     3     4     4     3     5     6     6     5     2     1     2     2
        E3    E4    E5    N1    N2    N3    N4    N5    O1    O2    O3    O4
     <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
  1:     2     5     2     2     2     2     2     2     6     1     5     5
  2:     4     2     6     3     3     5     3     2     5     2     6     6
  3:     2     1     1     1     2     1     3     6     6     6     5     6
  4:     3     6     5     1     2     1     2     1     5     1     6     6
  5:     4     5     5     2     2     2     2     3     5     2     5     5
 ---                                                                        
413:     4     4     2     1     1     1     4     2     6     1     6     6
414:     6     6     6     2     6     4     5     5     6     1     6     6
415:     2     3     5     1     1     3     4     1     5     1     4     6
416:     4     5     5    NA     1     4     2     4     5     4     5     5
417:     4     5     5     4     4     3     2     2     5     4     4     3
        O5 gender education   age Gender   Age    Edu
     <int>  <int>     <int> <int> <fctr> <num> <fctr>
  1:     2      1         5    68   Male    68      5
  2:     1      2         5    51 Female    51      5
  3:     1      1         5    23   Male    23      5
  4:     1      2         5    48 Female    48      5
  5:     1      2         5    24 Female    24      5
 ---                                                 
413:     1      1         5    28   Male    28      5
414:     1      2         5    26 Female    26      5
415:     1      2         5    40 Female    40      5
416:     1      1         5    28   Male    28      5
417:     4      2         5    33 Female    33      5
data[, A1:C5]
         A1    A2    A3    A4    A5    C1    C2    C3    C4    C5
      <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
   1:     2     4     3     4     4     2     3     3     4     4
   2:     2     4     5     2     5     5     4     4     3     4
   3:     5     4     5     4     4     4     5     4     2     5
   4:     4     4     6     5     5     4     4     3     5     5
   5:     2     3     3     4     5     4     4     5     3     2
  ---                                                            
2796:     6     1     3     3     3     6     6     6     1     1
2797:     2     4     4     3     5     2     3     4     4     3
2798:     2     3     5     2     5     5     5     5     1     1
2799:     5     2     2     4     4     5     5     5     2     6
2800:     2     3     1     4     2     5     5     3     3     3
data[, Gender:Edu]
      Gender   Age    Edu
      <fctr> <num> <fctr>
   1:   Male    16   <NA>
   2: Female    18   <NA>
   3: Female    17   <NA>
   4: Female    17   <NA>
   5:   Male    17   <NA>
  ---                    
2796:   Male    19      3
2797:   Male    27      4
2798: Female    29      4
2799:   Male    31      4
2800: Female    50      4
data[, .(Gender, Edu)]
      Gender    Edu
      <fctr> <fctr>
   1:   Male   <NA>
   2: Female   <NA>
   3: Female   <NA>
   4: Female   <NA>
   5:   Male   <NA>
  ---              
2796:   Male      3
2797:   Male      4
2798: Female      4
2799:   Male      4
2800: Female      4
data[Age >= 18 & Edu == 5, .(Gender, Age, Edu)]
     Gender   Age    Edu
     <fctr> <num> <fctr>
  1:   Male    68      5
  2: Female    51      5
  3:   Male    23      5
  4: Female    48      5
  5: Female    24      5
 ---                    
413:   Male    28      5
414: Female    26      5
415: Female    40      5
416:   Male    28      5
417: Female    33      5
data %>% select(A1:C5)
         A1    A2    A3    A4    A5    C1    C2    C3    C4    C5
      <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
   1:     2     4     3     4     4     2     3     3     4     4
   2:     2     4     5     2     5     5     4     4     3     4
   3:     5     4     5     4     4     4     5     4     2     5
   4:     4     4     6     5     5     4     4     3     5     5
   5:     2     3     3     4     5     4     4     5     3     2
  ---                                                            
2796:     6     1     3     3     3     6     6     6     1     1
2797:     2     4     4     3     5     2     3     4     4     3
2798:     2     3     5     2     5     5     5     5     1     1
2799:     5     2     2     4     4     5     5     5     2     6
2800:     2     3     1     4     2     5     5     3     3     3
data %>% select(matches("^E"))
         E1    E2    E3    E4    E5 education    Edu
      <int> <int> <int> <int> <int>     <int> <fctr>
   1:     3     3     3     4     4        NA   <NA>
   2:     1     1     6     4     3        NA   <NA>
   3:     2     4     4     4     5        NA   <NA>
   4:     5     3     4     4     4        NA   <NA>
   5:     2     2     5     4     5        NA   <NA>
  ---                                               
2796:     1     4     5     5     6         3      3
2797:     2     2     4     4     3         4      4
2798:     2     2     6     3     6         4      4
2799:     2     2     4     5     4         4      4
2800:     3     3     1     2     2         4      4
data %>% select(matches("E\\d"))
         E1    E2    E3    E4    E5
      <int> <int> <int> <int> <int>
   1:     3     3     3     4     4
   2:     1     1     6     4     3
   3:     2     4     4     4     5
   4:     5     3     4     4     4
   5:     2     2     5     4     5
  ---                              
2796:     1     4     5     5     6
2797:     2     2     4     4     3
2798:     2     2     6     3     6
2799:     2     2     4     5     4
2800:     3     3     1     2     2
data %>% select(num_range("A", 1:5))
         A1    A2    A3    A4    A5
      <int> <int> <int> <int> <int>
   1:     2     4     3     4     4
   2:     2     4     5     2     5
   3:     5     4     5     4     4
   4:     4     4     6     5     5
   5:     2     3     3     4     5
  ---                              
2796:     6     1     3     3     3
2797:     2     4     4     3     5
2798:     2     3     5     2     5
2799:     5     2     2     4     4
2800:     2     3     1     4     2

(本小节进度:3/3)

排序去重(data.table)

【实践3】排序去重

## 数据准备:大五人格问卷BFI(部分数据)
data = as.data.table(psych::bfi)
data[, let(
  Gender = factor(gender, levels=1:2, labels=c("Male", "Female")),
  Age = as.numeric(age),
  Edu = as.factor(education)
)]
d = data[2535:2546, c("Gender", "Age", "Edu", paste0("A", 1:5))]
d
    Gender   Age    Edu    A1    A2    A3    A4    A5
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>
 1: Female    20      3     1     6     6     6     6
 2: Female    56      5     3     5     3     5     5
 3:   Male     3      5     2     5     5     4     5
 4:   Male    65      2     5     4     2     6     4
 5: Female    34      3     2     4     3     4     4
 6: Female    29      4     1     6     5     3     5
 7: Female    21      4     4     4     5     4     5
 8: Female    32      2     3     5     4    NA     6
 9:   Male    26      2     2     6     5     4     4
10:   Male    27      4     2     2     1     2     3
11: Female    45      4     1     5     5     6     6
12:   Male    17   <NA>     2     4     4     3     4
str(d)
Classes 'data.table' and 'data.frame':  12 obs. of  8 variables:
 $ Gender: Factor w/ 2 levels "Male","Female": 2 2 1 1 2 2 2 2 1 1 ...
 $ Age   : num  20 56 3 65 34 29 21 32 26 27 ...
 $ Edu   : Factor w/ 5 levels "1","2","3","4",..: 3 5 5 2 3 4 4 2 2 4 ...
 $ A1    : int  1 3 2 5 2 1 4 3 2 2 ...
 $ A2    : int  6 5 5 4 4 6 4 5 6 2 ...
 $ A3    : int  6 3 5 2 3 5 5 4 5 1 ...
 $ A4    : int  6 5 4 6 4 3 4 NA 4 2 ...
 $ A5    : int  6 5 5 4 4 5 5 6 4 3 ...
 - attr(*, ".internal.selfref")=<externalptr> 
1. 排序
d[order(Gender, Age, Edu)]  # 正序
    Gender   Age    Edu    A1    A2    A3    A4    A5
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>
 1:   Male     3      5     2     5     5     4     5
 2:   Male    17   <NA>     2     4     4     3     4
 3:   Male    26      2     2     6     5     4     4
 4:   Male    27      4     2     2     1     2     3
 5:   Male    65      2     5     4     2     6     4
 6: Female    20      3     1     6     6     6     6
 7: Female    21      4     4     4     5     4     5
 8: Female    29      4     1     6     5     3     5
 9: Female    32      2     3     5     4    NA     6
10: Female    34      3     2     4     3     4     4
11: Female    45      4     1     5     5     6     6
12: Female    56      5     3     5     3     5     5
d[order(-Gender, -Age, -Edu)]  # 倒序
    Gender   Age    Edu    A1    A2    A3    A4    A5
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>
 1: Female    56      5     3     5     3     5     5
 2: Female    45      4     1     5     5     6     6
 3: Female    34      3     2     4     3     4     4
 4: Female    32      2     3     5     4    NA     6
 5: Female    29      4     1     6     5     3     5
 6: Female    21      4     4     4     5     4     5
 7: Female    20      3     1     6     6     6     6
 8:   Male    65      2     5     4     2     6     4
 9:   Male    27      4     2     2     1     2     3
10:   Male    26      2     2     6     5     4     4
11:   Male    17   <NA>     2     4     4     3     4
12:   Male     3      5     2     5     5     4     5
d[order(-Gender, -Age, -Edu)][Age <= 20]  # [ ][ ][ ] 依次执行,无限叠加
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1: Female    20      3     1     6     6     6     6
2:   Male    17   <NA>     2     4     4     3     4
3:   Male     3      5     2     5     5     4     5

(本小节进度:1/2)

2. 去重
unique(d, by="Gender")  # 根据某个变量去重,重复数据取第一个
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1: Female    20      3     1     6     6     6     6
2:   Male     3      5     2     5     5     4     5
unique(d, by=c("Gender", "Edu"))  # 根据多个变量去重,重复数据取第一个
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1: Female    20      3     1     6     6     6     6
2: Female    56      5     3     5     3     5     5
3:   Male     3      5     2     5     5     4     5
4:   Male    65      2     5     4     2     6     4
5: Female    29      4     1     6     5     3     5
6: Female    32      2     3     5     4    NA     6
7:   Male    27      4     2     2     1     2     3
8:   Male    17   <NA>     2     4     4     3     4
unique(d[order(-Gender, -Age, -Edu)], by=c("Gender", "Edu"))
   Gender   Age    Edu    A1    A2    A3    A4    A5
   <fctr> <num> <fctr> <int> <int> <int> <int> <int>
1: Female    56      5     3     5     3     5     5
2: Female    45      4     1     5     5     6     6
3: Female    34      3     2     4     3     4     4
4: Female    32      2     3     5     4    NA     6
5:   Male    65      2     5     4     2     6     4
6:   Male    27      4     2     2     1     2     3
7:   Male    17   <NA>     2     4     4     3     4
8:   Male     3      5     2     5     5     4     5

(本小节进度:2/2)

【自由练习】数据基本操作

参考前三小节代码(增删查改、行列筛选、排序去重),基于psych::bfi或期末自选数据,在自己电脑上自由练习数据基本操作,为【阶段作业①】做准备。

  • 可以尝试改变上述示例代码中的数值范围、变量范围、筛选条件、排序方式等
  • 自己敲代码,掌握更扎实!(AI替代不了你的肌肉记忆!)

分组汇总(data.table)

【实践4】分组汇总

## 数据准备:大五人格问卷BFI(部分数据)
data = as.data.table(psych::bfi)
data[, let(
  Gender = factor(gender, levels=1:2, labels=c("Male", "Female")),
  Age = as.numeric(age),
  Edu = as.factor(education)
)]
d = data[2535:2546, c("Gender", "Age", "Edu", paste0("A", 1:5))]
d
    Gender   Age    Edu    A1    A2    A3    A4    A5
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>
 1: Female    20      3     1     6     6     6     6
 2: Female    56      5     3     5     3     5     5
 3:   Male     3      5     2     5     5     4     5
 4:   Male    65      2     5     4     2     6     4
 5: Female    34      3     2     4     3     4     4
 6: Female    29      4     1     6     5     3     5
 7: Female    21      4     4     4     5     4     5
 8: Female    32      2     3     5     4    NA     6
 9:   Male    26      2     2     6     5     4     4
10:   Male    27      4     2     2     1     2     3
11: Female    45      4     1     5     5     6     6
12:   Male    17   <NA>     2     4     4     3     4
str(d)
Classes 'data.table' and 'data.frame':  12 obs. of  8 variables:
 $ Gender: Factor w/ 2 levels "Male","Female": 2 2 1 1 2 2 2 2 1 1 ...
 $ Age   : num  20 56 3 65 34 29 21 32 26 27 ...
 $ Edu   : Factor w/ 5 levels "1","2","3","4",..: 3 5 5 2 3 4 4 2 2 4 ...
 $ A1    : int  1 3 2 5 2 1 4 3 2 2 ...
 $ A2    : int  6 5 5 4 4 6 4 5 6 2 ...
 $ A3    : int  6 3 5 2 3 5 5 4 5 1 ...
 $ A4    : int  6 5 4 6 4 3 4 NA 4 2 ...
 $ A5    : int  6 5 5 4 4 5 5 6 4 3 ...
 - attr(*, ".internal.selfref")=<externalptr> 
1. 分组聚合

DT[i, j, by]

  • by:定义分组变量(原始顺序)
  • keyby:定义分组变量(重新排序)

## by分组,原始顺序
d[, .(.N), by=Gender]  # .N 是data.table保留关键字,用于统计样本量
   Gender     N
   <fctr> <int>
1: Female     7
2:   Male     5
## keyby分组,重新排序
d[, .(.N), keyby=Gender]  # .N 是data.table保留关键字,用于统计样本量
Key: <Gender>
   Gender     N
   <fctr> <int>
1:   Male     5
2: Female     7
d[, .(.N, Mean.Age = mean(Age)), keyby=Gender]
Key: <Gender>
   Gender     N Mean.Age
   <fctr> <int>    <num>
1:   Male     5    27.60
2: Female     7    33.86
d[, .(
  .N,
  Mean.Age = mean(Age),
  SD.Age = sd(Age)
), keyby=Gender]
Key: <Gender>
   Gender     N Mean.Age SD.Age
   <fctr> <int>    <num>  <num>
1:   Male     5    27.60  23.02
2: Female     7    33.86  12.90
d[Age >= 15, .(
  .N,
  Mean.Age = mean(Age),
  SD.Age = sd(Age)
), keyby=Gender]
Key: <Gender>
   Gender     N Mean.Age SD.Age
   <fctr> <int>    <num>  <num>
1:   Male     4    33.75  21.31
2: Female     7    33.86  12.90
## 全部数据的分组统计
# Education:
# 1 = high school
# 2 = finished high school
# 3 = some college
# 4 = college graduate
# 5 = graduate degree
data[, .(
  .N,
  Mean.Age = mean(Age)
), keyby=.(Gender, Edu)]
Key: <Gender, Edu>
    Gender    Edu     N Mean.Age
    <fctr> <fctr> <int>    <num>
 1:   Male   <NA>    81    18.88
 2:   Male      1    93    25.15
 3:   Male      2   103    31.47
 4:   Male      3   356    25.39
 5:   Male      4   134    33.17
 6:   Male      5   152    33.95
 7: Female   <NA>   142    17.42
 8: Female      1   131    25.12
 9: Female      2   189    31.54
10: Female      3   893    27.96
11: Female      4   260    32.88
12: Female      5   266    36.08

(本小节进度:1/2)

2. 分组计算
d[, Mean.Age := mean(Age)]  # 总均值
d
    Gender   Age    Edu    A1    A2    A3    A4    A5 Mean.Age
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>    <num>
 1: Female    20      3     1     6     6     6     6    31.25
 2: Female    56      5     3     5     3     5     5    31.25
 3:   Male     3      5     2     5     5     4     5    31.25
 4:   Male    65      2     5     4     2     6     4    31.25
 5: Female    34      3     2     4     3     4     4    31.25
 6: Female    29      4     1     6     5     3     5    31.25
 7: Female    21      4     4     4     5     4     5    31.25
 8: Female    32      2     3     5     4    NA     6    31.25
 9:   Male    26      2     2     6     5     4     4    31.25
10:   Male    27      4     2     2     1     2     3    31.25
11: Female    45      4     1     5     5     6     6    31.25
12:   Male    17   <NA>     2     4     4     3     4    31.25
d[, Mean.Age.G := mean(Age), keyby=Gender]  # 组均值
d
Key: <Gender>
    Gender   Age    Edu    A1    A2    A3    A4    A5 Mean.Age Mean.Age.G
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>    <num>      <num>
 1:   Male     3      5     2     5     5     4     5    31.25      27.60
 2:   Male    65      2     5     4     2     6     4    31.25      27.60
 3:   Male    26      2     2     6     5     4     4    31.25      27.60
 4:   Male    27      4     2     2     1     2     3    31.25      27.60
 5:   Male    17   <NA>     2     4     4     3     4    31.25      27.60
 6: Female    20      3     1     6     6     6     6    31.25      33.86
 7: Female    56      5     3     5     3     5     5    31.25      33.86
 8: Female    34      3     2     4     3     4     4    31.25      33.86
 9: Female    29      4     1     6     5     3     5    31.25      33.86
10: Female    21      4     4     4     5     4     5    31.25      33.86
11: Female    32      2     3     5     4    NA     6    31.25      33.86
12: Female    45      4     1     5     5     6     6    31.25      33.86
d[Gender=="Male", AgeGroup := ifelse(Age<40, "Young", "Middle")]
d
Key: <Gender>
    Gender   Age    Edu    A1    A2    A3    A4    A5 Mean.Age Mean.Age.G
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>    <num>      <num>
 1:   Male     3      5     2     5     5     4     5    31.25      27.60
 2:   Male    65      2     5     4     2     6     4    31.25      27.60
 3:   Male    26      2     2     6     5     4     4    31.25      27.60
 4:   Male    27      4     2     2     1     2     3    31.25      27.60
 5:   Male    17   <NA>     2     4     4     3     4    31.25      27.60
 6: Female    20      3     1     6     6     6     6    31.25      33.86
 7: Female    56      5     3     5     3     5     5    31.25      33.86
 8: Female    34      3     2     4     3     4     4    31.25      33.86
 9: Female    29      4     1     6     5     3     5    31.25      33.86
10: Female    21      4     4     4     5     4     5    31.25      33.86
11: Female    32      2     3     5     4    NA     6    31.25      33.86
12: Female    45      4     1     5     5     6     6    31.25      33.86
    AgeGroup
      <char>
 1:    Young
 2:   Middle
 3:    Young
 4:    Young
 5:    Young
 6:     <NA>
 7:     <NA>
 8:     <NA>
 9:     <NA>
10:     <NA>
11:     <NA>
12:     <NA>
## 总均值中心化
d[, Age.Grand.C := Age - mean(Age)]
d[, .(Gender, Age, Mean.Age, Age.Grand.C)]
Key: <Gender>
    Gender   Age Mean.Age Age.Grand.C
    <fctr> <num>    <num>       <num>
 1:   Male     3    31.25      -28.25
 2:   Male    65    31.25       33.75
 3:   Male    26    31.25       -5.25
 4:   Male    27    31.25       -4.25
 5:   Male    17    31.25      -14.25
 6: Female    20    31.25      -11.25
 7: Female    56    31.25       24.75
 8: Female    34    31.25        2.75
 9: Female    29    31.25       -2.25
10: Female    21    31.25      -10.25
11: Female    32    31.25        0.75
12: Female    45    31.25       13.75
## 组均值中心化
d[, Age.Group.C := Age - mean(Age), keyby=Gender]
d[, .(Gender, Age, Mean.Age, Mean.Age.G, Age.Group.C)]
Key: <Gender>
    Gender   Age Mean.Age Mean.Age.G Age.Group.C
    <fctr> <num>    <num>      <num>       <num>
 1:   Male     3    31.25      27.60    -24.6000
 2:   Male    65    31.25      27.60     37.4000
 3:   Male    26    31.25      27.60     -1.6000
 4:   Male    27    31.25      27.60     -0.6000
 5:   Male    17    31.25      27.60    -10.6000
 6: Female    20    31.25      33.86    -13.8571
 7: Female    56    31.25      33.86     22.1429
 8: Female    34    31.25      33.86      0.1429
 9: Female    29    31.25      33.86     -4.8571
10: Female    21    31.25      33.86    -12.8571
11: Female    32    31.25      33.86     -1.8571
12: Female    45    31.25      33.86     11.1429

【知识点】data.table核心知识点总结

(本小节进度:2/2)

匹配拼接(dplyr)

【知识点】dplyr包:join系列函数

两个数据d1d2具有相同变量"var"

  • left_join(d1, d2, by="var"):向d1合并⭐️(最常用)
  • right_join(d1, d2, by="var"):向d2合并
  • inner_join(d1, d2, by="var"):取d1d2交集合并
  • full_join(d1, d2, by="var"):取d1d2并集合并

(data.table也能完成匹配拼接操作,但比dplyr难用)

【实践5】匹配拼接

1. 匹配拼接-例1
## 数据准备:两个来源的数据,至少包含一个共同变量
d1 = as.data.table(dplyr::band_members)
d1
     name    band
   <char>  <char>
1:   Mick  Stones
2:   John Beatles
3:   Paul Beatles
d2 = as.data.table(dplyr::band_instruments)
d2
     name  plays
   <char> <char>
1:   John guitar
2:   Paul   bass
3:  Keith guitar
d3 = as.data.table(dplyr::band_instruments2)
d3
   artist  plays
   <char> <char>
1:   John guitar
2:   Paul   bass
3:  Keith guitar
## 匹配拼接:相同变量名
data = left_join(d1, d2, by="name")  # 向左边数据合并
data
     name    band  plays
   <char>  <char> <char>
1:   Mick  Stones   <NA>
2:   John Beatles guitar
3:   Paul Beatles   bass
right_join(d1, d2, by="name")  # 向右边数据合并
     name    band  plays
   <char>  <char> <char>
1:   John Beatles guitar
2:   Paul Beatles   bass
3:  Keith    <NA> guitar
inner_join(d1, d2, by="name")  # 两个数据的交集
     name    band  plays
   <char>  <char> <char>
1:   John Beatles guitar
2:   Paul Beatles   bass
full_join(d1, d2, by="name")  # 两个数据的并集
     name    band  plays
   <char>  <char> <char>
1:   Mick  Stones   <NA>
2:   John Beatles guitar
3:   Paul Beatles   bass
4:  Keith    <NA> guitar
## 匹配拼接:不同变量名
names(d1)  # 人名变量为"name"
[1] "name" "band"
names(d3)  # 人名变量为"artist"
[1] "artist" "plays" 
data = left_join(d1, d3, by=c("name"="artist"))
data
     name    band  plays
   <char>  <char> <char>
1:   Mick  Stones   <NA>
2:   John Beatles guitar
3:   Paul Beatles   bass

(本小节进度:1/2)

2. 匹配拼接-例2
set.seed(1)
d = data.table(x=rnorm(9), city=rep(1:3, each=3))
d
         x  city
     <num> <int>
1: -0.6265     1
2:  0.1836     1
3: -0.8356     1
4:  1.5953     2
5:  0.3295     2
6: -0.8205     2
7:  0.4874     3
8:  0.7383     3
9:  0.5758     3
d.group = data.table(
  city = 1:3,
  label = c("北京", "上海", "广州"),
  GDP = c(521, 567, 310)
)
d.group
    city  label   GDP
   <int> <char> <num>
1:     1   北京   521
2:     2   上海   567
3:     3   广州   310
d.merge = left_join(d, d.group, by="city")
d.merge
         x  city  label   GDP
     <num> <int> <char> <num>
1: -0.6265     1   北京   521
2:  0.1836     1   北京   521
3: -0.8356     1   北京   521
4:  1.5953     2   上海   567
5:  0.3295     2   上海   567
6: -0.8205     2   上海   567
7:  0.4874     3   广州   310
8:  0.7383     3   广州   310
9:  0.5758     3   广州   310

(本小节进度:2/2)

长宽转换(tidyr)

【知识点】宽数据 vs. 长数据

  • 宽数据(wide-format data)—— “汇总表”或“透视表”
    • 每个被观测的对象只占一行,而该对象的多个属性或随时间变化的观测值作为不同的列横向展开
      • 核心特征:一主体一行,多变量多列
      • 灵活性:增加新变量需增加新列
      • 优点:对人类阅读比较友好,很像我们常见的电子表格或汇总报表,很多统计模型的输入也要求是宽格式
      • 缺点:不利于进行某些分析和可视化,因为数据维度(变量)被锁定在列结构中
↑ 宽数据示例
↑ 宽数据示例
  • 长数据(long-format data)—— “流水记录”或“规范化”的数据库表
    • 每个被观测的对象会占据多行,每一行通常只包含一个变量在某一个时间点或条件下的观测值
      • 核心特征:一观测一行,键值对形式
      • 灵活性:增加新观测或变量只需增加新行,结构稳定
      • 优点:结构规整,是整洁数据的标准格式,特别适合用ggplot2等工具进行数据可视化,也便于进行分组、聚合和复杂变换,数据库存储也常采用类似结构
      • 缺点:对人类阅读不太直观,显得冗长
↑ 长数据示例
↑ 长数据示例

【知识点】tidyr包:pivot系列函数

(data.table也能完成长宽转换操作,但比tidyr难用)

【实践6】长宽转换

1. 宽变长
bruceR::within.1  # 被试内重复测量(宽数据)
  ID A1 A2 A3 A4
1 S1  3  4  8  9
2 S2  6  6  9  8
3 S3  4  4  8  8
4 S4  3  2  7  7
5 S5  5  4  5 12
6 S6  7  5  6 13
7 S7  5  3  7 12
8 S8  2  3  6 11
d.long.1 = pivot_longer(
  data = within.1,
  cols = A1:A4,
  names_to = "Condition",
  values_to = "Y"
) %>% as.data.table()
d.long.1  # 长数据
        ID Condition     Y
    <char>    <char> <num>
 1:     S1        A1     3
 2:     S1        A2     4
 3:     S1        A3     8
 4:     S1        A4     9
 5:     S2        A1     6
 6:     S2        A2     6
 7:     S2        A3     9
 8:     S2        A4     8
 9:     S3        A1     4
10:     S3        A2     4
11:     S3        A3     8
12:     S3        A4     8
13:     S4        A1     3
14:     S4        A2     2
15:     S4        A3     7
16:     S4        A4     7
17:     S5        A1     5
18:     S5        A2     4
19:     S5        A3     5
20:     S5        A4    12
21:     S6        A1     7
22:     S6        A2     5
23:     S6        A3     6
24:     S6        A4    13
25:     S7        A1     5
26:     S7        A2     3
27:     S7        A3     7
28:     S7        A4    12
29:     S8        A1     2
30:     S8        A2     3
31:     S8        A3     6
32:     S8        A4    11
        ID Condition     Y
    <char>    <char> <num>
bruceR::within.2  # 被试内重复测量(宽数据)
  ID A1B1 A1B2 A1B3 A2B1 A2B2 A2B3
1 S1    3    4    5    4    8   12
2 S2    6    6    7    5    9   13
3 S3    4    4    5    3    8   12
4 S4    3    2    2    3    7   11
d.long.2 = pivot_longer(
  data = within.2,
  cols = A1B1:A2B3,
  names_to = c("Cond.A", "Cond.B"),
  names_pattern = "A(.)B(.)",
  values_to = "Y"
) %>% as.data.table()
d.long.2  # 长数据
        ID Cond.A Cond.B     Y
    <char> <char> <char> <num>
 1:     S1      1      1     3
 2:     S1      1      2     4
 3:     S1      1      3     5
 4:     S1      2      1     4
 5:     S1      2      2     8
 6:     S1      2      3    12
 7:     S2      1      1     6
 8:     S2      1      2     6
 9:     S2      1      3     7
10:     S2      2      1     5
11:     S2      2      2     9
12:     S2      2      3    13
13:     S3      1      1     4
14:     S3      1      2     4
15:     S3      1      3     5
16:     S3      2      1     3
17:     S3      2      2     8
18:     S3      2      3    12
19:     S4      1      1     3
20:     S4      1      2     2
21:     S4      1      3     2
22:     S4      2      1     3
23:     S4      2      2     7
24:     S4      2      3    11
        ID Cond.A Cond.B     Y
    <char> <char> <char> <num>

(本小节进度:1/3)

2. 长变宽
d.long.1  # 长数据(见“宽变长”部分代码)
        ID Condition     Y
    <char>    <char> <num>
 1:     S1        A1     3
 2:     S1        A2     4
 3:     S1        A3     8
 4:     S1        A4     9
 5:     S2        A1     6
 6:     S2        A2     6
 7:     S2        A3     9
 8:     S2        A4     8
 9:     S3        A1     4
10:     S3        A2     4
11:     S3        A3     8
12:     S3        A4     8
13:     S4        A1     3
14:     S4        A2     2
15:     S4        A3     7
16:     S4        A4     7
17:     S5        A1     5
18:     S5        A2     4
19:     S5        A3     5
20:     S5        A4    12
21:     S6        A1     7
22:     S6        A2     5
23:     S6        A3     6
24:     S6        A4    13
25:     S7        A1     5
26:     S7        A2     3
27:     S7        A3     7
28:     S7        A4    12
29:     S8        A1     2
30:     S8        A2     3
31:     S8        A3     6
32:     S8        A4    11
        ID Condition     Y
    <char>    <char> <num>
d.wide.1 = pivot_wider(
  data = d.long.1,
  id_cols = ID,
  names_from = "Condition",
  values_from = "Y"
) %>% as.data.table()
d.wide.1  # 宽数据
       ID    A1    A2    A3    A4
   <char> <num> <num> <num> <num>
1:     S1     3     4     8     9
2:     S2     6     6     9     8
3:     S3     4     4     8     8
4:     S4     3     2     7     7
5:     S5     5     4     5    12
6:     S6     7     5     6    13
7:     S7     5     3     7    12
8:     S8     2     3     6    11
d.long.2  # 长数据(见“宽变长”部分代码)
        ID Cond.A Cond.B     Y
    <char> <char> <char> <num>
 1:     S1      1      1     3
 2:     S1      1      2     4
 3:     S1      1      3     5
 4:     S1      2      1     4
 5:     S1      2      2     8
 6:     S1      2      3    12
 7:     S2      1      1     6
 8:     S2      1      2     6
 9:     S2      1      3     7
10:     S2      2      1     5
11:     S2      2      2     9
12:     S2      2      3    13
13:     S3      1      1     4
14:     S3      1      2     4
15:     S3      1      3     5
16:     S3      2      1     3
17:     S3      2      2     8
18:     S3      2      3    12
19:     S4      1      1     3
20:     S4      1      2     2
21:     S4      1      3     2
22:     S4      2      1     3
23:     S4      2      2     7
24:     S4      2      3    11
        ID Cond.A Cond.B     Y
    <char> <char> <char> <num>
d.wide.2 = pivot_wider(
  data = d.long.2,
  id_cols = ID,
  names_from = c("Cond.A", "Cond.B"),
  names_prefix = "A",
  names_sep = "_B",
  values_from = "Y"
) %>% as.data.table()
d.wide.2  # 宽数据
       ID A1_B1 A1_B2 A1_B3 A2_B1 A2_B2 A2_B3
   <char> <num> <num> <num> <num> <num> <num>
1:     S1     3     4     5     4     8    12
2:     S2     6     6     7     5     9    13
3:     S3     4     4     5     3     8    12
4:     S4     3     2     2     3     7    11

(本小节进度:2/3)

3. 更复杂情况
d.wide.2  # 宽数据(见“长变宽”部分代码)
       ID A1_B1 A1_B2 A1_B3 A2_B1 A2_B2 A2_B3
   <char> <num> <num> <num> <num> <num> <num>
1:     S1     3     4     5     4     8    12
2:     S2     6     6     7     5     9    13
3:     S3     4     4     5     3     8    12
4:     S4     3     2     2     3     7    11
d.long.3 = pivot_longer(
  data = d.wide.2,
  cols = starts_with("A"),
  names_to = c("VariableA", ".value"),
  names_pattern = "A(.)_(.+)"
) %>% as.data.table()
d.long.3  # A变长,B保持宽
       ID VariableA    B1    B2    B3
   <char>    <char> <num> <num> <num>
1:     S1         1     3     4     5
2:     S1         2     4     8    12
3:     S2         1     6     6     7
4:     S2         2     5     9    13
5:     S3         1     4     4     5
6:     S3         2     3     8    12
7:     S4         1     3     2     2
8:     S4         2     3     7    11
d.wide.3 = pivot_wider(
  data = d.long.3,
  names_from = "VariableA",
  names_glue = "A{VariableA}{.value}",
  values_from = c("B1", "B2", "B3")
) %>% as.data.table()
d.wide.3
       ID  A1B1  A2B1  A1B2  A2B2  A1B3  A2B3
   <char> <num> <num> <num> <num> <num> <num>
1:     S1     3     4     4     8     5    12
2:     S2     6     5     6     9     7    13
3:     S3     4     3     4     8     5    12
4:     S4     3     3     2     7     2    11

(本小节进度:3/3)

【阶段作业①】数据处理综合

作业要求:

  • 基于【作业4】【作业6】的期末自选数据和代码积累,综合运用本章所学的各种数据操作方法和代码,对数据进行增删查改、行列筛选、排序去重、分组汇总、匹配拼接、长宽转换等操作,体现对目前所学全部内容的掌握和迁移应用
  • 使用R Markdown完成,对关键代码及结果要有注释说明

平台提交:

  • 运行得到的HTML网页
    • 提交文件命名格式:学号-姓名-R阶段作业1.html
LS0tDQp0aXRsZTogIuOAilLor63oqIDjgIvnrKw256ug77ya5pWw5o2u5pON5L2cIg0Kc3VidGl0bGU6IDxhIGhyZWY9Imh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS8iPui/lOWbnuivvueoi+S4u+mhtTwvYT4NCmF1dGhvcjogIuaOiOivvuaVmeW4iO+8muWMheWvkuWQtOmcnCINCiMgZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGFuY2hvcl9zZWN0aW9uczogdHJ1ZQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICBjc3M6IFJtZENTUy5jc3MNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8cCBzdHlsZT0iZm9udC1zaXplOiAxMnB4Ij7niYjmnYPlo7DmmI7vvJrmnKzlpZfor77nqIvmnZDmlpnlvIDmupDvvIzkvb/nlKjlkozliIbkuqvlv4XpobvpgbXlrojjgIzliJvkvZzlhbHnlKjorrjlj6/ljY/orq4gQ0MgQlktTkMtU0HjgI3vvIjmnaXmupDlvJXnlKgt6Z2e5ZWG5Lia55So6YCU5L2/55SoLeS7peebuOWQjOaWueW8j+WFseS6q++8ieOAgjxpbWcgc3JjPSJpbWcvQ0MtQlktTkMtU0EuanBnIiB3aWR0aD0iMTIwcHgiIGhlaWdodD0iNDJweCIgc3R5bGU9ImZsb2F0OiByaWdodCIgLz48L3A+DQpgYGANCg0KYGBge3IgQ29uZmlnLCBpbmNsdWRlPUZBTFNFfQ0Kb3B0aW9ucygNCiAga25pdHIua2FibGUuTkEgPSAiIiwNCiAgZGlnaXRzID0gNA0KKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiIsDQogIGZpZy53aWR0aCA9IDYsDQogIGZpZy5oZWlnaHQgPSA0LA0KICBkcGkgPSAzMDANCikNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBDaGFwMDbvvJrmlbDmja7mk43kvZwNCg0KIyMjIyDlvoDmnJ/opoHngrnlm57pob4NCg0KLSAgIFtDaGFwMDUgXCMg5Y+Y6YeP6K6h566X55qE5aSa56eN5pa55byPXShodHRwczovL3BzeWNoYnJ1Y2UuZ2l0aHViLmlvL1JDb3Vyc2UvQ2hhcDA1IyVFNSU4RiU5OCVFOSU4NyU4RiVFOCVBRSVBMSVFNyVBRSU5NyVFNyU5QSU4NCVFNiU4MCVCQiVFNCVCRCU5MyVFNCVCQiU4QiVFNyVCQiU4RCl7LnVyaX0NCg0KIyMjIyDmnKznq6DopoHngrnnm67lvZUNCg0KLSAgIFvjgJDnn6Xor4bngrnjgJFkYXRhLnRhYmxl5qC45b+D6KaB57SgXSgj55+l6K+G54K5ZGF0YS50YWJsZeaguOW/g+imgee0oCkNCi0gICBb44CQ5o6i57Si5Y+R546w44CRZGF0YS50YWJsZSB2cy4gZHBseXIgKHRpZHl2ZXJzZSkg5pWw5o2u5pON5L2c5Luj56CB6aOO5qC85q+U6L6DXSgj5o6i57Si5Y+R546wZGF0YS50YWJsZS12cy4tZHBseXItdGlkeXZlcnNlLeaVsOaNruaTjeS9nOS7o+eggemjjuagvOavlOi+gykNCi0gICBb44CQ5o6i57Si5Y+R546w44CR5oCn6IO95aSnUEvvvJpkYXRhLnRhYmxlIChSKSB2cy4gZHBseXIgKFIpIHZzLiBwYW5kYXMgKFB5dGhvbildKCPmjqLntKLlj5HnjrDmgKfog73lpKdwa2RhdGEudGFibGUtci12cy4tZHBseXItci12cy4tcGFuZGFzLXB5dGhvbikNCi0gICBb44CQ5a6e6Le1MeOAkeWinuWIoOafpeaUuV0oI+Wunui3tTHlop7liKDmn6XmlLkp77yI6YeN54K577yJDQotICAgW+OAkOWunui3tTLjgJHooYzliJfnrZvpgIldKCPlrp7ot7Uy6KGM5YiX562b6YCJKe+8iOmHjeeCue+8iQ0KLSAgIFvjgJDlrp7ot7Uz44CR5o6S5bqP5Y676YeNXSgj5a6e6Le1M+aOkuW6j+WOu+mHjSkNCi0gICBb44CQ6Ieq55Sx57uD5Lmg44CR5pWw5o2u5Z+65pys5pON5L2cXSgj6Ieq55Sx57uD5Lmg5pWw5o2u5Z+65pys5pON5L2cKQ0KLSAgIFvjgJDlrp7ot7U044CR5YiG57uE5rGH5oC7XSgj5a6e6Le1NOWIhue7hOaxh+aAuynvvIjph43ngrnvvIkNCi0gICBb44CQ55+l6K+G54K544CRZGF0YS50YWJsZeaguOW/g+efpeivhueCueaAu+e7k10oI+efpeivhueCuWRhdGEudGFibGXmoLjlv4Pnn6Xor4bngrnmgLvnu5MpDQotICAgW+OAkOefpeivhueCueOAkWRwbHly5YyF77yaam9pbuezu+WIl+WHveaVsF0oI+efpeivhueCuWRwbHly5YyFam9pbuezu+WIl+WHveaVsCkNCi0gICBb44CQ5a6e6Le1NeOAkeWMuemFjeaLvOaOpV0oI+Wunui3tTXljLnphY3mi7zmjqUp77yI6YeN54K577yJDQotICAgW+OAkOefpeivhueCueOAkeWuveaVsOaNriB2cy4g6ZW/5pWw5o2uXSgj55+l6K+G54K55a695pWw5o2uLXZzLi3plb/mlbDmja4pDQotICAgW+OAkOefpeivhueCueOAkXRpZHly5YyF77yacGl2b3Tns7vliJflh73mlbBdKCPnn6Xor4bngrl0aWR5cuWMhXBpdm9057O75YiX5Ye95pWwKQ0KLSAgIFvjgJDlrp7ot7U244CR6ZW/5a696L2s5o2iXSgj5a6e6Le1NumVv+Wuvei9rOaNoikNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyDmnKznq6DmiYDpnIBS5YyFDQpsaWJyYXJ5KGJydWNlUikNCiMgbGlicmFyeShkcGx5cikgICAgICAgIyDliqDovb1icnVjZVLml7blt7Lpu5jorqTliqDovb1kcGx5cg0KIyBsaWJyYXJ5KHRpZHlyKSAgICAgICAjIOWKoOi9vWJydWNlUuaXtuW3sum7mOiupOWKoOi9vXRpZHlyDQojIGxpYnJhcnkoZGF0YS50YWJsZSkgICMg5Yqg6L29YnJ1Y2VS5pe25bey6buY6K6k5Yqg6L29ZGF0YS50YWJsZQ0KYGBgDQoNCiMg5pWw5o2u5pON5L2c57G7UuWMheamgui/sOS4juavlOi+gw0KDQojIyMjIOOAkOefpeivhueCueOAkWRhdGEudGFibGXmoLjlv4PopoHntKAgeyPnn6Xor4bngrlkYXRhLnRhYmxl5qC45b+D6KaB57SgfQ0KDQotICAgW+S4gOWbvuWtpuS8mmRhdGEudGFibGXljIXvvIjlrpjmlrnpgJ/mn6XooajvvIldKGh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS9jaGVhdHNoZWV0L2RhdGEudGFibGUucGRmKQ0KLSAgIOaegeeugOS7o+eggemjjuagvO+8mmBkYXRhW2ksIGosIGJ5XWAg4oCU4oCUIOWPqumcgOimgeS4gOWvueS4reaLrOWPt++8jOWwseiDveWujOaIkOaJgOacieaTjeS9nO+8gQ0KICAgIC0gICBgaWDvvJrooYzmk43kvZwNCiAgICAtICAgYGpg77ya5YiX5pON5L2cDQogICAgLSAgIGBieWDvvJrliIbnu4Tlj5jph48NCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtODA5MjczMjQ4LnBuZykNCg0KIyMjIyDjgJDmjqLntKLlj5HnjrDjgJFkYXRhLnRhYmxlIHZzLiBkcGx5ciAodGlkeXZlcnNlKSDmlbDmja7mk43kvZzku6PnoIHpo47moLzmr5TovoMgeyPmjqLntKLlj5HnjrBkYXRhLnRhYmxlLXZzLi1kcGx5ci10aWR5dmVyc2Ut5pWw5o2u5pON5L2c5Luj56CB6aOO5qC85q+U6L6DfQ0KDQotICAgW0EgZGF0YS50YWJsZSBhbmQgZHBseXIgdG91ciAoQXRyZWJhcywgMjAxOSldKGh0dHBzOi8vYXRyZWJhcy5naXRodWIuaW8vcG9zdC8yMDE5LTAzLTAzLWRhdGF0YWJsZS1kcGx5ci8pey51cml9DQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTI1ODUwODA4MTMucG5nKQ0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0zMTc2OTAzMzE5LnBuZykNCg0KIyMjIyDjgJDmjqLntKLlj5HnjrDjgJHmgKfog73lpKdQS++8mmRhdGEudGFibGUgKFIpIHZzLiBkcGx5ciAoUikgdnMuIHBhbmRhcyAoUHl0aG9uKSB7I+aOoue0ouWPkeeOsOaAp+iDveWkp3BrZGF0YS50YWJsZS1yLXZzLi1kcGx5ci1yLXZzLi1wYW5kYXMtcHl0aG9uIC50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJsZS1waWxsfQ0KDQotICAgPGh0dHBzOi8vaDJvYWkuZ2l0aHViLmlvL2RiLWJlbmNobWFyay8+DQoNCiMjIyMjICoq5YiG57uE5rGH5oC76YCf5bqmICgwLjUgR0IpKioNCg0K77yI5pWw5o2u6KeE5qih77yaMTAwMOS4h+ihjCDDlyA55Liq5Y+Y6YeP77yJDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTI1MDAzODk0MzQucG5nKQ0KDQojIyMjIyAqKuWIhue7hOaxh+aAu+mAn+W6piAoNSBHQikqKg0KDQrvvIjmlbDmja7op4TmqKHvvJox5Lq/6KGMIMOXIDnkuKrlj5jph4/vvIkNCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMzc2MTQ4NTYxMy5wbmcpDQoNCiMjIyMjICoq5YiG57uE5rGH5oC76YCf5bqmICg1MCBHQikqKg0KDQrvvIjmlbDmja7op4TmqKHvvJoxMOS6v+ihjCDDlyA55Liq5Y+Y6YeP77yJDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTM3NzMxMDc2MTcucG5nKQ0KDQojIOWinuWIoOafpeaUue+8iGRhdGEudGFibGXvvIkNCg0KIyMjIyDjgJDlrp7ot7Ux44CR5aKe5Yig5p+l5pS5IHsj5a6e6Le1MeWinuWIoOafpeaUuSAudGFic2V0IC50YWJzZXQtZmFkZSAudGFibGUtcGlsbH0NCg0KYGBge3J9DQojIyDmlbDmja7lh4blpIfvvJrlpKfkupTkurrmoLzpl67ljbdCRknvvIjpg6jliIbmlbDmja7vvIkNCmRhdGEgPSBhcy5kYXRhLnRhYmxlKHBzeWNoOjpiZmkpDQpkID0gZGF0YVszMTo1MCwgYygiZ2VuZGVyIiwgImVkdWNhdGlvbiIsICJhZ2UiKV0NCmQNCnN0cihkKQ0KYGBgDQoNCiMjIyMjICoqMS4g5aKe5YqgKioNCg0KYGBge3J9DQojIyDmlrnlvI8gMTog5Y2V5Y+Y6YePICQg5pON5L2c56ymDQpkJEdlbmRlciA9IGZhY3RvcihkJGdlbmRlciwgbGV2ZWxzPTE6MiwgbGFiZWxzPWMoIk1hbGUiLCAiRmVtYWxlIikpDQpkDQoNCiMjIOaWueW8jyAyOiDljZXlj5jph48gOj0g6L+Q566X56ymICjljp/lnLDmm7TmlrApDQpkWywgR2VuZGVyIDo9IGZhY3RvcihnZW5kZXIsIGxldmVscz0xOjIsIGxhYmVscz1jKCJNYWxlIiwgIkZlbWFsZSIpKV0NCmQNCg0KIyMg5pa55byPIDM6IOWkmuWPmOmHjyBsZXQoKSDlh73mlbAgKOWOn+WcsOabtOaWsCkNCmRbLCBsZXQoDQogIEdlbmRlciA9IGZhY3RvcihnZW5kZXIsIGxldmVscz0xOjIsIGxhYmVscz1jKCJNYWxlIiwgIkZlbWFsZSIpKSwNCiAgQWdlID0gYXMubnVtZXJpYyhhZ2UpLA0KICBFZHUgPSBhcy5mYWN0b3IoZWR1Y2F0aW9uKQ0KKV0NCmQNCnN0cihkKQ0KYGBgDQoNCu+8iOacrOWwj+iKgui/m+W6pu+8mjEvNO+8iQ0KDQojIyMjIyAqKjIuIOWIoOmZpCoqDQoNCmBgYHtyfQ0KIyMg5Y2V5Y+Y6YePDQpkJEFnZSA9IGQkRWR1ID0gTlVMTA0KZA0KDQojIyDlpJrlj5jph48NCmRbLCBsZXQoDQogIGdlbmRlciA9IE5VTEwsDQogIGVkdWNhdGlvbiA9IE5VTEwsDQogIGFnZSA9IE5VTEwNCildDQpkDQpgYGANCg0K77yI5pys5bCP6IqC6L+b5bqm77yaMi8077yJDQoNCiMjIyMjICoqMy4g5p+l5om+KioNCg0KYGBge3J9DQpkID0gZGF0YVszMTo1MCwgYygiZ2VuZGVyIiwgImVkdWNhdGlvbiIsICJhZ2UiLCBwYXN0ZTAoIkEiLCAxOjUpKV0NCmQNCnN0cihkKQ0KDQpkWzE6NSwgImdlbmRlciJdICAjIERUW2ksIGpdDQpkWzE6NSwgZ2VuZGVyXSAgIyBEVFtpLCBqXQ0KZFsxOjUsIGMoImdlbmRlciIsICJhZ2UiKV0gICMgRFRbaSwgal0NCmRbMTo1LCAuKGdlbmRlciwgYWdlKV0gICMgRFRbaSwgal0NCg0KZFsxOjNdICAjIERUW2ldDQpkWzE6MywgXSAgIyBEVFtpLCBdDQpkWywgMjozXSAgIyBEVFtpLCBdDQpkWywgYWdlOkEzXSAgIyBEVFssIGpd77yI5Y+Y6YeP5ZCN6IyD5Zu077yM5LiN5Lya5pWw5pWw5a2X77yJDQpgYGANCg0K77yI5pys5bCP6IqC6L+b5bqm77yaMy8077yJDQoNCiMjIyMjICoqNC4g5L+u5pS5KioNCg0KYGBge3J9DQpkID0gZGF0YVsyNTM2OjI1NDAsIGMoImdlbmRlciIsICJlZHVjYXRpb24iLCAiYWdlIildDQpkDQoNCmRbMiwgImFnZSJdID0gTkEgICMg5peg5pWI5bm06b6E77yIM+Wyge+8ie+8jOabv+aNouS4uk5B57y65aSx5YC8DQpkDQpgYGANCg0KLSAgIFHvvJrlpoLkvZXoh6rliqjnrZvpgInjgIHmm7/mjaLml6DmlYjlubTpvoTvvJ8NCiAgICAtICAgQe+8muivt+eci+S4i+S4gOmDqOWIhg0KDQrvvIjmnKzlsI/oioLov5vluqbvvJo0LzTvvIkNCg0KIyDooYzliJfnrZvpgInvvIhkYXRhLnRhYmxl77yJDQoNCiMjIyMg44CQ5a6e6Le1MuOAkeihjOWIl+etm+mAiSB7I+Wunui3tTLooYzliJfnrZvpgIkgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYmxlLXBpbGx9DQoNCmBgYHtyfQ0KIyMg5pWw5o2u5YeG5aSH77ya5aSn5LqU5Lq65qC86Zeu5Y23QkZJ77yI6YOo5YiG5pWw5o2u77yJDQpkYXRhID0gYXMuZGF0YS50YWJsZShwc3ljaDo6YmZpKQ0KZGF0YVssIGxldCgNCiAgR2VuZGVyID0gZmFjdG9yKGdlbmRlciwgbGV2ZWxzPTE6MiwgbGFiZWxzPWMoIk1hbGUiLCAiRmVtYWxlIikpLA0KICBBZ2UgPSBhcy5udW1lcmljKGFnZSksDQogIEVkdSA9IGFzLmZhY3RvcihlZHVjYXRpb24pDQopXQ0KZCA9IGRhdGFbMjUzNToyNTQ2LCBjKCJHZW5kZXIiLCAiQWdlIiwgIkVkdSIsIHBhc3RlMCgiQSIsIDE6NSkpXQ0KZA0Kc3RyKGQpDQpgYGANCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMjI3MzU5MjQ1OC5wbmcpDQoNCiMjIyMjICoqMS4g6KGM562b6YCJKioNCg0KYGBge3J9DQpkW0dlbmRlciA9PSAiRmVtYWxlIl0NCg0KZFtHZW5kZXIgPT0gIk1hbGUiXQ0KDQpkW0dlbmRlciA9PSAiTWFsZSIgJiBBZ2UgPj0gMTZdDQoNCmRbR2VuZGVyID09ICJNYWxlIiAmIEFnZSA+PSAxNiAmICFpcy5uYShFZHUpXQ0KDQpkW0dlbmRlciA9PSAiTWFsZSIgJiBBZ2UgJWluJSAyMDo0NV0NCg0KZFtHZW5kZXIgPT0gIk1hbGUiICYgQWdlICVub3RpbiUgMjA6NDVdDQoNCmRbR2VuZGVyID09ICJNYWxlIiAmIChBZ2UgPCAyMCB8IEFnZSA+IDQ1KV0NCg0KZFtBZ2UgPCAxNV0NCmRbQWdlIDwgMTUsICJBZ2UiXSA9IE5BICAjIOiHquWKqOetm+mAieOAgeabv+aNouaXoOaViOW5tOm+hA0KZA0KYGBgDQoNCu+8iOacrOWwj+iKgui/m+W6pu+8mjEvM++8iQ0KDQojIyMjIyAqKjIuIOWIl+etm+mAiSoqDQoNCmBgYHtyfQ0KZCA9IGRhdGFbMjUzNToyNTQ2LCBjKCJHZW5kZXIiLCAiQWdlIiwgIkVkdSIsIHBhc3RlMCgiQSIsIDE6NSkpXQ0KDQojIyDnm7TmjqXnrZvpgInliJcNCmRbLCBBZ2U6QTNdICAjIERUWywgal3vvIjlj5jph4/lkI3ojIPlm7TvvIzkuI3kvJrmlbDmlbDlrZfvvIkNCmRbLCAuKEExLCBBMiwgQTMsIEVkdSwgQWdlKV0NCg0KIyMg6Ze05o6l562b6YCJ5YiXDQp2YXJzID0gYygiQWdlIiwgIkVkdSIpDQp0cnkoew0KICBkWywgdmFyc10gICMg5oql6ZSZ77yMdmFyc+S4jeaYr2RhdGEudGFibGXlhoXpg6jnjq/looPkuK3nmoTlj5jph4/lkI0NCn0pDQpkWywgLi52YXJzXSAgIyAuLuihqOekuuS7jmRhdGEudGFibGXlhoXpg6jnjq/looPov5Tlm57liLDlhajlsYDnjq/looPvvIzkvb/nlKjlj5jph4/pgInmi6nliJcNCg0KIyMg6L+Y5Y+v5Lul5L2/55SoIGRwbHlyOjpzZWxlY3QoKSDlh73mlbDvvIzmkK3phY0gdGlkeXNlbGVjdCDns7vliJflh73mlbANCnNlbGVjdChkLCBzdGFydHNfd2l0aCgiQSIpKQ0Kc2VsZWN0KGQsIG1hdGNoZXMoIkFcXGQiKSkgICMg5q2j5YiZ6KGo6L6+5byPDQpzZWxlY3QoZCwgbnVtX3JhbmdlKCJBIiwgMTo1KSkgICMg6aKY5bqP5Y+36IyD5Zu0DQpkICU+JSBzZWxlY3QobnVtX3JhbmdlKCJBIiwgMTo1KSkgICMg566h6YGT5pON5L2c56ymDQpgYGANCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMzY0MjQ1NTM3Mi5wbmcpDQoNCuaLk+WxleS6huino++8mlt0aWR5c2VsZWN05Y+Y6YeP6YCJ5oup6K+t5rOVXShodHRwczovL3RpZHlzZWxlY3Quci1saWIub3JnL3JlZmVyZW5jZS9sYW5ndWFnZS5odG1sKXsudXJpfQ0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0yNDM1NjQ0MDc1LnBuZykNCg0K77yI5pys5bCP6IqC6L+b5bqm77yaMi8z77yJDQoNCiMjIyMjICoqMy4g57u85ZCI57uD5LmgKioNCg0KYGBge3J9DQpkYXRhW0FnZSA+PSAxOCAmIEVkdSA9PSA1XQ0KZGF0YVssIEExOkM1XQ0KZGF0YVssIEdlbmRlcjpFZHVdDQpkYXRhWywgLihHZW5kZXIsIEVkdSldDQpkYXRhW0FnZSA+PSAxOCAmIEVkdSA9PSA1LCAuKEdlbmRlciwgQWdlLCBFZHUpXQ0KDQpkYXRhICU+JSBzZWxlY3QoQTE6QzUpDQpkYXRhICU+JSBzZWxlY3QobWF0Y2hlcygiXkUiKSkNCmRhdGEgJT4lIHNlbGVjdChtYXRjaGVzKCJFXFxkIikpDQpkYXRhICU+JSBzZWxlY3QobnVtX3JhbmdlKCJBIiwgMTo1KSkNCmBgYA0KDQrvvIjmnKzlsI/oioLov5vluqbvvJozLzPvvIkNCg0KIyDmjpLluo/ljrvph43vvIhkYXRhLnRhYmxl77yJDQoNCiMjIyMg44CQ5a6e6Le1M+OAkeaOkuW6j+WOu+mHjSB7I+Wunui3tTPmjpLluo/ljrvph40gLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYmxlLXBpbGx9DQoNCmBgYHtyfQ0KIyMg5pWw5o2u5YeG5aSH77ya5aSn5LqU5Lq65qC86Zeu5Y23QkZJ77yI6YOo5YiG5pWw5o2u77yJDQpkYXRhID0gYXMuZGF0YS50YWJsZShwc3ljaDo6YmZpKQ0KZGF0YVssIGxldCgNCiAgR2VuZGVyID0gZmFjdG9yKGdlbmRlciwgbGV2ZWxzPTE6MiwgbGFiZWxzPWMoIk1hbGUiLCAiRmVtYWxlIikpLA0KICBBZ2UgPSBhcy5udW1lcmljKGFnZSksDQogIEVkdSA9IGFzLmZhY3RvcihlZHVjYXRpb24pDQopXQ0KZCA9IGRhdGFbMjUzNToyNTQ2LCBjKCJHZW5kZXIiLCAiQWdlIiwgIkVkdSIsIHBhc3RlMCgiQSIsIDE6NSkpXQ0KZA0Kc3RyKGQpDQpgYGANCg0KIyMjIyMgKioxLiDmjpLluo8qKg0KDQpgYGB7cn0NCmRbb3JkZXIoR2VuZGVyLCBBZ2UsIEVkdSldICAjIOato+W6jw0KDQpkW29yZGVyKC1HZW5kZXIsIC1BZ2UsIC1FZHUpXSAgIyDlgJLluo8NCg0KZFtvcmRlcigtR2VuZGVyLCAtQWdlLCAtRWR1KV1bQWdlIDw9IDIwXSAgIyBbIF1bIF1bIF0g5L6d5qyh5omn6KGM77yM5peg6ZmQ5Y+g5YqgDQpgYGANCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtOTU1MDQyNjc2LnBuZykNCg0K77yI5pys5bCP6IqC6L+b5bqm77yaMS8y77yJDQoNCiMjIyMjICoqMi4g5Y676YeNKioNCg0KYGBge3J9DQp1bmlxdWUoZCwgYnk9IkdlbmRlciIpICAjIOagueaNruafkOS4quWPmOmHj+WOu+mHje+8jOmHjeWkjeaVsOaNruWPluesrOS4gOS4qg0KDQp1bmlxdWUoZCwgYnk9YygiR2VuZGVyIiwgIkVkdSIpKSAgIyDmoLnmja7lpJrkuKrlj5jph4/ljrvph43vvIzph43lpI3mlbDmja7lj5bnrKzkuIDkuKoNCg0KdW5pcXVlKGRbb3JkZXIoLUdlbmRlciwgLUFnZSwgLUVkdSldLCBieT1jKCJHZW5kZXIiLCAiRWR1IikpDQpgYGANCg0K77yI5pys5bCP6IqC6L+b5bqm77yaMi8y77yJDQoNCiMg44CQ6Ieq55Sx57uD5Lmg44CR5pWw5o2u5Z+65pys5pON5L2cIHsj6Ieq55Sx57uD5Lmg5pWw5o2u5Z+65pys5pON5L2cfQ0KDQrlj4LogIPliY3kuInlsI/oioLku6PnoIHvvIjlop7liKDmn6XmlLnjgIHooYzliJfnrZvpgInjgIHmjpLluo/ljrvph43vvInvvIzln7rkuo5gcHN5Y2g6OmJmaWDmiJbmnJ/mnKvoh6rpgInmlbDmja7vvIzlnKjoh6rlt7HnlLXohJHkuIroh6rnlLHnu4PkuaDmlbDmja7ln7rmnKzmk43kvZzvvIzkuLrjgJDpmLbmrrXkvZzkuJrikaDjgJHlgZrlh4blpIfjgIINCg0KLSAgIOWPr+S7peWwneivleaUueWPmOS4iui/sOekuuS+i+S7o+eggeS4reeahOaVsOWAvOiMg+WbtOOAgeWPmOmHj+iMg+WbtOOAgeetm+mAieadoeS7tuOAgeaOkuW6j+aWueW8j+etiQ0KLSAgICoq6Ieq5bex5pWy5Luj56CB77yM5o6M5o+h5pu05omO5a6e77yB77yIQUnmm7/ku6PkuI3kuobkvaDnmoTogozogonorrDlv4bvvIHvvIkqKg0KDQojIOWIhue7hOaxh+aAu++8iGRhdGEudGFibGXvvIkNCg0KIyMjIyDjgJDlrp7ot7U044CR5YiG57uE5rGH5oC7IHsj5a6e6Le1NOWIhue7hOaxh+aAuyAudGFic2V0IC50YWJzZXQtZmFkZSAudGFibGUtcGlsbH0NCg0KYGBge3J9DQojIyDmlbDmja7lh4blpIfvvJrlpKfkupTkurrmoLzpl67ljbdCRknvvIjpg6jliIbmlbDmja7vvIkNCmRhdGEgPSBhcy5kYXRhLnRhYmxlKHBzeWNoOjpiZmkpDQpkYXRhWywgbGV0KA0KICBHZW5kZXIgPSBmYWN0b3IoZ2VuZGVyLCBsZXZlbHM9MToyLCBsYWJlbHM9YygiTWFsZSIsICJGZW1hbGUiKSksDQogIEFnZSA9IGFzLm51bWVyaWMoYWdlKSwNCiAgRWR1ID0gYXMuZmFjdG9yKGVkdWNhdGlvbikNCildDQpkID0gZGF0YVsyNTM1OjI1NDYsIGMoIkdlbmRlciIsICJBZ2UiLCAiRWR1IiwgcGFzdGUwKCJBIiwgMTo1KSldDQpkDQpzdHIoZCkNCmBgYA0KDQojIyMjIyAqKjEuIOWIhue7hOiBmuWQiCoqDQoNCmBEVFtpLCBqLCBieV1gDQoNCi0gICBgYnlg77ya5a6a5LmJ5YiG57uE5Y+Y6YeP77yI5Y6f5aeL6aG65bqP77yJDQotICAgYGtleWJ5YO+8muWumuS5ieWIhue7hOWPmOmHj++8iOmHjeaWsOaOkuW6j++8iQ0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC00MzEyNjQ0ODQucG5nKQ0KDQpgYGB7cn0NCiMjIGJ55YiG57uE77yM5Y6f5aeL6aG65bqPDQpkWywgLiguTiksIGJ5PUdlbmRlcl0gICMgLk4g5pivZGF0YS50YWJsZeS/neeVmeWFs+mUruWtl++8jOeUqOS6jue7n+iuoeagt+acrOmHjw0KDQojIyBrZXlieeWIhue7hO+8jOmHjeaWsOaOkuW6jw0KZFssIC4oLk4pLCBrZXlieT1HZW5kZXJdICAjIC5OIOaYr2RhdGEudGFibGXkv53nlZnlhbPplK7lrZfvvIznlKjkuo7nu5/orqHmoLfmnKzph48NCg0KZFssIC4oLk4sIE1lYW4uQWdlID0gbWVhbihBZ2UpKSwga2V5Ynk9R2VuZGVyXQ0KDQpkWywgLigNCiAgLk4sDQogIE1lYW4uQWdlID0gbWVhbihBZ2UpLA0KICBTRC5BZ2UgPSBzZChBZ2UpDQopLCBrZXlieT1HZW5kZXJdDQoNCmRbQWdlID49IDE1LCAuKA0KICAuTiwNCiAgTWVhbi5BZ2UgPSBtZWFuKEFnZSksDQogIFNELkFnZSA9IHNkKEFnZSkNCiksIGtleWJ5PUdlbmRlcl0NCg0KIyMg5YWo6YOo5pWw5o2u55qE5YiG57uE57uf6K6hDQojIEVkdWNhdGlvbjoNCiMgMSA9IGhpZ2ggc2Nob29sDQojIDIgPSBmaW5pc2hlZCBoaWdoIHNjaG9vbA0KIyAzID0gc29tZSBjb2xsZWdlDQojIDQgPSBjb2xsZWdlIGdyYWR1YXRlDQojIDUgPSBncmFkdWF0ZSBkZWdyZWUNCmRhdGFbLCAuKA0KICAuTiwNCiAgTWVhbi5BZ2UgPSBtZWFuKEFnZSkNCiksIGtleWJ5PS4oR2VuZGVyLCBFZHUpXQ0KYGBgDQoNCu+8iOacrOWwj+iKgui/m+W6pu+8mjEvMu+8iQ0KDQojIyMjIyAqKjIuIOWIhue7hOiuoeeulyoqDQoNCmBgYHtyfQ0KZFssIE1lYW4uQWdlIDo9IG1lYW4oQWdlKV0gICMg5oC75Z2H5YC8DQpkDQoNCmRbLCBNZWFuLkFnZS5HIDo9IG1lYW4oQWdlKSwga2V5Ynk9R2VuZGVyXSAgIyDnu4TlnYflgLwNCmQNCg0KZFtHZW5kZXI9PSJNYWxlIiwgQWdlR3JvdXAgOj0gaWZlbHNlKEFnZTw0MCwgIllvdW5nIiwgIk1pZGRsZSIpXQ0KZA0KDQojIyDmgLvlnYflgLzkuK3lv4PljJYNCmRbLCBBZ2UuR3JhbmQuQyA6PSBBZ2UgLSBtZWFuKEFnZSldDQpkWywgLihHZW5kZXIsIEFnZSwgTWVhbi5BZ2UsIEFnZS5HcmFuZC5DKV0NCg0KIyMg57uE5Z2H5YC85Lit5b+D5YyWDQpkWywgQWdlLkdyb3VwLkMgOj0gQWdlIC0gbWVhbihBZ2UpLCBrZXlieT1HZW5kZXJdDQpkWywgLihHZW5kZXIsIEFnZSwgTWVhbi5BZ2UsIE1lYW4uQWdlLkcsIEFnZS5Hcm91cC5DKV0NCmBgYA0KDQojIyMjIOOAkOefpeivhueCueOAkWRhdGEudGFibGXmoLjlv4Pnn6Xor4bngrnmgLvnu5MgeyPnn6Xor4bngrlkYXRhLnRhYmxl5qC45b+D55+l6K+G54K55oC757uTfQ0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0yMDA2MjQ4MDU2LnBuZykNCg0K77yI5pys5bCP6IqC6L+b5bqm77yaMi8y77yJDQoNCiMg5Yy56YWN5ou85o6l77yIZHBseXLvvIkNCg0KIyMjIyDjgJDnn6Xor4bngrnjgJFkcGx5cuWMhe+8mmpvaW7ns7vliJflh73mlbAgeyPnn6Xor4bngrlkcGx5cuWMhWpvaW7ns7vliJflh73mlbB9DQoNCuS4pOS4quaVsOaNrmBkMWDlkoxgZDJg5YW35pyJ55u45ZCM5Y+Y6YePYCJ2YXIiYO+8mg0KDQotICAgYGxlZnRfam9pbihkMSwgZDIsIGJ5PSJ2YXIiKWDvvJrlkJFgZDFg5ZCI5bm24q2Q77iP77yI5pyA5bi455So77yJDQotICAgYHJpZ2h0X2pvaW4oZDEsIGQyLCBieT0idmFyIilg77ya5ZCRYGQyYOWQiOW5tg0KLSAgIGBpbm5lcl9qb2luKGQxLCBkMiwgYnk9InZhciIpYO+8muWPlmBkMWDlkoxgZDJg5Lqk6ZuG5ZCI5bm2DQotICAgYGZ1bGxfam9pbihkMSwgZDIsIGJ5PSJ2YXIiKWDvvJrlj5ZgZDFg5ZKMYGQyYOW5tumbhuWQiOW5tg0KDQrvvIhkYXRhLnRhYmxl5Lmf6IO95a6M5oiQ5Yy56YWN5ou85o6l5pON5L2c77yM5L2G5q+UZHBseXLpmr7nlKjvvIkNCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMTc0NzMzMTQ0My5wbmcpDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTE1MzE3MzUzMDQucG5nKQ0KDQojIyMjIOOAkOWunui3tTXjgJHljLnphY3mi7zmjqUgeyPlrp7ot7U15Yy56YWN5ou85o6lIC50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJsZS1waWxsfQ0KDQojIyMjIyAqKjEuIOWMuemFjeaLvOaOpS3kvosxKioNCg0KYGBge3J9DQojIyDmlbDmja7lh4blpIfvvJrkuKTkuKrmnaXmupDnmoTmlbDmja7vvIzoh7PlsJHljIXlkKvkuIDkuKrlhbHlkIzlj5jph48NCmQxID0gYXMuZGF0YS50YWJsZShkcGx5cjo6YmFuZF9tZW1iZXJzKQ0KZDENCmQyID0gYXMuZGF0YS50YWJsZShkcGx5cjo6YmFuZF9pbnN0cnVtZW50cykNCmQyDQpkMyA9IGFzLmRhdGEudGFibGUoZHBseXI6OmJhbmRfaW5zdHJ1bWVudHMyKQ0KZDMNCg0KIyMg5Yy56YWN5ou85o6l77ya55u45ZCM5Y+Y6YeP5ZCNDQpkYXRhID0gbGVmdF9qb2luKGQxLCBkMiwgYnk9Im5hbWUiKSAgIyDlkJHlt6bovrnmlbDmja7lkIjlubYNCmRhdGENCg0KcmlnaHRfam9pbihkMSwgZDIsIGJ5PSJuYW1lIikgICMg5ZCR5Y+z6L655pWw5o2u5ZCI5bm2DQppbm5lcl9qb2luKGQxLCBkMiwgYnk9Im5hbWUiKSAgIyDkuKTkuKrmlbDmja7nmoTkuqTpm4YNCmZ1bGxfam9pbihkMSwgZDIsIGJ5PSJuYW1lIikgICMg5Lik5Liq5pWw5o2u55qE5bm26ZuGDQoNCiMjIOWMuemFjeaLvOaOpe+8muS4jeWQjOWPmOmHj+WQjQ0KbmFtZXMoZDEpICAjIOS6uuWQjeWPmOmHj+S4uiJuYW1lIg0KbmFtZXMoZDMpICAjIOS6uuWQjeWPmOmHj+S4uiJhcnRpc3QiDQpkYXRhID0gbGVmdF9qb2luKGQxLCBkMywgYnk9YygibmFtZSI9ImFydGlzdCIpKQ0KZGF0YQ0KYGBgDQoNCu+8iOacrOWwj+iKgui/m+W6pu+8mjEvMu+8iQ0KDQojIyMjIyAqKjIuIOWMuemFjeaLvOaOpS3kvosyKioNCg0KYGBge3J9DQpzZXQuc2VlZCgxKQ0KZCA9IGRhdGEudGFibGUoeD1ybm9ybSg5KSwgY2l0eT1yZXAoMTozLCBlYWNoPTMpKQ0KZA0KDQpkLmdyb3VwID0gZGF0YS50YWJsZSgNCiAgY2l0eSA9IDE6MywNCiAgbGFiZWwgPSBjKCLljJfkuqwiLCAi5LiK5rW3IiwgIuW5v+W3niIpLA0KICBHRFAgPSBjKDUyMSwgNTY3LCAzMTApDQopDQpkLmdyb3VwDQoNCmQubWVyZ2UgPSBsZWZ0X2pvaW4oZCwgZC5ncm91cCwgYnk9ImNpdHkiKQ0KZC5tZXJnZQ0KYGBgDQoNCu+8iOacrOWwj+iKgui/m+W6pu+8mjIvMu+8iQ0KDQojIOmVv+Wuvei9rOaNou+8iHRpZHly77yJDQoNCiMjIyMg44CQ55+l6K+G54K544CR5a695pWw5o2uIHZzLiDplb/mlbDmja4geyPnn6Xor4bngrnlrr3mlbDmja4tdnMuLemVv+aVsOaNrn0NCg0KLSAgICoq5a695pWw5o2u77yId2lkZS1mb3JtYXQgZGF0Ye+8iSoq4oCU4oCUIOKAnOaxh+aAu+ihqOKAneaIluKAnOmAj+inhuihqOKAnQ0KICAgIC0gICDmr4/kuKrooqvop4LmtYvnmoTlr7nosaHlj6rljaDkuIDooYzvvIzogIzor6Xlr7nosaHnmoTlpJrkuKrlsZ7mgKfmiJbpmo/ml7bpl7Tlj5jljJbnmoTop4LmtYvlgLzkvZzkuLrkuI3lkIznmoTliJfmqKrlkJHlsZXlvIANCiAgICAgICAgLSAgIOaguOW/g+eJueW+ge+8muS4gOS4u+S9k+S4gOihjO+8jOWkmuWPmOmHj+WkmuWIlw0KICAgICAgICAtICAg54G15rS75oCn77ya5aKe5Yqg5paw5Y+Y6YeP6ZyA5aKe5Yqg5paw5YiXDQogICAgICAgIC0gICDkvJjngrnvvJrlr7nkurrnsbvpmIXor7vmr5TovoPlj4vlpb3vvIzlvojlg4/miJHku6zluLjop4HnmoTnlLXlrZDooajmoLzmiJbmsYfmgLvmiqXooajvvIzlvojlpJrnu5/orqHmqKHlnovnmoTovpPlhaXkuZ/opoHmsYLmmK/lrr3moLzlvI8NCiAgICAgICAgLSAgIOe8uueCue+8muS4jeWIqeS6jui/m+ihjOafkOS6m+WIhuaekOWSjOWPr+inhuWMlu+8jOWboOS4uuaVsOaNrue7tOW6pu+8iOWPmOmHj++8ieiiq+mUgeWumuWcqOWIl+e7k+aehOS4rQ0KDQohW+KGkSDlrr3mlbDmja7npLrkvotdKGltYWdlcy9jbGlwYm9hcmQtMjM5MDI3ODM1NC5wbmcpDQoNCi0gICAqKumVv+aVsOaNru+8iGxvbmctZm9ybWF0IGRhdGHvvIkqKuKAlOKAlCDigJzmtYHmsLTorrDlvZXigJ3miJbigJzop4TojIPljJbigJ3nmoTmlbDmja7lupPooagNCiAgICAtICAg5q+P5Liq6KKr6KeC5rWL55qE5a+56LGh5Lya5Y2g5o2u5aSa6KGM77yM5q+P5LiA6KGM6YCa5bi45Y+q5YyF5ZCr5LiA5Liq5Y+Y6YeP5Zyo5p+Q5LiA5Liq5pe26Ze054K55oiW5p2h5Lu25LiL55qE6KeC5rWL5YC8DQogICAgICAgIC0gICDmoLjlv4PnibnlvoHvvJrkuIDop4LmtYvkuIDooYzvvIzplK7lgLzlr7nlvaLlvI8NCiAgICAgICAgLSAgIOeBtea0u+aAp++8muWinuWKoOaWsOingua1i+aIluWPmOmHj+WPqumcgOWinuWKoOaWsOihjO+8jOe7k+aehOeos+Wumg0KICAgICAgICAtICAg5LyY54K577ya57uT5p6E6KeE5pW077yM5piv5pW05rSB5pWw5o2u55qE5qCH5YeG5qC85byP77yM54m55Yir6YCC5ZCI55SoYGdncGxvdDJg562J5bel5YW36L+b6KGM5pWw5o2u5Y+v6KeG5YyW77yM5Lmf5L6/5LqO6L+b6KGM5YiG57uE44CB6IGa5ZCI5ZKM5aSN5p2C5Y+Y5o2i77yM5pWw5o2u5bqT5a2Y5YKo5Lmf5bi46YeH55So57G75Ly857uT5p6EDQogICAgICAgIC0gICDnvLrngrnvvJrlr7nkurrnsbvpmIXor7vkuI3lpKrnm7Top4LvvIzmmL7lvpflhpfplb8NCg0KIVvihpEg6ZW/5pWw5o2u56S65L6LXShpbWFnZXMvY2xpcGJvYXJkLTI4NzIwOTMzMTQucG5nKQ0KDQojIyMjIOOAkOefpeivhueCueOAkXRpZHly5YyF77yacGl2b3Tns7vliJflh73mlbAgeyPnn6Xor4bngrl0aWR5cuWMhXBpdm9057O75YiX5Ye95pWwfQ0KDQrvvIhkYXRhLnRhYmxl5Lmf6IO95a6M5oiQ6ZW/5a696L2s5o2i5pON5L2c77yM5L2G5q+UdGlkeXLpmr7nlKjvvIkNCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMzYzMDU5ODkzOS5wbmcpDQoNCiMjIyMg44CQ5a6e6Le1NuOAkemVv+Wuvei9rOaNoiB7I+Wunui3tTbplb/lrr3ovazmjaIgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYmxlLXBpbGx9DQoNCiMjIyMjICoqMS4g5a695Y+Y6ZW/KioNCg0KYGBge3J9DQpicnVjZVI6OndpdGhpbi4xICAjIOiiq+ivleWGhemHjeWkjea1i+mHj++8iOWuveaVsOaNru+8iQ0KDQpkLmxvbmcuMSA9IHBpdm90X2xvbmdlcigNCiAgZGF0YSA9IHdpdGhpbi4xLA0KICBjb2xzID0gQTE6QTQsDQogIG5hbWVzX3RvID0gIkNvbmRpdGlvbiIsDQogIHZhbHVlc190byA9ICJZIg0KKSAlPiUgYXMuZGF0YS50YWJsZSgpDQpkLmxvbmcuMSAgIyDplb/mlbDmja4NCmBgYA0KDQpgYGB7cn0NCmJydWNlUjo6d2l0aGluLjIgICMg6KKr6K+V5YaF6YeN5aSN5rWL6YeP77yI5a695pWw5o2u77yJDQoNCmQubG9uZy4yID0gcGl2b3RfbG9uZ2VyKA0KICBkYXRhID0gd2l0aGluLjIsDQogIGNvbHMgPSBBMUIxOkEyQjMsDQogIG5hbWVzX3RvID0gYygiQ29uZC5BIiwgIkNvbmQuQiIpLA0KICBuYW1lc19wYXR0ZXJuID0gIkEoLilCKC4pIiwNCiAgdmFsdWVzX3RvID0gIlkiDQopICU+JSBhcy5kYXRhLnRhYmxlKCkNCmQubG9uZy4yICAjIOmVv+aVsOaNrg0KYGBgDQoNCu+8iOacrOWwj+iKgui/m+W6pu+8mjEvM++8iQ0KDQojIyMjIyAqKjIuIOmVv+WPmOWuvSoqDQoNCmBgYHtyfQ0KZC5sb25nLjEgICMg6ZW/5pWw5o2u77yI6KeB4oCc5a695Y+Y6ZW/4oCd6YOo5YiG5Luj56CB77yJDQoNCmQud2lkZS4xID0gcGl2b3Rfd2lkZXIoDQogIGRhdGEgPSBkLmxvbmcuMSwNCiAgaWRfY29scyA9IElELA0KICBuYW1lc19mcm9tID0gIkNvbmRpdGlvbiIsDQogIHZhbHVlc19mcm9tID0gIlkiDQopICU+JSBhcy5kYXRhLnRhYmxlKCkNCmQud2lkZS4xICAjIOWuveaVsOaNrg0KYGBgDQoNCmBgYHtyfQ0KZC5sb25nLjIgICMg6ZW/5pWw5o2u77yI6KeB4oCc5a695Y+Y6ZW/4oCd6YOo5YiG5Luj56CB77yJDQoNCmQud2lkZS4yID0gcGl2b3Rfd2lkZXIoDQogIGRhdGEgPSBkLmxvbmcuMiwNCiAgaWRfY29scyA9IElELA0KICBuYW1lc19mcm9tID0gYygiQ29uZC5BIiwgIkNvbmQuQiIpLA0KICBuYW1lc19wcmVmaXggPSAiQSIsDQogIG5hbWVzX3NlcCA9ICJfQiIsDQogIHZhbHVlc19mcm9tID0gIlkiDQopICU+JSBhcy5kYXRhLnRhYmxlKCkNCmQud2lkZS4yICAjIOWuveaVsOaNrg0KYGBgDQoNCu+8iOacrOWwj+iKgui/m+W6pu+8mjIvM++8iQ0KDQojIyMjIyAqKjMuIOabtOWkjeadguaDheWGtSoqDQoNCmBgYHtyfQ0KZC53aWRlLjIgICMg5a695pWw5o2u77yI6KeB4oCc6ZW/5Y+Y5a694oCd6YOo5YiG5Luj56CB77yJDQoNCmQubG9uZy4zID0gcGl2b3RfbG9uZ2VyKA0KICBkYXRhID0gZC53aWRlLjIsDQogIGNvbHMgPSBzdGFydHNfd2l0aCgiQSIpLA0KICBuYW1lc190byA9IGMoIlZhcmlhYmxlQSIsICIudmFsdWUiKSwNCiAgbmFtZXNfcGF0dGVybiA9ICJBKC4pXyguKykiDQopICU+JSBhcy5kYXRhLnRhYmxlKCkNCmQubG9uZy4zICAjIEHlj5jplb/vvIxC5L+d5oyB5a69DQpgYGANCg0KYGBge3J9DQpkLndpZGUuMyA9IHBpdm90X3dpZGVyKA0KICBkYXRhID0gZC5sb25nLjMsDQogIG5hbWVzX2Zyb20gPSAiVmFyaWFibGVBIiwNCiAgbmFtZXNfZ2x1ZSA9ICJBe1ZhcmlhYmxlQX17LnZhbHVlfSIsDQogIHZhbHVlc19mcm9tID0gYygiQjEiLCAiQjIiLCAiQjMiKQ0KKSAlPiUgYXMuZGF0YS50YWJsZSgpDQpkLndpZGUuMw0KYGBgDQoNCu+8iOacrOWwj+iKgui/m+W6pu+8mjMvM++8iQ0KDQojIOOAkOmYtuauteS9nOS4muKRoOOAkeaVsOaNruWkhOeQhue7vOWQiA0KDQrkvZzkuJropoHmsYLvvJoNCg0KLSAgIOWfuuS6jlvjgJDkvZzkuJo044CRXShodHRwczovL3BzeWNoYnJ1Y2UuZ2l0aHViLmlvL1JDb3Vyc2UvQ2hhcDAzIyVFNCVCRCU5QyVFNCVCOCU5QTQlRTYlOUMlOUYlRTYlOUMlQUIlRTglODclQUElRTklODAlODklRTUlODUlQUMlRTUlQkMlODAlRTYlOTUlQjAlRTYlOEQlQUUlRTUlQUYlQkMlRTUlODUlQTUp5ZKMW+OAkOS9nOS4mjbjgJFdKGh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS9DaGFwMDUjJUU0JUJEJTlDJUU0JUI4JTlBNiVFNiU5QyU5RiVFNiU5QyVBQiVFNCVCRCU5QyVFNCVCOCU5QSVFNiU5NSVCMCVFNiU4RCVBRSVFNSU4RiU5OCVFOSU4NyU4RiVFOCVBRSVBMSVFNyVBRSU5Nyl7LnVyaX3nmoTmnJ/mnKvoh6rpgInmlbDmja7lkozku6PnoIHnp6/ntK/vvIznu7zlkIjov5DnlKjmnKznq6DmiYDlrabnmoTlkITnp43mlbDmja7mk43kvZzmlrnms5Xlkozku6PnoIHvvIzlr7nmlbDmja7ov5vooYwqKuWinuWIoOafpeaUueOAgeihjOWIl+etm+mAieOAgeaOkuW6j+WOu+mHjeOAgeWIhue7hOaxh+aAu+OAgeWMuemFjeaLvOaOpeOAgemVv+Wuvei9rOaNoioq562J5pON5L2c77yM5L2T546w5a+555uu5YmN5omA5a2m5YWo6YOo5YaF5a6555qE5o6M5o+h5ZKM6L+B56e75bqU55SoDQotICAg5L2/55SoUiBNYXJrZG93buWujOaIkO+8jOWvueWFs+mUruS7o+eggeWPiue7k+aenOimgeacieazqOmHiuivtOaYjg0KDQrlubPlj7Dmj5DkuqTvvJoNCg0KLSAgIOi/kOihjOW+l+WIsOeahEhUTUznvZHpobUNCiAgICAtICAg5o+Q5Lqk5paH5Lu25ZG95ZCN5qC85byP77yaYOWtpuWPty3lp5PlkI0tUumYtuauteS9nOS4mjEuaHRtbGANCg==