是否可以创建以下输出(假设有很多ID和更多属性)? 在按ID中的ATT1然后按ATT2等计算总计的百分比后,我陷入了困境。不知道如何将行变成列标题并进行汇总。
输入文件(R中的df):
ID ATT1 ATT2 ATT3 ATT4 Value
1 a x d i 10
1 a y d j 10
1 a y d k 10
1 b y c k 10
1 b y c l 10
2 a x c k 20
…
我希望输出文件看起来像(ATT4_l被切断):
ID ATT1_a ATT1_b ATT2_x ATT2_y ATT3_d ATT3_c ATT4_i ATT4_j ATT4_k
1 0.6 0.4 0.2 0.8 0.6 0.4 0.2 0.2 0.4
...
我尝试使用dplyr
df %>% group_by(ID, ATT1) %>% mutate(proc = (Value/sum(Value) * 100))
但是我不确定一旦计算出所有的ATT就可以将它们分成几列并进行汇总,以便每个ID仅包含1行数据,该怎么办。
答案 0 :(得分:1)
您可以使用tidyverse
的两个主要功能来完成此操作:dplyr
用于计算,tidyr
用于重塑数据。重塑有些复杂,因此我将其分为几步。
library(dplyr)
library(tidyr)
...
如果您将数据从其原始的宽格式gather
转换为长格式,则将有一列ID,一列ATTx值,一列字母(不知道这些,因此我实际上将其称为letters
)和一列值。通过这种格式,您可以按ID,ATT和字母的组合对观察进行分组,然后可以按布局方式将ATT和字母粘贴在一起。
df %>%
gather(key = att, value = letter, -ID, -Value) %>%
head()
#> # A tibble: 6 x 4
#> ID Value att letter
#> <int> <int> <chr> <chr>
#> 1 1 10 ATT1 a
#> 2 1 10 ATT1 a
#> 3 1 10 ATT1 a
#> 4 1 10 ATT1 b
#> 5 1 10 ATT1 b
#> 6 2 20 ATT1 a
分组后,计算每个ID / ATT /字母组合的总值:
df %>%
gather(key = att, value = letter, -ID, -Value) %>%
group_by(ID, att, letter) %>%
summarise(group_val = sum(Value)) %>%
head()
#> # A tibble: 6 x 4
#> # Groups: ID, att [3]
#> ID att letter group_val
#> <int> <chr> <chr> <int>
#> 1 1 ATT1 a 30
#> 2 1 ATT1 b 20
#> 3 1 ATT2 x 10
#> 4 1 ATT2 y 40
#> 5 1 ATT3 c 20
#> 6 1 ATT3 d 30
使用mutate
,您可以计算每个观察值在其较大组中的份额。 mutate
删除了分组层次结构的一层,因此这是给定ID和ATT中每个字母的值份额。由于您不再需要总价值,只需共享它们的份额,然后删除该列,然后将ATT和字母与unite
放在一起即可。
df %>%
gather(key = att, value = letter, -ID, -Value) %>%
group_by(ID, att, letter) %>%
summarise(group_val = sum(Value)) %>%
mutate(share = group_val / sum(group_val)) %>%
select(-group_val) %>%
unite(group, att, letter, sep = "_") %>%
head()
#> # A tibble: 6 x 3
#> # Groups: ID [1]
#> ID group share
#> <int> <chr> <dbl>
#> 1 1 ATT1_a 0.6
#> 2 1 ATT1_b 0.4
#> 3 1 ATT2_x 0.2
#> 4 1 ATT2_y 0.8
#> 5 1 ATT3_c 0.4
#> 6 1 ATT3_d 0.6
现在,您拥有了所需的所有信息,只需将其转换为宽格式,即可将group
列中的值转换为单独的列。您可以使用spread
进行此操作:
df %>%
gather(key = att, value = letter, -ID, -Value) %>%
group_by(ID, att, letter) %>%
summarise(group_val = sum(Value)) %>%
mutate(share = group_val / sum(group_val)) %>%
select(-group_val) %>%
unite(group, att, letter, sep = "_") %>%
spread(key = group, value = share)
#> # A tibble: 2 x 11
#> # Groups: ID [2]
#> ID ATT1_a ATT1_b ATT2_x ATT2_y ATT3_c ATT3_d ATT4_i ATT4_j ATT4_k
#> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 0.6 0.4 0.2 0.8 0.4 0.6 0.2 0.2 0.4
#> 2 2 1 NA 1 NA 1 NA NA NA 1
#> # ... with 1 more variable: ATT4_l <dbl>
请注意,这里没有填写NA
,其中没有观察到ID / ATT /字母的组合。我假设您将拥有比发布的样本中更完整的数据。
由reprex package(v0.2.1)于2018-10-03创建
答案 1 :(得分:0)
我相信您正在寻找reshape2
包裹
library(reshape2)
df.new <- dcast(df,
formula = ID~ATT1,
value.var = "proc",
fun.aggregate = mean)
尽管这不能完全解决您的问题-我建议您先这样做以使数据整洁
df.tidy <- melt(df,
id.vars = c("ID","Value"),
variable.name = "ATT1_4",
value.name = "att.factor")
df.tidy <- df.tidy %>% group_by(ID, att.factor) %>% mutate(proc = (Value/sum(Value)*100))
df.new <- dcast(df.tidy,
formula = ID~att.factor,
value.var = "proc",
fun.aggregate = mean)
对于df.tidy中未表示的任何组合,将返回NaN。您可以使用fill
参数为它们分配一个值。