在 R 中重新格式化 table
Reformat table in R
我有一个 table 如下(具有相同 ID 的不同行将具有相同的性别和年龄值但不同的类别和子类别值):
ID product.category sub.category gender age
1 1 food chicken M young
2 1 kitchen napkin M young
3 1 food steak M young
4 2 electronic phone F mid
5 3 cloth shirt M old
6 3 kitchen bowl M old
7 4 alch beer F young
并且通过组合具有相同 ID 的不同行,我想按如下方式改革 table:
ID product.category1 sub.category1 product.category2 sub.category2 product.category3 sub.category3 gender age
1 1 food chicken kitchen napkin food steak M young
2 2 electronic phone null null null null F mid
3 3 cloth shirt kitchen bowl null null M old
4 4 alch beer null null null null F young
我如何在 R 中执行此操作?
#
新数据集:text变量实际上是notes的文本列
text Category Subcategory variable1 variable2 variable3 variable4 date
aaaaa c1 s11 v1 N RETAIL Y 2014-01
aaaaa c2 s22 v1 N LEASE Y 2014-01
aaaaa c3 s31 v1 N LEASE Y 2014-01
bbbbb c1 s12 v2 N LEASE Y 2014-01
ccccc c2 s21 v1 N LEASE Y 2014-01
ddddd c2 s21 v1 N RETAIL Y 2014-01
ddddd c3 s31 v1 N LEASE Y 2014-01
eeeee c1 s11 v1 N RETAIL Y 2014-01
fffff c2 s21 v2 U RETAIL Y 2014-01
谢谢
我们使用包 reshape2
中的 melt
和 dcast
的组合。
library(dplyr)
library(reshape2)
m2 <- melt(df, c("ID", "gender", "age")) %>% group_by(ID, variable) %>%
mutate(variable2 = paste0(variable, seq_along(value)))
newdf <- dcast(m2[!names(m2) %in% "variable"], ...~variable2, value.var="value", fill="null")
我们首先通过产品类别和 sub-category 融合原始数据框。接下来使用 dplyr,我们按 id 列和产品列(现在默认称为 "variable")分组,并创建一个名为 variable2
的新列。这只是类别标题和 运行 观察计数的粘贴。
现在我们有了一个新列,我们可以通过它来展开数据。我们在新的 variable2 列上使用 dcast
去 "wide"。还有一个名为 fill
的参数,我们将其设置为 "null"
告诉 dcast 用什么来填充缺失值。
下面我们根据所需的输出对列重新排序。这个技巧即使很小也值得注意。创建一个交织序列很有趣。我们的输出按字母顺序排序("p1"、"p2"、"p3"、"s1"、"s2"、"s3")。我们想要一个将它们编织在一起的序列。挑战在于获得类似(1,4,2,5,3,6)的东西。所以我们使用:
c(rbind(1:3, 4:6))
[1] 1 4 2 5 3 6
很酷吧?我们利用了 rbind 在我们按行输入值时展开 column-wise 的事实。在我们的例子中,写入 1:3
无济于事,因为数据中可能有更多产品。但是我们知道有两个标题"product category"和"sub-subcategory"。我们将 variable2
的唯一值除以 2 并使用它。
n <- nrow(unique(m2[,"variable2"]))
newdf[c(1:3,(c(rbind(1:(n/2), (n/2+1):n))+3))]
# ID gender age product.category1 sub.category1 product.category2
# 1 1 M young food chicken kitchen
# 2 2 F mid electronic phone null
# 3 3 M old cloth shirt kitchen
# 4 4 F young alch beer null
# sub.category2 product.category3 sub.category3
# 1 napkin food steak
# 2 null null null
# 3 bowl null null
# 4 null null null
更新
使用提供的新数据集,相同的代码结构适用于新的列名。
m2 <- melt(df, measure.vars=c("Category", "Subcategory")) %>% group_by(text, variable) %>%
mutate(variable2 = paste0(variable, seq_along(value)))
newdf <- dcast(m2[!names(m2) %in% "variable"], ... ~ variable2, value.var="value", fill="null")
n <- nrow(unique(m2[,"variable2"]))
newdf2 <- newdf[c(1:5, c(rbind(1:(n/2), (n/2+1):n))+5)]
newdf2
# text variable1 variable3 variable4 date Category1 Subcategory1 Category2
# 1 aaaaa v1 LEASE Y 2014-01 null null c2
# 2 aaaaa v1 RETAIL Y 2014-01 c1 s11 null
# 3 bbbbb v2 LEASE Y 2014-01 c1 s12 null
# 4 ccccc v1 LEASE Y 2014-01 c2 s21 null
# 5 ddddd v1 LEASE Y 2014-01 null null c3
# 6 ddddd v1 RETAIL Y 2014-01 c2 s21 null
# 7 eeeee v1 RETAIL Y 2014-01 c1 s11 null
# 8 fffff v2 RETAIL Y 2014-01 c2 s21 null
# Subcategory2 Category3 Subcategory3
# 1 s22 c3 s31
# 2 null null null
# 3 null null null
# 4 null null null
# 5 s31 null null
# 6 null null null
# 7 null null null
# 8 null null null
data.table dcast 您可以使用 reshape2 或 data.table 包中的 dcast
:
library(data.table)
setDT(DT)
DT[, obsno := 1:.N, by=ID]
res <- dcast(DT, ID+gender+age~obsno, value.var=c("product.category","sub.category"))
这给出
ID gender age product.category_1 product.category_2 product.category_3 sub.category_1 sub.category_2 sub.category_3
1: 1 M young food kitchen food chicken napkin steak
2: 2 F mid electronic NA NA phone NA NA
3: 3 M old cloth kitchen NA shirt bowl NA
4: 4 F young alch NA NA beer NA NA
要按您想要的顺序查看列,您可以执行类似
的操作
res[, c(1:3,4,7,5,8,6,9), with=FALSE]
类似的方法可能适用于 tidyr 包(尽管它不会被称为 "dcast")。
我建议坚持使用长格式(您最初使用的格式)进行任何分析。您正在寻找的这种宽格式对于浏览数据以外的任何事情都非常麻烦。
第二个例子对于OP的第二个例子,我会做
DT2[, obsno := 1:.N, by=text]
dcast(DT2, ...~obsno, value.var=c("Category", "Subcategory"))
从@PierreLafortune 的回答中复制 ...~
技巧。结果是
text variable1 variable2 variable3 variable4 date Category_1 Category_2 Category_3 Subcategory_1 Subcategory_2 Subcategory_3
1: aaaaa v1 N LEASE Y 2014-01 NA c2 c3 NA s22 s31
2: aaaaa v1 N RETAIL Y 2014-01 c1 NA NA s11 NA NA
3: bbbbb v2 N LEASE Y 2014-01 c1 NA NA s12 NA NA
4: ccccc v1 N LEASE Y 2014-01 c2 NA NA s21 NA NA
5: ddddd v1 N LEASE Y 2014-01 NA c3 NA NA s31 NA
6: ddddd v1 N RETAIL Y 2014-01 c2 NA NA s21 NA NA
7: eeeee v1 N RETAIL Y 2014-01 c1 NA NA s11 NA NA
8: fffff v2 U RETAIL Y 2014-01 c2 NA NA s21 NA NA
dplyr
& tidyr
的替代方案:
newdf <- df %>% gather(variable, value, product.category, sub.category) %>%
group_by(ID, variable) %>%
mutate(variable2 = paste0(variable, seq_along(value))) %>%
ungroup() %>%
select(-variable) %>%
spread(variable2 , value)
给出:
> newdf
Source: local data frame [4 x 9]
ID gender age product.category1 product.category2 product.category3 sub.category1 sub.category2 sub.category3
(int) (fctr) (fctr) (chr) (chr) (chr) (chr) (chr) (chr)
1 1 M young food kitchen food chicken napkin steak
2 2 F mid electronic NA NA phone NA NA
3 3 M old cloth kitchen NA shirt bowl NA
4 4 F young alch NA NA beer NA NA
可以对第二个示例数据集执行相同的操作:
newdat <- dat %>% gather(variable, value, Category, Subcategory) %>%
group_by(text, variable) %>%
mutate(var2 = paste0(variable, seq_along(value))) %>%
ungroup() %>%
select(-variable) %>%
spread(var2 , value)
给出:
> newdat
Source: local data frame [8 x 12]
text variable1 variable2 variable3 variable4 date Category1 Category2 Category3 Subcategory1 Subcategory2 Subcategory3
(fctr) (fctr) (fctr) (fctr) (fctr) (fctr) (chr) (chr) (chr) (chr) (chr) (chr)
1 aaaaa v1 N LEASE Y 2014-01 NA c2 c3 NA s22 s31
2 aaaaa v1 N RETAIL Y 2014-01 c1 NA NA s11 NA NA
3 bbbbb v2 N LEASE Y 2014-01 c1 NA NA s12 NA NA
4 ccccc v1 N LEASE Y 2014-01 c2 NA NA s21 NA NA
5 ddddd v1 N LEASE Y 2014-01 NA c3 NA NA s31 NA
6 ddddd v1 N RETAIL Y 2014-01 c2 NA NA s21 NA NA
7 eeeee v1 N RETAIL Y 2014-01 c1 NA NA s11 NA NA
8 fffff v2 U RETAIL Y 2014-01 c2 NA NA s21 NA NA
我有一个 table 如下(具有相同 ID 的不同行将具有相同的性别和年龄值但不同的类别和子类别值):
ID product.category sub.category gender age
1 1 food chicken M young
2 1 kitchen napkin M young
3 1 food steak M young
4 2 electronic phone F mid
5 3 cloth shirt M old
6 3 kitchen bowl M old
7 4 alch beer F young
并且通过组合具有相同 ID 的不同行,我想按如下方式改革 table:
ID product.category1 sub.category1 product.category2 sub.category2 product.category3 sub.category3 gender age
1 1 food chicken kitchen napkin food steak M young
2 2 electronic phone null null null null F mid
3 3 cloth shirt kitchen bowl null null M old
4 4 alch beer null null null null F young
我如何在 R 中执行此操作?
#新数据集:text变量实际上是notes的文本列
text Category Subcategory variable1 variable2 variable3 variable4 date
aaaaa c1 s11 v1 N RETAIL Y 2014-01
aaaaa c2 s22 v1 N LEASE Y 2014-01
aaaaa c3 s31 v1 N LEASE Y 2014-01
bbbbb c1 s12 v2 N LEASE Y 2014-01
ccccc c2 s21 v1 N LEASE Y 2014-01
ddddd c2 s21 v1 N RETAIL Y 2014-01
ddddd c3 s31 v1 N LEASE Y 2014-01
eeeee c1 s11 v1 N RETAIL Y 2014-01
fffff c2 s21 v2 U RETAIL Y 2014-01
谢谢
我们使用包 reshape2
中的 melt
和 dcast
的组合。
library(dplyr)
library(reshape2)
m2 <- melt(df, c("ID", "gender", "age")) %>% group_by(ID, variable) %>%
mutate(variable2 = paste0(variable, seq_along(value)))
newdf <- dcast(m2[!names(m2) %in% "variable"], ...~variable2, value.var="value", fill="null")
我们首先通过产品类别和 sub-category 融合原始数据框。接下来使用 dplyr,我们按 id 列和产品列(现在默认称为 "variable")分组,并创建一个名为 variable2
的新列。这只是类别标题和 运行 观察计数的粘贴。
现在我们有了一个新列,我们可以通过它来展开数据。我们在新的 variable2 列上使用 dcast
去 "wide"。还有一个名为 fill
的参数,我们将其设置为 "null"
告诉 dcast 用什么来填充缺失值。
下面我们根据所需的输出对列重新排序。这个技巧即使很小也值得注意。创建一个交织序列很有趣。我们的输出按字母顺序排序("p1"、"p2"、"p3"、"s1"、"s2"、"s3")。我们想要一个将它们编织在一起的序列。挑战在于获得类似(1,4,2,5,3,6)的东西。所以我们使用:
c(rbind(1:3, 4:6))
[1] 1 4 2 5 3 6
很酷吧?我们利用了 rbind 在我们按行输入值时展开 column-wise 的事实。在我们的例子中,写入 1:3
无济于事,因为数据中可能有更多产品。但是我们知道有两个标题"product category"和"sub-subcategory"。我们将 variable2
的唯一值除以 2 并使用它。
n <- nrow(unique(m2[,"variable2"]))
newdf[c(1:3,(c(rbind(1:(n/2), (n/2+1):n))+3))]
# ID gender age product.category1 sub.category1 product.category2
# 1 1 M young food chicken kitchen
# 2 2 F mid electronic phone null
# 3 3 M old cloth shirt kitchen
# 4 4 F young alch beer null
# sub.category2 product.category3 sub.category3
# 1 napkin food steak
# 2 null null null
# 3 bowl null null
# 4 null null null
更新
使用提供的新数据集,相同的代码结构适用于新的列名。
m2 <- melt(df, measure.vars=c("Category", "Subcategory")) %>% group_by(text, variable) %>%
mutate(variable2 = paste0(variable, seq_along(value)))
newdf <- dcast(m2[!names(m2) %in% "variable"], ... ~ variable2, value.var="value", fill="null")
n <- nrow(unique(m2[,"variable2"]))
newdf2 <- newdf[c(1:5, c(rbind(1:(n/2), (n/2+1):n))+5)]
newdf2
# text variable1 variable3 variable4 date Category1 Subcategory1 Category2
# 1 aaaaa v1 LEASE Y 2014-01 null null c2
# 2 aaaaa v1 RETAIL Y 2014-01 c1 s11 null
# 3 bbbbb v2 LEASE Y 2014-01 c1 s12 null
# 4 ccccc v1 LEASE Y 2014-01 c2 s21 null
# 5 ddddd v1 LEASE Y 2014-01 null null c3
# 6 ddddd v1 RETAIL Y 2014-01 c2 s21 null
# 7 eeeee v1 RETAIL Y 2014-01 c1 s11 null
# 8 fffff v2 RETAIL Y 2014-01 c2 s21 null
# Subcategory2 Category3 Subcategory3
# 1 s22 c3 s31
# 2 null null null
# 3 null null null
# 4 null null null
# 5 s31 null null
# 6 null null null
# 7 null null null
# 8 null null null
data.table dcast 您可以使用 reshape2 或 data.table 包中的 dcast
:
library(data.table)
setDT(DT)
DT[, obsno := 1:.N, by=ID]
res <- dcast(DT, ID+gender+age~obsno, value.var=c("product.category","sub.category"))
这给出
ID gender age product.category_1 product.category_2 product.category_3 sub.category_1 sub.category_2 sub.category_3
1: 1 M young food kitchen food chicken napkin steak
2: 2 F mid electronic NA NA phone NA NA
3: 3 M old cloth kitchen NA shirt bowl NA
4: 4 F young alch NA NA beer NA NA
要按您想要的顺序查看列,您可以执行类似
的操作res[, c(1:3,4,7,5,8,6,9), with=FALSE]
类似的方法可能适用于 tidyr 包(尽管它不会被称为 "dcast")。
我建议坚持使用长格式(您最初使用的格式)进行任何分析。您正在寻找的这种宽格式对于浏览数据以外的任何事情都非常麻烦。
第二个例子对于OP的第二个例子,我会做
DT2[, obsno := 1:.N, by=text]
dcast(DT2, ...~obsno, value.var=c("Category", "Subcategory"))
从@PierreLafortune 的回答中复制 ...~
技巧。结果是
text variable1 variable2 variable3 variable4 date Category_1 Category_2 Category_3 Subcategory_1 Subcategory_2 Subcategory_3
1: aaaaa v1 N LEASE Y 2014-01 NA c2 c3 NA s22 s31
2: aaaaa v1 N RETAIL Y 2014-01 c1 NA NA s11 NA NA
3: bbbbb v2 N LEASE Y 2014-01 c1 NA NA s12 NA NA
4: ccccc v1 N LEASE Y 2014-01 c2 NA NA s21 NA NA
5: ddddd v1 N LEASE Y 2014-01 NA c3 NA NA s31 NA
6: ddddd v1 N RETAIL Y 2014-01 c2 NA NA s21 NA NA
7: eeeee v1 N RETAIL Y 2014-01 c1 NA NA s11 NA NA
8: fffff v2 U RETAIL Y 2014-01 c2 NA NA s21 NA NA
dplyr
& tidyr
的替代方案:
newdf <- df %>% gather(variable, value, product.category, sub.category) %>%
group_by(ID, variable) %>%
mutate(variable2 = paste0(variable, seq_along(value))) %>%
ungroup() %>%
select(-variable) %>%
spread(variable2 , value)
给出:
> newdf
Source: local data frame [4 x 9]
ID gender age product.category1 product.category2 product.category3 sub.category1 sub.category2 sub.category3
(int) (fctr) (fctr) (chr) (chr) (chr) (chr) (chr) (chr)
1 1 M young food kitchen food chicken napkin steak
2 2 F mid electronic NA NA phone NA NA
3 3 M old cloth kitchen NA shirt bowl NA
4 4 F young alch NA NA beer NA NA
可以对第二个示例数据集执行相同的操作:
newdat <- dat %>% gather(variable, value, Category, Subcategory) %>%
group_by(text, variable) %>%
mutate(var2 = paste0(variable, seq_along(value))) %>%
ungroup() %>%
select(-variable) %>%
spread(var2 , value)
给出:
> newdat
Source: local data frame [8 x 12]
text variable1 variable2 variable3 variable4 date Category1 Category2 Category3 Subcategory1 Subcategory2 Subcategory3
(fctr) (fctr) (fctr) (fctr) (fctr) (fctr) (chr) (chr) (chr) (chr) (chr) (chr)
1 aaaaa v1 N LEASE Y 2014-01 NA c2 c3 NA s22 s31
2 aaaaa v1 N RETAIL Y 2014-01 c1 NA NA s11 NA NA
3 bbbbb v2 N LEASE Y 2014-01 c1 NA NA s12 NA NA
4 ccccc v1 N LEASE Y 2014-01 c2 NA NA s21 NA NA
5 ddddd v1 N LEASE Y 2014-01 NA c3 NA NA s31 NA
6 ddddd v1 N RETAIL Y 2014-01 c2 NA NA s21 NA NA
7 eeeee v1 N RETAIL Y 2014-01 c1 NA NA s11 NA NA
8 fffff v2 U RETAIL Y 2014-01 c2 NA NA s21 NA NA