【问题标题】:Select multiple columns and reshape wide to long选择多列并将宽改成长
【发布时间】:2017-03-07 16:10:50
【问题描述】:

我拥有与案例及其联系人相关的广泛数据集。 (这是一个虚构的例子;真实的数据集要大得多)。

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 是案例的唯一标识
  • 地点是案件所在的地方
  • age 是病例的年龄
  • 性别就是病例的性别

  • 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 是联系人的年龄

在真实数据集中,每个案例可能有很多联系人,以及更多与联系人特征相关的变量。并非所有病例都有接触者。

我想将数据集重塑为整洁的格式,每个案例/联系人一行,即:

         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

我认为我需要创建与每个联系人相关的列名向量(可能对列名使用字符匹配),依次选择这些列,并将它们彼此附加(以及连接大小写/联系ID),但在没有大量复制代码行的情况下真的很挣扎。一定是更有效的方法吗?

【问题讨论】:

  • 这没有帮助吗:stackoverflow.com/questions/40229114/…。基本上看起来是一样的。
  • 你可能应该在读入时设置na.strings=''。这没有多大意义/让所有东西都更难在那里有空白......

标签: r dplyr tidyverse


【解决方案1】:

这是你要找的吗?

这是一个 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。 (enamemutate 行)

Gather 将数据从宽转换为长,但给我们留下了一个非常丑陋的列,并将所有数据转换为字符。 (这是触发警告的丑陋部分。)

separate 将旧列名拆分为联系人 ID 和数据列。

spread 然后将年龄、性别和 ID 再次打开到列中。在这一行,这些数据是您想要的,但仍然可以稍微清理一下。

arrange 不是必需的,但它将所有记录 ID 放在一起。

filter 也不是必须的,它只是删除没有合同信息的行。

最后,我使用mutateage 从字符转换为数字。如果你愿意,你也可以在这里把性变成一个因素,也可能是联系 ID。

【讨论】:

  • 是的 - 这就是工作。很好地使用 setNames 和 gsub
猜你喜欢
  • 2014-07-19
  • 1970-01-01
  • 2014-07-11
  • 2021-09-22
  • 2021-03-23
  • 2018-05-13
  • 2012-01-01
  • 2022-01-22
  • 2021-08-01
相关资源
最近更新 更多