版权声明:本套课程材料开源,使用和分享必须遵守「创作共用许可协议 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")=<pointer: 0x0000012b3d1cace0> 
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")=<pointer: 0x0000012b3d1cace0> 

(本小节进度: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")=<pointer: 0x0000012b3d1cace0> 
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")=<pointer: 0x0000012b3d1cace0> 

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    E3
     <int> <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:     2     4     4     4     3     6     5     6     1     1     2     4     4
  3:     1     5     6     5     4     1     5     6     4     6     6     6     2
  4:     1     5     4     3     5     6     5     5     2     2     3     2     3
  5:     2     6     6     6     6     5     4     5     3     4     2     2     4
 ---                                                                              
413:     1     6     6     5     6     5     5     3     2     4     1     5     4
414:     1     6     6     6     6     6     6     6     2     1     4     3     6
415:     2     5     4     5     4     6     5     5     2     4     6     5     2
416:     2     6     5     4     5     4     4     1     4     1     1     5     4
417:     3     4     4     3     5     6     6     5     2     1     2     2     4
        E4    E5    N1    N2    N3    N4    N5    O1    O2    O3    O4    O5 gender
     <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>  <int>
  1:     5     2     2     2     2     2     2     6     1     5     5     2      1
  2:     2     6     3     3     5     3     2     5     2     6     6     1      2
  3:     1     1     1     2     1     3     6     6     6     5     6     1      1
  4:     6     5     1     2     1     2     1     5     1     6     6     1      2
  5:     5     5     2     2     2     2     3     5     2     5     5     1      2
 ---                                                                               
413:     4     2     1     1     1     4     2     6     1     6     6     1      1
414:     6     6     2     6     4     5     5     6     1     6     6     1      2
415:     3     5     1     1     3     4     1     5     1     4     6     1      2
416:     5     5    NA     1     4     2     4     5     4     5     5     1      1
417:     5     5     4     4     3     2     2     5     4     4     3     4      2
     education   age Gender   Age    Edu
         <int> <int> <fctr> <num> <fctr>
  1:         5    68   Male    68      5
  2:         5    51 Female    51      5
  3:         5    23   Male    23      5
  4:         5    48 Female    48      5
  5:         5    24 Female    24      5
 ---                                    
413:         5    28   Male    28      5
414:         5    26 Female    26      5
415:         5    40 Female    40      5
416:         5    28   Male    28      5
417:         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")=<pointer: 0x0000012b3d1cace0> 
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")=<pointer: 0x0000012b3d1cace0> 
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 AgeGroup
    <fctr> <num> <fctr> <int> <int> <int> <int> <int>    <num>      <num>   <char>
 1:   Male     3      5     2     5     5     4     5    31.25      27.60    Young
 2:   Male    65      2     5     4     2     6     4    31.25      27.60   Middle
 3:   Male    26      2     2     6     5     4     4    31.25      27.60    Young
 4:   Male    27      4     2     2     1     2     3    31.25      27.60    Young
 5:   Male    17   <NA>     2     4     4     3     4    31.25      27.60    Young
 6: Female    20      3     1     6     6     6     6    31.25      33.86     <NA>
 7: Female    56      5     3     5     3     5     5    31.25      33.86     <NA>
 8: Female    34      3     2     4     3     4     4    31.25      33.86     <NA>
 9: Female    29      4     1     6     5     3     5    31.25      33.86     <NA>
10: Female    21      4     4     4     5     4     5    31.25      33.86     <NA>
11: Female    32      2     3     5     4    NA     6    31.25      33.86     <NA>
12: Female    45      4     1     5     5     6     6    31.25      33.86     <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网页文件(本地的“.html”后缀格式文件)
    • 提交文件命名格式:学号-姓名-R阶段作业1.html

返回课程主页

© 包寒吴霜

LS0tDQp0aXRsZTogIuOAilLor63oqIDjgIvnrKw256ug77ya5pWw5o2u5pON5L2cIg0Kc3VidGl0bGU6IDxhIGhyZWY9Imh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS8iPui/lOWbnuivvueoi+S4u+mhtTwvYT4NCmF1dGhvcjogIuaOiOivvuaVmeW4iO+8muWMheWvkuWQtOmcnCINCiMgZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgYW5jaG9yX3NlY3Rpb25zOiB0cnVlDQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIGNzczogUm1kQ1NTLmNzcw0KLS0tDQoNCmBgYHs9aHRtbH0NCjxwIHN0eWxlPSJmb250LXNpemU6IDEycHgiPueJiOadg+WjsOaYju+8muacrOWll+ivvueoi+adkOaWmeW8gOa6kO+8jOS9v+eUqOWSjOWIhuS6q+W/hemhu+mBteWuiOOAjOWIm+S9nOWFseeUqOiuuOWPr+WNj+iuriBDQyBCWS1OQy1TQeOAje+8iOadpea6kOW8leeUqC3pnZ7llYbkuJrnlKjpgJTkvb/nlKgt5Lul55u45ZCM5pa55byP5YWx5Lqr77yJ44CCPGltZyBzcmM9ImltZy9DQy1CWS1OQy1TQS5qcGciIHdpZHRoPSIxMjBweCIgaGVpZ2h0PSI0MnB4IiBzdHlsZT0iZmxvYXQ6IHJpZ2h0IiAvPjwvcD4NCmBgYA0KDQpgYGB7ciBDb25maWcsIGluY2x1ZGU9RkFMU0V9DQpvcHRpb25zKA0KICBrbml0ci5rYWJsZS5OQSA9ICIiLA0KICBkaWdpdHMgPSA0DQopDQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGNvbW1lbnQgPSAiIiwNCiAgZmlnLndpZHRoID0gNiwNCiAgZmlnLmhlaWdodCA9IDQsDQogIGRwaSA9IDMwMA0KKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIENoYXAwNu+8muaVsOaNruaTjeS9nA0KDQojIyMjIOW+gOacn+imgeeCueWbnumhvg0KDQotIFtDaGFwMDUgXCMg5Y+Y6YeP6K6h566X55qE5aSa56eN5pa55byPXShodHRwczovL3BzeWNoYnJ1Y2UuZ2l0aHViLmlvL1JDb3Vyc2UvQ2hhcDA1IyVFNSU4RiU5OCVFOSU4NyU4RiVFOCVBRSVBMSVFNyVBRSU5NyVFNyU5QSU4NCVFNiU4MCVCQiVFNCVCRCU5MyVFNCVCQiU4QiVFNyVCQiU4RCl7LnVyaX0NCg0KIyMjIyDmnKznq6DopoHngrnnm67lvZUNCg0KLSBb44CQ55+l6K+G54K544CRZGF0YS50YWJsZeaguOW/g+imgee0oF0oI+efpeivhueCuWRhdGEudGFibGXmoLjlv4PopoHntKApDQotIFvjgJDmjqLntKLlj5HnjrDjgJFkYXRhLnRhYmxlIHZzLiBkcGx5ciAodGlkeXZlcnNlKSDmlbDmja7mk43kvZzku6PnoIHpo47moLzmr5TovoNdKCPmjqLntKLlj5HnjrBkYXRhLnRhYmxlLXZzLi1kcGx5ci10aWR5dmVyc2Ut5pWw5o2u5pON5L2c5Luj56CB6aOO5qC85q+U6L6DKQ0KLSBb44CQ5o6i57Si5Y+R546w44CR5oCn6IO95aSnUEvvvJpkYXRhLnRhYmxlIChSKSB2cy4gZHBseXIgKFIpIHZzLiBwYW5kYXMgKFB5dGhvbildKCPmjqLntKLlj5HnjrDmgKfog73lpKdwa2RhdGEudGFibGUtci12cy4tZHBseXItci12cy4tcGFuZGFzLXB5dGhvbikNCi0gW+OAkOWunui3tTHjgJHlop7liKDmn6XmlLldKCPlrp7ot7Ux5aKe5Yig5p+l5pS5Ke+8iOmHjeeCue+8iQ0KLSBb44CQ5a6e6Le1MuOAkeihjOWIl+etm+mAiV0oI+Wunui3tTLooYzliJfnrZvpgIkp77yI6YeN54K577yJDQotIFvjgJDlrp7ot7Uz44CR5o6S5bqP5Y676YeNXSgj5a6e6Le1M+aOkuW6j+WOu+mHjSkNCi0gW+OAkOiHqueUsee7g+S5oOOAkeaVsOaNruWfuuacrOaTjeS9nF0oI+iHqueUsee7g+S5oOaVsOaNruWfuuacrOaTjeS9nCkNCi0gW+OAkOWunui3tTTjgJHliIbnu4TmsYfmgLtdKCPlrp7ot7U05YiG57uE5rGH5oC7Ke+8iOmHjeeCue+8iQ0KLSBb44CQ55+l6K+G54K544CRZGF0YS50YWJsZeaguOW/g+efpeivhueCueaAu+e7k10oI+efpeivhueCuWRhdGEudGFibGXmoLjlv4Pnn6Xor4bngrnmgLvnu5MpDQotIFvjgJDnn6Xor4bngrnjgJFkcGx5cuWMhe+8mmpvaW7ns7vliJflh73mlbBdKCPnn6Xor4bngrlkcGx5cuWMhWpvaW7ns7vliJflh73mlbApDQotIFvjgJDlrp7ot7U144CR5Yy56YWN5ou85o6lXSgj5a6e6Le1NeWMuemFjeaLvOaOpSnvvIjph43ngrnvvIkNCi0gW+OAkOefpeivhueCueOAkeWuveaVsOaNriB2cy4g6ZW/5pWw5o2uXSgj55+l6K+G54K55a695pWw5o2uLXZzLi3plb/mlbDmja4pDQotIFvjgJDnn6Xor4bngrnjgJF0aWR5cuWMhe+8mnBpdm9057O75YiX5Ye95pWwXSgj55+l6K+G54K5dGlkeXLljIVwaXZvdOezu+WIl+WHveaVsCkNCi0gW+OAkOWunui3tTbjgJHplb/lrr3ovazmjaJdKCPlrp7ot7U26ZW/5a696L2s5o2iKQ0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIOacrOeroOaJgOmcgFLljIUNCmxpYnJhcnkoYnJ1Y2VSKQ0KIyBsaWJyYXJ5KGRwbHlyKSAgICAgICAjIOWKoOi9vWJydWNlUuaXtuW3sum7mOiupOWKoOi9vWRwbHlyDQojIGxpYnJhcnkodGlkeXIpICAgICAgICMg5Yqg6L29YnJ1Y2VS5pe25bey6buY6K6k5Yqg6L29dGlkeXINCiMgbGlicmFyeShkYXRhLnRhYmxlKSAgIyDliqDovb1icnVjZVLml7blt7Lpu5jorqTliqDovb1kYXRhLnRhYmxlDQpgYGANCg0KIyDmlbDmja7mk43kvZznsbtS5YyF5qaC6L+w5LiO5q+U6L6DDQoNCiMjIyMg44CQ55+l6K+G54K544CRZGF0YS50YWJsZeaguOW/g+imgee0oCB7I+efpeivhueCuWRhdGEudGFibGXmoLjlv4PopoHntKB9DQoNCi0gW+S4gOWbvuWtpuS8mmRhdGEudGFibGXljIXvvIjlrpjmlrnpgJ/mn6XooajvvIldKGh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS9jaGVhdHNoZWV0L2RhdGEudGFibGUucGRmKQ0KLSDmnoHnroDku6PnoIHpo47moLzvvJpgZGF0YVtpLCBqLCBieV1gIOKAlOKAlCDlj6rpnIDopoHkuIDlr7nkuK3mi6zlj7fvvIzlsLHog73lrozmiJDmiYDmnInmk43kvZzvvIENCiAgLSBgaWDvvJrooYzmk43kvZwNCiAgLSBgamDvvJrliJfmk43kvZwNCiAgLSBgYnlg77ya5YiG57uE5Y+Y6YePDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTgwOTI3MzI0OC5wbmcpDQoNCiMjIyMg44CQ5o6i57Si5Y+R546w44CRZGF0YS50YWJsZSB2cy4gZHBseXIgKHRpZHl2ZXJzZSkg5pWw5o2u5pON5L2c5Luj56CB6aOO5qC85q+U6L6DIHsj5o6i57Si5Y+R546wZGF0YS50YWJsZS12cy4tZHBseXItdGlkeXZlcnNlLeaVsOaNruaTjeS9nOS7o+eggemjjuagvOavlOi+g30NCg0KLSBbQSBkYXRhLnRhYmxlIGFuZCBkcGx5ciB0b3VyIChBdHJlYmFzLCAyMDE5KV0oaHR0cHM6Ly9hdHJlYmFzLmdpdGh1Yi5pby9wb3N0LzIwMTktMDMtMDMtZGF0YXRhYmxlLWRwbHlyLyl7LnVyaX0NCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMjU4NTA4MDgxMy5wbmcpDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTMxNzY5MDMzMTkucG5nKQ0KDQojIyMjIOOAkOaOoue0ouWPkeeOsOOAkeaAp+iDveWkp1BL77yaZGF0YS50YWJsZSAoUikgdnMuIGRwbHlyIChSKSB2cy4gcGFuZGFzIChQeXRob24pIHsj5o6i57Si5Y+R546w5oCn6IO95aSncGtkYXRhLnRhYmxlLXItdnMuLWRwbHlyLXItdnMuLXBhbmRhcy1weXRob24gLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYmxlLXBpbGx9DQoNCi0gPGh0dHBzOi8vaDJvYWkuZ2l0aHViLmlvL2RiLWJlbmNobWFyay8+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+aNouS4uk5B57y65aSx5YC8DQpkDQpgYGANCg0KLSBR77ya5aaC5L2V6Ieq5Yqo562b6YCJ44CB5pu/5o2i5peg5pWI5bm06b6E77yfDQogIC0gQe+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/mnKvoh6rpgInmlbDmja7vvIzlnKjoh6rlt7HnlLXohJHkuIroh6rnlLHnu4PkuaDmlbDmja7ln7rmnKzmk43kvZzvvIzkuLrjgJDpmLbmrrXkvZzkuJrikaDjgJHlgZrlh4blpIfjgIINCg0KLSDlj6/ku6XlsJ3or5XmlLnlj5jkuIrov7DnpLrkvovku6PnoIHkuK3nmoTmlbDlgLzojIPlm7TjgIHlj5jph4/ojIPlm7TjgIHnrZvpgInmnaHku7bjgIHmjpLluo/mlrnlvI/nrYkNCi0gKiroh6rlt7HmlbLku6PnoIHvvIzmjozmj6Hmm7TmiY7lrp7vvIHvvIhBSeabv+S7o+S4jeS6huS9oOeahOiCjOiCieiusOW/hu+8ge+8iSoqDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIOWIhue7hOaxh+aAu++8iGRhdGEudGFibGXvvIkNCg0KIyMjIyDjgJDlrp7ot7U044CR5YiG57uE5rGH5oC7IHsj5a6e6Le1NOWIhue7hOaxh+aAuyAudGFic2V0IC50YWJzZXQtZmFkZSAudGFibGUtcGlsbH0NCg0KYGBge3J9DQojIyDmlbDmja7lh4blpIfvvJrlpKfkupTkurrmoLzpl67ljbdCRknvvIjpg6jliIbmlbDmja7vvIkNCmRhdGEgPSBhcy5kYXRhLnRhYmxlKHBzeWNoOjpiZmkpDQpkYXRhWywgbGV0KA0KICBHZW5kZXIgPSBmYWN0b3IoZ2VuZGVyLCBsZXZlbHM9MToyLCBsYWJlbHM9YygiTWFsZSIsICJGZW1hbGUiKSksDQogIEFnZSA9IGFzLm51bWVyaWMoYWdlKSwNCiAgRWR1ID0gYXMuZmFjdG9yKGVkdWNhdGlvbikNCildDQpkID0gZGF0YVsyNTM1OjI1NDYsIGMoIkdlbmRlciIsICJBZ2UiLCAiRWR1IiwgcGFzdGUwKCJBIiwgMTo1KSldDQpkDQpzdHIoZCkNCmBgYA0KDQojIyMjIyAqKjEuIOWIhue7hOiBmuWQiCoqDQoNCmBEVFtpLCBqLCBieV1gDQoNCi0gYGJ5YO+8muWumuS5ieWIhue7hOWPmOmHj++8iOWOn+Wni+mhuuW6j++8iQ0KLSBga2V5Ynlg77ya5a6a5LmJ5YiG57uE5Y+Y6YeP77yI6YeN5paw5o6S5bqP77yJDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTQzMTI2NDQ4NC5wbmcpDQoNCmBgYHtyfQ0KIyMgYnnliIbnu4TvvIzljp/lp4vpobrluo8NCmRbLCAuKC5OKSwgYnk9R2VuZGVyXSAgIyAuTiDmmK9kYXRhLnRhYmxl5L+d55WZ5YWz6ZSu5a2X77yM55So5LqO57uf6K6h5qC35pys6YePDQoNCiMjIGtleWJ55YiG57uE77yM6YeN5paw5o6S5bqPDQpkWywgLiguTiksIGtleWJ5PUdlbmRlcl0gICMgLk4g5pivZGF0YS50YWJsZeS/neeVmeWFs+mUruWtl++8jOeUqOS6jue7n+iuoeagt+acrOmHjw0KDQpkWywgLiguTiwgTWVhbi5BZ2UgPSBtZWFuKEFnZSkpLCBrZXlieT1HZW5kZXJdDQoNCmRbLCAuKA0KICAuTiwNCiAgTWVhbi5BZ2UgPSBtZWFuKEFnZSksDQogIFNELkFnZSA9IHNkKEFnZSkNCiksIGtleWJ5PUdlbmRlcl0NCg0KZFtBZ2UgPj0gMTUsIC4oDQogIC5OLA0KICBNZWFuLkFnZSA9IG1lYW4oQWdlKSwNCiAgU0QuQWdlID0gc2QoQWdlKQ0KKSwga2V5Ynk9R2VuZGVyXQ0KDQojIyDlhajpg6jmlbDmja7nmoTliIbnu4Tnu5/orqENCiMgRWR1Y2F0aW9uOg0KIyAxID0gaGlnaCBzY2hvb2wNCiMgMiA9IGZpbmlzaGVkIGhpZ2ggc2Nob29sDQojIDMgPSBzb21lIGNvbGxlZ2UNCiMgNCA9IGNvbGxlZ2UgZ3JhZHVhdGUNCiMgNSA9IGdyYWR1YXRlIGRlZ3JlZQ0KZGF0YVssIC4oDQogIC5OLA0KICBNZWFuLkFnZSA9IG1lYW4oQWdlKQ0KKSwga2V5Ynk9LihHZW5kZXIsIEVkdSldDQpgYGANCg0K77yI5pys5bCP6IqC6L+b5bqm77yaMS8y77yJDQoNCiMjIyMjICoqMi4g5YiG57uE6K6h566XKioNCg0KYGBge3J9DQpkWywgTWVhbi5BZ2UgOj0gbWVhbihBZ2UpXSAgIyDmgLvlnYflgLwNCmQNCg0KZFssIE1lYW4uQWdlLkcgOj0gbWVhbihBZ2UpLCBrZXlieT1HZW5kZXJdICAjIOe7hOWdh+WAvA0KZA0KDQpkW0dlbmRlcj09Ik1hbGUiLCBBZ2VHcm91cCA6PSBpZmVsc2UoQWdlPDQwLCAiWW91bmciLCAiTWlkZGxlIildDQpkDQoNCiMjIOaAu+Wdh+WAvOS4reW/g+WMlg0KZFssIEFnZS5HcmFuZC5DIDo9IEFnZSAtIG1lYW4oQWdlKV0NCmRbLCAuKEdlbmRlciwgQWdlLCBNZWFuLkFnZSwgQWdlLkdyYW5kLkMpXQ0KDQojIyDnu4TlnYflgLzkuK3lv4PljJYNCmRbLCBBZ2UuR3JvdXAuQyA6PSBBZ2UgLSBtZWFuKEFnZSksIGtleWJ5PUdlbmRlcl0NCmRbLCAuKEdlbmRlciwgQWdlLCBNZWFuLkFnZSwgTWVhbi5BZ2UuRywgQWdlLkdyb3VwLkMpXQ0KYGBgDQoNCiMjIyMg44CQ55+l6K+G54K544CRZGF0YS50YWJsZeaguOW/g+efpeivhueCueaAu+e7kyB7I+efpeivhueCuWRhdGEudGFibGXmoLjlv4Pnn6Xor4bngrnmgLvnu5N9DQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTIwMDYyNDgwNTYucG5nKQ0KDQrvvIjmnKzlsI/oioLov5vluqbvvJoyLzLvvIkNCg0KIyDljLnphY3mi7zmjqXvvIhkcGx5cu+8iQ0KDQojIyMjIOOAkOefpeivhueCueOAkWRwbHly5YyF77yaam9pbuezu+WIl+WHveaVsCB7I+efpeivhueCuWRwbHly5YyFam9pbuezu+WIl+WHveaVsH0NCg0K5Lik5Liq5pWw5o2uYGQxYOWSjGBkMmDlhbfmnInnm7jlkIzlj5jph49gInZhciJg77yaDQoNCi0gYGxlZnRfam9pbihkMSwgZDIsIGJ5PSJ2YXIiKWDvvJrlkJFgZDFg5ZCI5bm24q2Q77iP77yI5pyA5bi455So77yJDQotIGByaWdodF9qb2luKGQxLCBkMiwgYnk9InZhciIpYO+8muWQkWBkMmDlkIjlubYNCi0gYGlubmVyX2pvaW4oZDEsIGQyLCBieT0idmFyIilg77ya5Y+WYGQxYOWSjGBkMmDkuqTpm4blkIjlubYNCi0gYGZ1bGxfam9pbihkMSwgZDIsIGJ5PSJ2YXIiKWDvvJrlj5ZgZDFg5ZKMYGQyYOW5tumbhuWQiOW5tg0KDQrvvIhkYXRhLnRhYmxl5Lmf6IO95a6M5oiQ5Yy56YWN5ou85o6l5pON5L2c77yM5L2G5q+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+aVsOaNrn0NCg0KLSAqKuWuveaVsOaNru+8iHdpZGUtZm9ybWF0IGRhdGHvvIkqKuKAlOKAlCDigJzmsYfmgLvooajigJ3miJbigJzpgI/op4booajigJ0NCiAgLSDmr4/kuKrooqvop4LmtYvnmoTlr7nosaHlj6rljaDkuIDooYzvvIzogIzor6Xlr7nosaHnmoTlpJrkuKrlsZ7mgKfmiJbpmo/ml7bpl7Tlj5jljJbnmoTop4LmtYvlgLzkvZzkuLrkuI3lkIznmoTliJfmqKrlkJHlsZXlvIANCiAgICAtIOaguOW/g+eJueW+ge+8muS4gOS4u+S9k+S4gOihjO+8jOWkmuWPmOmHj+WkmuWIlw0KICAgIC0g54G15rS75oCn77ya5aKe5Yqg5paw5Y+Y6YeP6ZyA5aKe5Yqg5paw5YiXDQogICAgLSDkvJjngrnvvJrlr7nkurrnsbvpmIXor7vmr5TovoPlj4vlpb3vvIzlvojlg4/miJHku6zluLjop4HnmoTnlLXlrZDooajmoLzmiJbmsYfmgLvmiqXooajvvIzlvojlpJrnu5/orqHmqKHlnovnmoTovpPlhaXkuZ/opoHmsYLmmK/lrr3moLzlvI8NCiAgICAtIOe8uueCue+8muS4jeWIqeS6jui/m+ihjOafkOS6m+WIhuaekOWSjOWPr+inhuWMlu+8jOWboOS4uuaVsOaNrue7tOW6pu+8iOWPmOmHj++8ieiiq+mUgeWumuWcqOWIl+e7k+aehOS4rQ0KDQohW+KGkSDlrr3mlbDmja7npLrkvotdKGltYWdlcy9jbGlwYm9hcmQtMjM5MDI3ODM1NC5wbmcpDQoNCi0gKirplb/mlbDmja7vvIhsb25nLWZvcm1hdCBkYXRh77yJKirigJTigJQg4oCc5rWB5rC06K6w5b2V4oCd5oiW4oCc6KeE6IyD5YyW4oCd55qE5pWw5o2u5bqT6KGoDQogIC0g5q+P5Liq6KKr6KeC5rWL55qE5a+56LGh5Lya5Y2g5o2u5aSa6KGM77yM5q+P5LiA6KGM6YCa5bi45Y+q5YyF5ZCr5LiA5Liq5Y+Y6YeP5Zyo5p+Q5LiA5Liq5pe26Ze054K55oiW5p2h5Lu25LiL55qE6KeC5rWL5YC8DQogICAgLSDmoLjlv4PnibnlvoHvvJrkuIDop4LmtYvkuIDooYzvvIzplK7lgLzlr7nlvaLlvI8NCiAgICAtIOeBtea0u+aAp++8muWinuWKoOaWsOingua1i+aIluWPmOmHj+WPqumcgOWinuWKoOaWsOihjO+8jOe7k+aehOeos+Wumg0KICAgIC0g5LyY54K577ya57uT5p6E6KeE5pW077yM5piv5pW05rSB5pWw5o2u55qE5qCH5YeG5qC85byP77yM54m55Yir6YCC5ZCI55SoYGdncGxvdDJg562J5bel5YW36L+b6KGM5pWw5o2u5Y+v6KeG5YyW77yM5Lmf5L6/5LqO6L+b6KGM5YiG57uE44CB6IGa5ZCI5ZKM5aSN5p2C5Y+Y5o2i77yM5pWw5o2u5bqT5a2Y5YKo5Lmf5bi46YeH55So57G75Ly857uT5p6EDQogICAgLSDnvLrngrnvvJrlr7nkurrnsbvpmIXor7vkuI3lpKrnm7Top4LvvIzmmL7lvpflhpfplb8NCg0KIVvihpEg6ZW/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++8iQ0KDQojIOOAkOmYtuauteS9nOS4muKRoOOAkeaVsOaNruWkhOeQhue7vOWQiA0KDQrkvZzkuJropoHmsYLvvJoNCg0KLSDln7rkuo5b44CQ5L2c5LiaNOOAkV0oaHR0cHM6Ly9wc3ljaGJydWNlLmdpdGh1Yi5pby9SQ291cnNlL0NoYXAwMyMlRTQlQkQlOUMlRTQlQjglOUE0JUU2JTlDJTlGJUU2JTlDJUFCJUU4JTg3JUFBJUU5JTgwJTg5JUU1JTg1JUFDJUU1JUJDJTgwJUU2JTk1JUIwJUU2JThEJUFFJUU1JUFGJUJDJUU1JTg1JUE1KeWSjFvjgJDkvZzkuJo244CRXShodHRwczovL3BzeWNoYnJ1Y2UuZ2l0aHViLmlvL1JDb3Vyc2UvQ2hhcDA1IyVFNCVCRCU5QyVFNCVCOCU5QTYlRTYlOUMlOUYlRTYlOUMlQUIlRTQlQkQlOUMlRTQlQjglOUElRTYlOTUlQjAlRTYlOEQlQUUlRTUlOEYlOTglRTklODclOEYlRTglQUUlQTElRTclQUUlOTcpey51cml955qE5pyf5pyr6Ieq6YCJ5pWw5o2u5ZKM5Luj56CB56ev57Sv77yM57u85ZCI6L+Q55So5pys56ug5omA5a2m55qE5ZCE56eN5pWw5o2u5pON5L2c5pa55rOV5ZKM5Luj56CB77yM5a+55pWw5o2u6L+b6KGMKirlop7liKDmn6XmlLnjgIHooYzliJfnrZvpgInjgIHmjpLluo/ljrvph43jgIHliIbnu4TmsYfmgLvjgIHljLnphY3mi7zmjqXjgIHplb/lrr3ovazmjaIqKuetieaTjeS9nO+8jOS9k+eOsOWvueebruWJjeaJgOWtpuWFqOmDqOWGheWuueeahOaOjOaPoeWSjOi/geenu+W6lOeUqA0KLSDkvb/nlKhSIE1hcmtkb3du5a6M5oiQ77yM5a+55YWz6ZSu5Luj56CB5Y+K57uT5p6c6KaB5pyJ5rOo6YeK6K+05piODQoNCuW5s+WPsOaPkOS6pO+8mg0KDQotIOi/kOihjOW+l+WIsOeahEhUTUznvZHpobXmlofku7bvvIjmnKzlnLDnmoTigJwuaHRtbOKAneWQjue8gOagvOW8j+aWh+S7tu+8iQ0KICAtIOaPkOS6pOaWh+S7tuWRveWQjeagvOW8j++8mmDlrablj7ct5aeT5ZCNLVLpmLbmrrXkvZzkuJoxLmh0bWxgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpb6L+U5Zue6K++56iL5Li76aG1XShodHRwczovL3BzeWNoYnJ1Y2UuZ2l0aHViLmlvL1JDb3Vyc2UvKQ0KDQrCqSDljIXlr5LlkLTpnJwNCg==