在R中将复杂的杂乱数据整理成长数据格式
Tidy complicated messy data into long data format in R
我可以通过创建数组、转置它们并组合它们来简单地手动完成此操作,或者可能通过 base::reshape
。然而,我想通过跳入 Tidyverse 来迁移到终极真理,但现在我溺水了。
我有这样的数据:
id A B
1 2 3
1 3 4
1 5 5
1 - 6
1 - 7
2 ...
我想要这个:
id A1 A2 A3 B1 B2 B3 B4 B5
1 2 3 5 3 4 5 6 7
2 ...
变量A
和B
中的实际值是上面的任意值,我的实际数据有10多个A和B对,有500多个id
。显然,我将数据推送为 "long" 格式,但这对我的数据很有意义。另外,一旦它们被这样排列,将它们塑造成长格式应该不难吧?
有什么惯用的 tidyverse 方法吗?如果我们可以在单个函数调用中将整个事情弄平(具有多个类似的 A
ish 和 B
ish 列),那就太好了。
这是一个使用 dplyr
和 tidyr
中的函数的解决方案。 dt2
是最终输出。
# Load package
library(dplyr)
library(tidyr)
# Create example data frame
dt <- read.table(text = "id A B
1 2 3
1 3 4
1 5 5
1 NA 6
1 NA 7",
header = TRUE, stringsAsFactors = FALSE)
# Process the data
dt2 <- dt %>%
gather(Label, Value, -id) %>%
drop_na(Value) %>%
group_by(id, Label) %>%
mutate(Label_Id = 1:n()) %>%
unite(Col, Label, Label_Id, sep = "") %>%
spread(Col, Value)
更新:创建一个函数来泛化过程
根据评论,OP要求更"generalized"的方法,我可能没有完全理解,但在这里我演示了如何将上述代码转换为函数并设计了三个测试用例。函数 flatten
有一个参数,即输入 tbl
或一个 data frame
。输入 tbl
或 data frame
的列应为 id, A, B, C, D ...
.
# Load package
library(dplyr)
library(tidyr)
# Process the data
flatten <- function(dt){
dt %>%
gather(Label, Value, -id) %>%
drop_na(Value) %>%
group_by(id, Label) %>%
mutate(Label_Id = 1:n()) %>%
unite(Col, Label, Label_Id, sep = "") %>%
spread(Col, Value)
}
### Test Case 1
test1 <- data_frame(id = rep(1, 5),
A = c(2, 3, 5, NA, NA),
B = 3:7)
test1_result <- flatten(test1)
### Test Case 2
test2 <- data_frame(id = c(rep(1, 5), rep(2, 8)),
A = c(2, 3, 5, NA, NA, 3, 4, 6, 8, 9, NA, 10, 12),
B = 3:15)
test2_result <- flatten(test2)
### Test Case 3
test3 <- data_frame(id = c(rep(1, 5), rep(2, 8)),
A = c(2, 3, 5, NA, NA, 3, 4, 6, 8, 9, NA, 10, 12),
B = 3:15,
C = c(rep(c(1, 2, 3, 4, 5), each = 2), NA, NA, NA),
D = seq(2, 26, 2))
test3_result <- flatten(test3)
我可以通过创建数组、转置它们并组合它们来简单地手动完成此操作,或者可能通过 base::reshape
。然而,我想通过跳入 Tidyverse 来迁移到终极真理,但现在我溺水了。
我有这样的数据:
id A B
1 2 3
1 3 4
1 5 5
1 - 6
1 - 7
2 ...
我想要这个:
id A1 A2 A3 B1 B2 B3 B4 B5
1 2 3 5 3 4 5 6 7
2 ...
变量A
和B
中的实际值是上面的任意值,我的实际数据有10多个A和B对,有500多个id
。显然,我将数据推送为 "long" 格式,但这对我的数据很有意义。另外,一旦它们被这样排列,将它们塑造成长格式应该不难吧?
有什么惯用的 tidyverse 方法吗?如果我们可以在单个函数调用中将整个事情弄平(具有多个类似的 A
ish 和 B
ish 列),那就太好了。
这是一个使用 dplyr
和 tidyr
中的函数的解决方案。 dt2
是最终输出。
# Load package
library(dplyr)
library(tidyr)
# Create example data frame
dt <- read.table(text = "id A B
1 2 3
1 3 4
1 5 5
1 NA 6
1 NA 7",
header = TRUE, stringsAsFactors = FALSE)
# Process the data
dt2 <- dt %>%
gather(Label, Value, -id) %>%
drop_na(Value) %>%
group_by(id, Label) %>%
mutate(Label_Id = 1:n()) %>%
unite(Col, Label, Label_Id, sep = "") %>%
spread(Col, Value)
更新:创建一个函数来泛化过程
根据评论,OP要求更"generalized"的方法,我可能没有完全理解,但在这里我演示了如何将上述代码转换为函数并设计了三个测试用例。函数 flatten
有一个参数,即输入 tbl
或一个 data frame
。输入 tbl
或 data frame
的列应为 id, A, B, C, D ...
.
# Load package
library(dplyr)
library(tidyr)
# Process the data
flatten <- function(dt){
dt %>%
gather(Label, Value, -id) %>%
drop_na(Value) %>%
group_by(id, Label) %>%
mutate(Label_Id = 1:n()) %>%
unite(Col, Label, Label_Id, sep = "") %>%
spread(Col, Value)
}
### Test Case 1
test1 <- data_frame(id = rep(1, 5),
A = c(2, 3, 5, NA, NA),
B = 3:7)
test1_result <- flatten(test1)
### Test Case 2
test2 <- data_frame(id = c(rep(1, 5), rep(2, 8)),
A = c(2, 3, 5, NA, NA, 3, 4, 6, 8, 9, NA, 10, 12),
B = 3:15)
test2_result <- flatten(test2)
### Test Case 3
test3 <- data_frame(id = c(rep(1, 5), rep(2, 8)),
A = c(2, 3, 5, NA, NA, 3, 4, 6, 8, 9, NA, 10, 12),
B = 3:15,
C = c(rep(c(1, 2, 3, 4, 5), each = 2), NA, NA, NA),
D = seq(2, 26, 2))
test3_result <- flatten(test3)