我有一个如下所示的数据框:
Name School Weight Days
Antoine Bach 0.03 5
Antoine Ken 0.02 7
Barbara Franklin 0.04 3
我想获得如下输出:
Name School 1 2 3 4 5 6 7
Antoine Bach 0.03 0.03 0.03 0.03 0.03 NA NA
Antoine Ken 0.02 0.02 0.02 0.02 0.02 0.02 0.02
Barbara Franklin 0.04 0.04 0.04 NA NA NA NA
可重现的样本数据:
df <- tribble(
~Name, ~School, ~Weight, ~Days,
"Antoine", "Bach", 0.03, 5,
"Antoine", "Ken", 0.02, 7,
"Barbara", "Franklin", 0.04, 3
)
答案 0 :(得分:4)
使用 data.table,您可以通过rep
为每行读取 Weight
值 Days
次,然后dcast
转换为宽格式来创建长版本以新变量的rowid
作为列。
library(data.table)
setDT(df)
dcast(df[, .(rep(Weight, Days)), .(Name, School)],
Name + School ~ rowid(V1))
# Name School 1 2 3 4 5 6 7
# 1: Antoine Bach 0.03 0.03 0.03 0.03 0.03 NA NA
# 2: Antoine Ken 0.02 0.02 0.02 0.02 0.02 0.02 0.02
# 3: Barbara Franklin 0.04 0.04 0.04 NA NA NA NA
您也可以rep
Weight
Days
的数量,然后重复 NA
次以完成该行。
max_days <- max(df$Days)
df[, as.list(rep(c(Weight, NA), c(Days, max_days - Days))),
.(Name, School)]
# Name School V1 V2 V3 V4 V5 V6 V7
# 1: Antoine Bach 0.03 0.03 0.03 0.03 0.03 NA NA
# 2: Antoine Ken 0.02 0.02 0.02 0.02 0.02 0.02 0.02
# 3: Barbara Franklin 0.04 0.04 0.04 NA NA NA NA
答案 1 :(得分:3)
您可以使用 pmap_dfr
跨行应用函数,然后将结果列表行绑定到 tibble 对象中。该函数将参数与列名匹配,其余的行值将在省略号 ...
中捕获。
library(purrr)
library(dplyr)
pmap_dfr(df, function(Weight, Days, ...) c(..., setNames(rep(Weight, Days), 1:Days))) %>%
mutate(across(3:last_col(), ~ as.numeric(.)))
因为向量在 R 中是原子的,所以 c()
会将行中的所有内容强制为字符。因此 mutate 将新创建的列转换回数字。
setNames
用于命名新创建的列,需要按行绑定。
输出
Name School `1` `2` `3` `4` `5` `6` `7`
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Antoine Bach 0.03 0.03 0.03 0.03 0.03 NA NA
2 Antoine Ken 0.02 0.02 0.02 0.02 0.02 0.02 0.02
3 Barbara Franklin 0.04 0.04 0.04 NA NA NA NA
注意:pmap_dfr
来自 purrr
包,mutate
、across
和 last_col
均来自 dplyr
。>
工作原理
当您以上述方式使用 pmap
时,命名函数参数将与具有相同名称的列匹配。因此 Weights
和 Days
作为函数参数与每一行中同名的列匹配。
...
收集仍然传递给函数但在函数中未使用(按名称)的剩余列。本质上,省略号在您的情况下收集 Name
和 School
。
由于 Name
和 School
已经有了名称,因此它们首先被传递给 c()
以保持您的列顺序。此外,我们组合其他值并给它们命名。单行的输出是这样的:
Name School 1 2 3 4 5 6
"Antoine" "Bach" "0.03" "0.03" "0.03" "0.03" "0.03" NA
7
NA
pmap
的输出是一个列表。 _dfr
是将这些列表元素行绑定(因此 r
)到数据框/tibble(因此 df
)的特定函数。
答案 2 :(得分:2)
您可以使用以下代码获得所需的输出:
library(dplyr)
library(tidyr)
df %>%
select(Weight, Days) %>%
uncount(Days, .remove = FALSE) %>%
group_by(Days) %>%
mutate(id = row_number()) %>%
pivot_wider(Days, names_from = id, values_from = Weight) %>%
right_join(df, by = "Days") %>%
relocate(Name, School) %>%
ungroup() %>%
select(-c(Weight, Days))
# A tibble: 3 x 9
Name School `1` `2` `3` `4` `5` `6` `7`
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Antoine Bach 0.03 0.03 0.03 0.03 0.03 NA NA
2 Antoine Ken 0.02 0.02 0.02 0.02 0.02 0.02 0.02
3 Barbara Franklin 0.04 0.04 0.04 NA NA NA NA
数据:
df <- tribble(
~Name, ~School, ~Weight, ~Days,
"Antoine", "Bach", 0.03, 5,
"Antoine", "Ken", 0.02, 7,
"Barbara", "Franklin", 0.04, 3
)
已更新
由于我们亲爱的朋友正确地建议使用 pmap
包中的 map
和 purrr
,这是另一种变体,想知道会很酷:
library(purrr)
df %>%
mutate(map2_dfr(Weight, Days, ~ set_names(rep(.x, .y), 1:.y))) %>%
select(-c(Weight, Days))
# A tibble: 3 x 9
Name School `1` `2` `3` `4` `5` `6` `7`
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Antoine Bach 0.03 0.03 0.03 0.03 0.03 NA NA
2 Antoine Ken 0.02 0.02 0.02 0.02 0.02 0.02 0.02
3 Barbara Franklin 0.04 0.04 0.04 NA NA NA NA
答案 3 :(得分:2)
一个 tidyverse
解决方案。
tidyr::nest
两列。结果列将是一个名为 d
的列表列,表示虚拟。d
函数将 weights
变异为 days
的向量,最多 rep
次。此迭代使用 purrr::map
完成。 注意:此阶段不需要 map_dbl
,因为它将在下一步中取消嵌套。setNames
中,以便将 d
变异为命名列表(名称如预期)。对于名称,使用 seq
函数。tidyr::unnest_wider
列d
插入到名称已在前面步骤中保存在列表中的列中library(dplyr)
library(tidyr)
library(purrr)
df %>% nest(d = c(Weight, Days)) %>%
mutate(d = map(d, ~setNames( rep(.x$Weight, .x$Days), seq(1, .x$Days, 1)))) %>%
unnest_wider(d)
# A tibble: 3 x 9
Name School `1` `2` `3` `4` `5` `6` `7`
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Antoine Bach 0.03 0.03 0.03 0.03 0.03 NA NA
2 Antoine Ken 0.02 0.02 0.02 0.02 0.02 0.02 0.02
3 Barbara Franklin 0.04 0.04 0.04 NA NA NA NA
答案 4 :(得分:1)
我喜欢 tidyr::uncount
为每行制作 x
份副本。我们可以旋转更长的时间,不计算,然后再次旋转更宽。
library(tidyr)
my_data %>%
pivot_longer(Weight) %>%
uncount(Days, .id = "colnum") %>%
dplyr::select(-name) %>%
pivot_wider(names_from = colnum, values_from = value)
# A tibble: 3 x 9
Name School `1` `2` `3` `4` `5` `6` `7`
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Antoine Bach 0.03 0.03 0.03 0.03 0.03 NA NA
2 Antoine Ken 0.02 0.02 0.02 0.02 0.02 0.02 0.02
3 Barbara Franklin 0.04 0.04 0.04 NA NA NA NA