版权声明:本套课程材料开源,使用和分享必须遵守「创作共用许可协议 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网页文件(本地的“.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/ku6PkuI3kuobkvaDnmoTogozogonorrDlv4bvvIHvvIkqKg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyDliIbnu4TmsYfmgLvvvIhkYXRhLnRhYmxl77yJDQoNCiMjIyMg44CQ5a6e6Le1NOOAkeWIhue7hOaxh+aAuyB7I+Wunui3tTTliIbnu4TmsYfmgLsgLnRhYnNldCAudGFic2V0LWZhZGUgLnRhYmxlLXBpbGx9DQoNCmBgYHtyfQ0KIyMg5pWw5o2u5YeG5aSH77ya5aSn5LqU5Lq65qC86Zeu5Y23QkZJ77yI6YOo5YiG5pWw5o2u77yJDQpkYXRhID0gYXMuZGF0YS50YWJsZShwc3ljaDo6YmZpKQ0KZGF0YVssIGxldCgNCiAgR2VuZGVyID0gZmFjdG9yKGdlbmRlciwgbGV2ZWxzPTE6MiwgbGFiZWxzPWMoIk1hbGUiLCAiRmVtYWxlIikpLA0KICBBZ2UgPSBhcy5udW1lcmljKGFnZSksDQogIEVkdSA9IGFzLmZhY3RvcihlZHVjYXRpb24pDQopXQ0KZCA9IGRhdGFbMjUzNToyNTQ2LCBjKCJHZW5kZXIiLCAiQWdlIiwgIkVkdSIsIHBhc3RlMCgiQSIsIDE6NSkpXQ0KZA0Kc3RyKGQpDQpgYGANCg0KIyMjIyMgKioxLiDliIbnu4TogZrlkIgqKg0KDQpgRFRbaSwgaiwgYnldYA0KDQotICAgYGJ5YO+8muWumuS5ieWIhue7hOWPmOmHj++8iOWOn+Wni+mhuuW6j++8iQ0KLSAgIGBrZXlieWDvvJrlrprkuYnliIbnu4Tlj5jph4/vvIjph43mlrDmjpLluo/vvIkNCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtNDMxMjY0NDg0LnBuZykNCg0KYGBge3J9DQojIyBieeWIhue7hO+8jOWOn+Wni+mhuuW6jw0KZFssIC4oLk4pLCBieT1HZW5kZXJdICAjIC5OIOaYr2RhdGEudGFibGXkv53nlZnlhbPplK7lrZfvvIznlKjkuo7nu5/orqHmoLfmnKzph48NCg0KIyMga2V5YnnliIbnu4TvvIzph43mlrDmjpLluo8NCmRbLCAuKC5OKSwga2V5Ynk9R2VuZGVyXSAgIyAuTiDmmK9kYXRhLnRhYmxl5L+d55WZ5YWz6ZSu5a2X77yM55So5LqO57uf6K6h5qC35pys6YePDQoNCmRbLCAuKC5OLCBNZWFuLkFnZSA9IG1lYW4oQWdlKSksIGtleWJ5PUdlbmRlcl0NCg0KZFssIC4oDQogIC5OLA0KICBNZWFuLkFnZSA9IG1lYW4oQWdlKSwNCiAgU0QuQWdlID0gc2QoQWdlKQ0KKSwga2V5Ynk9R2VuZGVyXQ0KDQpkW0FnZSA+PSAxNSwgLigNCiAgLk4sDQogIE1lYW4uQWdlID0gbWVhbihBZ2UpLA0KICBTRC5BZ2UgPSBzZChBZ2UpDQopLCBrZXlieT1HZW5kZXJdDQoNCiMjIOWFqOmDqOaVsOaNrueahOWIhue7hOe7n+iuoQ0KIyBFZHVjYXRpb246DQojIDEgPSBoaWdoIHNjaG9vbA0KIyAyID0gZmluaXNoZWQgaGlnaCBzY2hvb2wNCiMgMyA9IHNvbWUgY29sbGVnZQ0KIyA0ID0gY29sbGVnZSBncmFkdWF0ZQ0KIyA1ID0gZ3JhZHVhdGUgZGVncmVlDQpkYXRhWywgLigNCiAgLk4sDQogIE1lYW4uQWdlID0gbWVhbihBZ2UpDQopLCBrZXlieT0uKEdlbmRlciwgRWR1KV0NCmBgYA0KDQrvvIjmnKzlsI/oioLov5vluqbvvJoxLzLvvIkNCg0KIyMjIyMgKioyLiDliIbnu4TorqHnrpcqKg0KDQpgYGB7cn0NCmRbLCBNZWFuLkFnZSA6PSBtZWFuKEFnZSldICAjIOaAu+Wdh+WAvA0KZA0KDQpkWywgTWVhbi5BZ2UuRyA6PSBtZWFuKEFnZSksIGtleWJ5PUdlbmRlcl0gICMg57uE5Z2H5YC8DQpkDQoNCmRbR2VuZGVyPT0iTWFsZSIsIEFnZUdyb3VwIDo9IGlmZWxzZShBZ2U8NDAsICJZb3VuZyIsICJNaWRkbGUiKV0NCmQNCg0KIyMg5oC75Z2H5YC85Lit5b+D5YyWDQpkWywgQWdlLkdyYW5kLkMgOj0gQWdlIC0gbWVhbihBZ2UpXQ0KZFssIC4oR2VuZGVyLCBBZ2UsIE1lYW4uQWdlLCBBZ2UuR3JhbmQuQyldDQoNCiMjIOe7hOWdh+WAvOS4reW/g+WMlg0KZFssIEFnZS5Hcm91cC5DIDo9IEFnZSAtIG1lYW4oQWdlKSwga2V5Ynk9R2VuZGVyXQ0KZFssIC4oR2VuZGVyLCBBZ2UsIE1lYW4uQWdlLCBNZWFuLkFnZS5HLCBBZ2UuR3JvdXAuQyldDQpgYGANCg0KIyMjIyDjgJDnn6Xor4bngrnjgJFkYXRhLnRhYmxl5qC45b+D55+l6K+G54K55oC757uTIHsj55+l6K+G54K5ZGF0YS50YWJsZeaguOW/g+efpeivhueCueaAu+e7k30NCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMjAwNjI0ODA1Ni5wbmcpDQoNCu+8iOacrOWwj+iKgui/m+W6pu+8mjIvMu+8iQ0KDQojIOWMuemFjeaLvOaOpe+8iGRwbHly77yJDQoNCiMjIyMg44CQ55+l6K+G54K544CRZHBseXLljIXvvJpqb2lu57O75YiX5Ye95pWwIHsj55+l6K+G54K5ZHBseXLljIVqb2lu57O75YiX5Ye95pWwfQ0KDQrkuKTkuKrmlbDmja5gZDFg5ZKMYGQyYOWFt+acieebuOWQjOWPmOmHj2AidmFyImDvvJoNCg0KLSAgIGBsZWZ0X2pvaW4oZDEsIGQyLCBieT0idmFyIilg77ya5ZCRYGQxYOWQiOW5tuKtkO+4j++8iOacgOW4uOeUqO+8iQ0KLSAgIGByaWdodF9qb2luKGQxLCBkMiwgYnk9InZhciIpYO+8muWQkWBkMmDlkIjlubYNCi0gICBgaW5uZXJfam9pbihkMSwgZDIsIGJ5PSJ2YXIiKWDvvJrlj5ZgZDFg5ZKMYGQyYOS6pOmbhuWQiOW5tg0KLSAgIGBmdWxsX2pvaW4oZDEsIGQyLCBieT0idmFyIilg77ya5Y+WYGQxYOWSjGBkMmDlubbpm4blkIjlubYNCg0K77yIZGF0YS50YWJsZeS5n+iDveWujOaIkOWMuemFjeaLvOaOpeaTjeS9nO+8jOS9huavlGRwbHly6Zq+55So77yJDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTE3NDczMzE0NDMucG5nKQ0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0xNTMxNzM1MzA0LnBuZykNCg0KIyMjIyDjgJDlrp7ot7U144CR5Yy56YWN5ou85o6lIHsj5a6e6Le1NeWMuemFjeaLvOaOpSAudGFic2V0IC50YWJzZXQtZmFkZSAudGFibGUtcGlsbH0NCg0KIyMjIyMgKioxLiDljLnphY3mi7zmjqUt5L6LMSoqDQoNCmBgYHtyfQ0KIyMg5pWw5o2u5YeG5aSH77ya5Lik5Liq5p2l5rqQ55qE5pWw5o2u77yM6Iez5bCR5YyF5ZCr5LiA5Liq5YWx5ZCM5Y+Y6YePDQpkMSA9IGFzLmRhdGEudGFibGUoZHBseXI6OmJhbmRfbWVtYmVycykNCmQxDQpkMiA9IGFzLmRhdGEudGFibGUoZHBseXI6OmJhbmRfaW5zdHJ1bWVudHMpDQpkMg0KZDMgPSBhcy5kYXRhLnRhYmxlKGRwbHlyOjpiYW5kX2luc3RydW1lbnRzMikNCmQzDQoNCiMjIOWMuemFjeaLvOaOpe+8muebuOWQjOWPmOmHj+WQjQ0KZGF0YSA9IGxlZnRfam9pbihkMSwgZDIsIGJ5PSJuYW1lIikgICMg5ZCR5bem6L655pWw5o2u5ZCI5bm2DQpkYXRhDQoNCnJpZ2h0X2pvaW4oZDEsIGQyLCBieT0ibmFtZSIpICAjIOWQkeWPs+i+ueaVsOaNruWQiOW5tg0KaW5uZXJfam9pbihkMSwgZDIsIGJ5PSJuYW1lIikgICMg5Lik5Liq5pWw5o2u55qE5Lqk6ZuGDQpmdWxsX2pvaW4oZDEsIGQyLCBieT0ibmFtZSIpICAjIOS4pOS4quaVsOaNrueahOW5tumbhg0KDQojIyDljLnphY3mi7zmjqXvvJrkuI3lkIzlj5jph4/lkI0NCm5hbWVzKGQxKSAgIyDkurrlkI3lj5jph4/kuLoibmFtZSINCm5hbWVzKGQzKSAgIyDkurrlkI3lj5jph4/kuLoiYXJ0aXN0Ig0KZGF0YSA9IGxlZnRfam9pbihkMSwgZDMsIGJ5PWMoIm5hbWUiPSJhcnRpc3QiKSkNCmRhdGENCmBgYA0KDQrvvIjmnKzlsI/oioLov5vluqbvvJoxLzLvvIkNCg0KIyMjIyMgKioyLiDljLnphY3mi7zmjqUt5L6LMioqDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMSkNCmQgPSBkYXRhLnRhYmxlKHg9cm5vcm0oOSksIGNpdHk9cmVwKDE6MywgZWFjaD0zKSkNCmQNCg0KZC5ncm91cCA9IGRhdGEudGFibGUoDQogIGNpdHkgPSAxOjMsDQogIGxhYmVsID0gYygi5YyX5LqsIiwgIuS4iua1tyIsICLlub/lt54iKSwNCiAgR0RQID0gYyg1MjEsIDU2NywgMzEwKQ0KKQ0KZC5ncm91cA0KDQpkLm1lcmdlID0gbGVmdF9qb2luKGQsIGQuZ3JvdXAsIGJ5PSJjaXR5IikNCmQubWVyZ2UNCmBgYA0KDQrvvIjmnKzlsI/oioLov5vluqbvvJoyLzLvvIkNCg0KIyDplb/lrr3ovazmjaLvvIh0aWR5cu+8iQ0KDQojIyMjIOOAkOefpeivhueCueOAkeWuveaVsOaNriB2cy4g6ZW/5pWw5o2uIHsj55+l6K+G54K55a695pWw5o2uLXZzLi3plb/mlbDmja59DQoNCi0gICAqKuWuveaVsOaNru+8iHdpZGUtZm9ybWF0IGRhdGHvvIkqKuKAlOKAlCDigJzmsYfmgLvooajigJ3miJbigJzpgI/op4booajigJ0NCiAgICAtICAg5q+P5Liq6KKr6KeC5rWL55qE5a+56LGh5Y+q5Y2g5LiA6KGM77yM6ICM6K+l5a+56LGh55qE5aSa5Liq5bGe5oCn5oiW6ZqP5pe26Ze05Y+Y5YyW55qE6KeC5rWL5YC85L2c5Li65LiN5ZCM55qE5YiX5qiq5ZCR5bGV5byADQogICAgICAgIC0gICDmoLjlv4PnibnlvoHvvJrkuIDkuLvkvZPkuIDooYzvvIzlpJrlj5jph4/lpJrliJcNCiAgICAgICAgLSAgIOeBtea0u+aAp++8muWinuWKoOaWsOWPmOmHj+mcgOWinuWKoOaWsOWIlw0KICAgICAgICAtICAg5LyY54K577ya5a+55Lq657G76ZiF6K+75q+U6L6D5Y+L5aW977yM5b6I5YOP5oiR5Lus5bi46KeB55qE55S15a2Q6KGo5qC85oiW5rGH5oC75oql6KGo77yM5b6I5aSa57uf6K6h5qih5Z6L55qE6L6T5YWl5Lmf6KaB5rGC5piv5a695qC85byPDQogICAgICAgIC0gICDnvLrngrnvvJrkuI3liKnkuo7ov5vooYzmn5DkupvliIbmnpDlkozlj6/op4bljJbvvIzlm6DkuLrmlbDmja7nu7TluqbvvIjlj5jph4/vvInooqvplIHlrprlnKjliJfnu5PmnoTkuK0NCg0KIVvihpEg5a695pWw5o2u56S65L6LXShpbWFnZXMvY2xpcGJvYXJkLTIzOTAyNzgzNTQucG5nKQ0KDQotICAgKirplb/mlbDmja7vvIhsb25nLWZvcm1hdCBkYXRh77yJKirigJTigJQg4oCc5rWB5rC06K6w5b2V4oCd5oiW4oCc6KeE6IyD5YyW4oCd55qE5pWw5o2u5bqT6KGoDQogICAgLSAgIOavj+S4quiiq+ingua1i+eahOWvueixoeS8muWNoOaNruWkmuihjO+8jOavj+S4gOihjOmAmuW4uOWPquWMheWQq+S4gOS4quWPmOmHj+WcqOafkOS4gOS4quaXtumXtOeCueaIluadoeS7tuS4i+eahOingua1i+WAvA0KICAgICAgICAtICAg5qC45b+D54m55b6B77ya5LiA6KeC5rWL5LiA6KGM77yM6ZSu5YC85a+55b2i5byPDQogICAgICAgIC0gICDngbXmtLvmgKfvvJrlop7liqDmlrDop4LmtYvmiJblj5jph4/lj6rpnIDlop7liqDmlrDooYzvvIznu5PmnoTnqLPlrpoNCiAgICAgICAgLSAgIOS8mOeCue+8mue7k+aehOinhOaVtO+8jOaYr+aVtOa0geaVsOaNrueahOagh+WHhuagvOW8j++8jOeJueWIq+mAguWQiOeUqGBnZ3Bsb3QyYOetieW3peWFt+i/m+ihjOaVsOaNruWPr+inhuWMlu+8jOS5n+S+v+S6jui/m+ihjOWIhue7hOOAgeiBmuWQiOWSjOWkjeadguWPmOaNou+8jOaVsOaNruW6k+WtmOWCqOS5n+W4uOmHh+eUqOexu+S8vOe7k+aehA0KICAgICAgICAtICAg57y654K577ya5a+55Lq657G76ZiF6K+75LiN5aSq55u06KeC77yM5pi+5b6X5YaX6ZW/DQoNCiFb4oaRIOmVv+aVsOaNruekuuS+i10oaW1hZ2VzL2NsaXBib2FyZC0yODcyMDkzMzE0LnBuZykNCg0KIyMjIyDjgJDnn6Xor4bngrnjgJF0aWR5cuWMhe+8mnBpdm9057O75YiX5Ye95pWwIHsj55+l6K+G54K5dGlkeXLljIVwaXZvdOezu+WIl+WHveaVsH0NCg0K77yIZGF0YS50YWJsZeS5n+iDveWujOaIkOmVv+Wuvei9rOaNouaTjeS9nO+8jOS9huavlHRpZHly6Zq+55So77yJDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTM2MzA1OTg5MzkucG5nKQ0KDQojIyMjIOOAkOWunui3tTbjgJHplb/lrr3ovazmjaIgeyPlrp7ot7U26ZW/5a696L2s5o2iIC50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJsZS1waWxsfQ0KDQojIyMjIyAqKjEuIOWuveWPmOmVvyoqDQoNCmBgYHtyfQ0KYnJ1Y2VSOjp3aXRoaW4uMSAgIyDooqvor5XlhoXph43lpI3mtYvph4/vvIjlrr3mlbDmja7vvIkNCg0KZC5sb25nLjEgPSBwaXZvdF9sb25nZXIoDQogIGRhdGEgPSB3aXRoaW4uMSwNCiAgY29scyA9IEExOkE0LA0KICBuYW1lc190byA9ICJDb25kaXRpb24iLA0KICB2YWx1ZXNfdG8gPSAiWSINCikgJT4lIGFzLmRhdGEudGFibGUoKQ0KZC5sb25nLjEgICMg6ZW/5pWw5o2uDQpgYGANCg0KYGBge3J9DQpicnVjZVI6OndpdGhpbi4yICAjIOiiq+ivleWGhemHjeWkjea1i+mHj++8iOWuveaVsOaNru+8iQ0KDQpkLmxvbmcuMiA9IHBpdm90X2xvbmdlcigNCiAgZGF0YSA9IHdpdGhpbi4yLA0KICBjb2xzID0gQTFCMTpBMkIzLA0KICBuYW1lc190byA9IGMoIkNvbmQuQSIsICJDb25kLkIiKSwNCiAgbmFtZXNfcGF0dGVybiA9ICJBKC4pQiguKSIsDQogIHZhbHVlc190byA9ICJZIg0KKSAlPiUgYXMuZGF0YS50YWJsZSgpDQpkLmxvbmcuMiAgIyDplb/mlbDmja4NCmBgYA0KDQrvvIjmnKzlsI/oioLov5vluqbvvJoxLzPvvIkNCg0KIyMjIyMgKioyLiDplb/lj5jlrr0qKg0KDQpgYGB7cn0NCmQubG9uZy4xICAjIOmVv+aVsOaNru+8iOingeKAnOWuveWPmOmVv+KAnemDqOWIhuS7o+egge+8iQ0KDQpkLndpZGUuMSA9IHBpdm90X3dpZGVyKA0KICBkYXRhID0gZC5sb25nLjEsDQogIGlkX2NvbHMgPSBJRCwNCiAgbmFtZXNfZnJvbSA9ICJDb25kaXRpb24iLA0KICB2YWx1ZXNfZnJvbSA9ICJZIg0KKSAlPiUgYXMuZGF0YS50YWJsZSgpDQpkLndpZGUuMSAgIyDlrr3mlbDmja4NCmBgYA0KDQpgYGB7cn0NCmQubG9uZy4yICAjIOmVv+aVsOaNru+8iOingeKAnOWuveWPmOmVv+KAnemDqOWIhuS7o+egge+8iQ0KDQpkLndpZGUuMiA9IHBpdm90X3dpZGVyKA0KICBkYXRhID0gZC5sb25nLjIsDQogIGlkX2NvbHMgPSBJRCwNCiAgbmFtZXNfZnJvbSA9IGMoIkNvbmQuQSIsICJDb25kLkIiKSwNCiAgbmFtZXNfcHJlZml4ID0gIkEiLA0KICBuYW1lc19zZXAgPSAiX0IiLA0KICB2YWx1ZXNfZnJvbSA9ICJZIg0KKSAlPiUgYXMuZGF0YS50YWJsZSgpDQpkLndpZGUuMiAgIyDlrr3mlbDmja4NCmBgYA0KDQrvvIjmnKzlsI/oioLov5vluqbvvJoyLzPvvIkNCg0KIyMjIyMgKiozLiDmm7TlpI3mnYLmg4XlhrUqKg0KDQpgYGB7cn0NCmQud2lkZS4yICAjIOWuveaVsOaNru+8iOingeKAnOmVv+WPmOWuveKAnemDqOWIhuS7o+egge+8iQ0KDQpkLmxvbmcuMyA9IHBpdm90X2xvbmdlcigNCiAgZGF0YSA9IGQud2lkZS4yLA0KICBjb2xzID0gc3RhcnRzX3dpdGgoIkEiKSwNCiAgbmFtZXNfdG8gPSBjKCJWYXJpYWJsZUEiLCAiLnZhbHVlIiksDQogIG5hbWVzX3BhdHRlcm4gPSAiQSguKV8oLispIg0KKSAlPiUgYXMuZGF0YS50YWJsZSgpDQpkLmxvbmcuMyAgIyBB5Y+Y6ZW/77yMQuS/neaMgeWuvQ0KYGBgDQoNCmBgYHtyfQ0KZC53aWRlLjMgPSBwaXZvdF93aWRlcigNCiAgZGF0YSA9IGQubG9uZy4zLA0KICBuYW1lc19mcm9tID0gIlZhcmlhYmxlQSIsDQogIG5hbWVzX2dsdWUgPSAiQXtWYXJpYWJsZUF9ey52YWx1ZX0iLA0KICB2YWx1ZXNfZnJvbSA9IGMoIkIxIiwgIkIyIiwgIkIzIikNCikgJT4lIGFzLmRhdGEudGFibGUoKQ0KZC53aWRlLjMNCmBgYA0KDQrvvIjmnKzlsI/oioLov5vluqbvvJozLzPvvIkNCg0KIyDjgJDpmLbmrrXkvZzkuJrikaDjgJHmlbDmja7lpITnkIbnu7zlkIgNCg0K5L2c5Lia6KaB5rGC77yaDQoNCi0gICDln7rkuo5b44CQ5L2c5LiaNOOAkV0oaHR0cHM6Ly9wc3ljaGJydWNlLmdpdGh1Yi5pby9SQ291cnNlL0NoYXAwMyMlRTQlQkQlOUMlRTQlQjglOUE0JUU2JTlDJTlGJUU2JTlDJUFCJUU4JTg3JUFBJUU5JTgwJTg5JUU1JTg1JUFDJUU1JUJDJTgwJUU2JTk1JUIwJUU2JThEJUFFJUU1JUFGJUJDJUU1JTg1JUE1KeWSjFvjgJDkvZzkuJo244CRXShodHRwczovL3BzeWNoYnJ1Y2UuZ2l0aHViLmlvL1JDb3Vyc2UvQ2hhcDA1IyVFNCVCRCU5QyVFNCVCOCU5QTYlRTYlOUMlOUYlRTYlOUMlQUIlRTQlQkQlOUMlRTQlQjglOUElRTYlOTUlQjAlRTYlOEQlQUUlRTUlOEYlOTglRTklODclOEYlRTglQUUlQTElRTclQUUlOTcpey51cml955qE5pyf5pyr6Ieq6YCJ5pWw5o2u5ZKM5Luj56CB56ev57Sv77yM57u85ZCI6L+Q55So5pys56ug5omA5a2m55qE5ZCE56eN5pWw5o2u5pON5L2c5pa55rOV5ZKM5Luj56CB77yM5a+55pWw5o2u6L+b6KGMKirlop7liKDmn6XmlLnjgIHooYzliJfnrZvpgInjgIHmjpLluo/ljrvph43jgIHliIbnu4TmsYfmgLvjgIHljLnphY3mi7zmjqXjgIHplb/lrr3ovazmjaIqKuetieaTjeS9nO+8jOS9k+eOsOWvueebruWJjeaJgOWtpuWFqOmDqOWGheWuueeahOaOjOaPoeWSjOi/geenu+W6lOeUqA0KLSAgIOS9v+eUqFIgTWFya2Rvd27lrozmiJDvvIzlr7nlhbPplK7ku6PnoIHlj4rnu5PmnpzopoHmnInms6jph4ror7TmmI4NCg0K5bmz5Y+w5o+Q5Lqk77yaDQoNCi0gICDov5DooYzlvpfliLDnmoRIVE1M572R6aG15paH5Lu277yI5pys5Zyw55qE4oCcLmh0bWzigJ3lkI7nvIDmoLzlvI/mlofku7bvvIkNCiAgICAtICAg5o+Q5Lqk5paH5Lu25ZG95ZCN5qC85byP77yaYOWtpuWPty3lp5PlkI0tUumYtuauteS9nOS4mjEuaHRtbGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNClvov5Tlm57or77nqIvkuLvpobVdKGh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS8pDQoNCsKpIOWMheWvkuWQtOmcnA0K