Select 多列并将宽变长
Select multiple columns and reshape wide to long
我有与案件及其联系人有关的广泛数据集。 (这是一个虚构的例子;真实的数据集要大得多)。
structure(list(record_id = structure(1:4, .Label = c("01-001",
"01-002", "01-003", "01-004"), class = "factor"), place = structure(c(1L,
2L, 1L, 1L), .Label = c("a", "b"), class = "factor"), sex = structure(c(2L,
2L, 1L, 2L), .Label = c("F", "M"), class = "factor"), age = c(4L,
13L, 28L, 44L), d02_1 = c(2L, 2L, NA, 2L), d02_2 = structure(c(3L,
2L, 1L, 3L), .Label = c("", "F", "M"), class = "factor"), d02_3 = c(27L,
16L, NA, 66L), d03_1 = c(3L, 3L, NA, 3L), d03_2 = structure(c(3L,
3L, 1L, 2L), .Label = c("", "F", "M"), class = "factor"), d03_3 = c(14L,
55L, NA, 12L), d04_1 = c(4L, NA, NA, NA), d04_2 = structure(c(2L,
1L, 1L, 1L), .Label = c("", "M"), class = "factor"), d04_3 = c(7L,
NA, NA, NA)), .Names = c("record_id", "place", "sex", "age",
"d02_1", "d02_2", "d02_3", "d03_1", "d03_2", "d03_3", "d04_1",
"d04_2", "d04_3"), row.names = c(NA, -4L), class = "data.frame")
其中:
- record_id是案例的唯一标识
- place为案件居住地
- 年龄是个案的年龄
性别为案例性别
d02_1, d03_1, d04_1 ... d0j_1 是联系人的 ID
- d02_2, d03_2, d04_2 ... d0j_2 是联系人的性别
- d02_3, d03_3, d04_3 ... d0j_3 是联系人的年龄
在真实的数据集中,每个案例可能有很多联系人,以及更多与联系人特征相关的变量。并非所有病例都会有接触者。
我想将数据集重塑为整洁的格式,每个 case/contact 一行,即:
id case place sex age
1 01-001 1 a M 4
2 01-001-2 0 a M 27
3 01-001-3 0 a M 14
4 01-001-4 0 a M 7
5 01-002 1 b M 13
6 01-002-2 0 b F 16
7 01-002-3 0 b M 55
8 01-003 1 a F 28
9 01-004 1 a M 44
10 01-004-2 0 a M 66
11 01-004-3 0 a F 12
我想我需要创建与每个联系人相关的列名向量(可能在列名上使用字符匹配),select 这些列按顺序排列,并将它们附加到彼此(如以及连接 case/contact id),但真的很难避免大量复制代码行。必须是更有效的方法吗?
这是您要找的吗?
这是一个 dplyr
解决方案,由于多种原因,它很丑陋,但我认为它可以完成工作。
DF <- DF %>%
rename_(.dots=setNames(names(.), gsub('_1','_ContactID',names(.)))) %>%
rename_(.dots=setNames(names(.), gsub('_2','_sex',names(.)))) %>%
rename_(.dots=setNames(names(.), gsub('_3','_age',names(.)))) %>%
rename(d00_sex=sex,d00_age=age) %>%
mutate(d00_ContactID=1) %>%
gather(Var,Val,-record_id,-place) %>%
mutate(Val =ifelse(Val=='',NA,Val)) %>%
separate(Var,c('ContactLevel','Var'),sep='_') %>%
spread(Var,Val) %>%
arrange(record_id,ContactLevel) %>%
filter(!is.na(age),!is.na(ContactID),!is.na(sex)) %>%
mutate(age = as.numeric(age))
为了清楚起见,我首先重命名您的变量。 (rename_
行)
接下来,我将您的案例信息变量放入一个一致的模式中,其中案例信息为 ContactID=1。 (ename
和 mutate
行)
Gather
将数据从宽变长,但给我们留下了一个非常难看的列,并将所有数据转换为字符。 (这是触发警告的丑陋部分。)
separate
将旧列名称拆分为 Contact ID 和数据列。
spread
然后又将年龄、性别、身份证开辟成栏目。在这一行,这些数据是你想要的,但仍然可以稍微清理一下。
arrange
不是必需的,但它将所有记录 ID 放在一起。
filter
也不是必需的,它只是删除没有合同信息的行。
最后,我使用 mutate
将 age
从字符转换为数字。如果你愿意,你也可以在这里把性别变成一个因素,可能还有联系 ID。
我有与案件及其联系人有关的广泛数据集。 (这是一个虚构的例子;真实的数据集要大得多)。
structure(list(record_id = structure(1:4, .Label = c("01-001",
"01-002", "01-003", "01-004"), class = "factor"), place = structure(c(1L,
2L, 1L, 1L), .Label = c("a", "b"), class = "factor"), sex = structure(c(2L,
2L, 1L, 2L), .Label = c("F", "M"), class = "factor"), age = c(4L,
13L, 28L, 44L), d02_1 = c(2L, 2L, NA, 2L), d02_2 = structure(c(3L,
2L, 1L, 3L), .Label = c("", "F", "M"), class = "factor"), d02_3 = c(27L,
16L, NA, 66L), d03_1 = c(3L, 3L, NA, 3L), d03_2 = structure(c(3L,
3L, 1L, 2L), .Label = c("", "F", "M"), class = "factor"), d03_3 = c(14L,
55L, NA, 12L), d04_1 = c(4L, NA, NA, NA), d04_2 = structure(c(2L,
1L, 1L, 1L), .Label = c("", "M"), class = "factor"), d04_3 = c(7L,
NA, NA, NA)), .Names = c("record_id", "place", "sex", "age",
"d02_1", "d02_2", "d02_3", "d03_1", "d03_2", "d03_3", "d04_1",
"d04_2", "d04_3"), row.names = c(NA, -4L), class = "data.frame")
其中:
- record_id是案例的唯一标识
- place为案件居住地
- 年龄是个案的年龄
性别为案例性别
d02_1, d03_1, d04_1 ... d0j_1 是联系人的 ID
- d02_2, d03_2, d04_2 ... d0j_2 是联系人的性别
- d02_3, d03_3, d04_3 ... d0j_3 是联系人的年龄
在真实的数据集中,每个案例可能有很多联系人,以及更多与联系人特征相关的变量。并非所有病例都会有接触者。
我想将数据集重塑为整洁的格式,每个 case/contact 一行,即:
id case place sex age
1 01-001 1 a M 4
2 01-001-2 0 a M 27
3 01-001-3 0 a M 14
4 01-001-4 0 a M 7
5 01-002 1 b M 13
6 01-002-2 0 b F 16
7 01-002-3 0 b M 55
8 01-003 1 a F 28
9 01-004 1 a M 44
10 01-004-2 0 a M 66
11 01-004-3 0 a F 12
我想我需要创建与每个联系人相关的列名向量(可能在列名上使用字符匹配),select 这些列按顺序排列,并将它们附加到彼此(如以及连接 case/contact id),但真的很难避免大量复制代码行。必须是更有效的方法吗?
这是您要找的吗?
这是一个 dplyr
解决方案,由于多种原因,它很丑陋,但我认为它可以完成工作。
DF <- DF %>%
rename_(.dots=setNames(names(.), gsub('_1','_ContactID',names(.)))) %>%
rename_(.dots=setNames(names(.), gsub('_2','_sex',names(.)))) %>%
rename_(.dots=setNames(names(.), gsub('_3','_age',names(.)))) %>%
rename(d00_sex=sex,d00_age=age) %>%
mutate(d00_ContactID=1) %>%
gather(Var,Val,-record_id,-place) %>%
mutate(Val =ifelse(Val=='',NA,Val)) %>%
separate(Var,c('ContactLevel','Var'),sep='_') %>%
spread(Var,Val) %>%
arrange(record_id,ContactLevel) %>%
filter(!is.na(age),!is.na(ContactID),!is.na(sex)) %>%
mutate(age = as.numeric(age))
为了清楚起见,我首先重命名您的变量。 (rename_
行)
接下来,我将您的案例信息变量放入一个一致的模式中,其中案例信息为 ContactID=1。 (ename
和 mutate
行)
Gather
将数据从宽变长,但给我们留下了一个非常难看的列,并将所有数据转换为字符。 (这是触发警告的丑陋部分。)
separate
将旧列名称拆分为 Contact ID 和数据列。
spread
然后又将年龄、性别、身份证开辟成栏目。在这一行,这些数据是你想要的,但仍然可以稍微清理一下。
arrange
不是必需的,但它将所有记录 ID 放在一起。
filter
也不是必需的,它只是删除没有合同信息的行。
最后,我使用 mutate
将 age
从字符转换为数字。如果你愿意,你也可以在这里把性别变成一个因素,可能还有联系 ID。