添加聚合计数作为额外的数据框行
Adding aggregated counts as extra dataframe rows
我有一个包含英文字母及其出现频率的数据框。现在如果能知道元音和辅音的出现频率以及出现的总次数就好了——因为我想绘制所有这些信息,所以我需要将它们放在一个数据框中。
所以我经常遇到这样的情况:
df <- data.frame(letter = letters, freq = sample(1:100, length(letters)))
df_vowels <- data.frame(letter = "vowels", freq = sum(df[df$letter %in% c("a", "e", "i", "o", "u"), ]$freq))
df_consonants <- data.frame(letter = "consonants", freq = sum(df[!df$letter %in% c("a", "e", "i", "o", "u"), ]$freq))
df_totals <- data.frame(letter = "totals", freq = sum(df$freq))
df <- rbind(df, df_vowels, df_consonants, df_totals)
我这样做的方式是否正确,或者是否有更优雅的解决方案?
看来我的描述非常混乱:
基本上,我想向数据框中添加新类别(行)。在这个非常简单的示例中,它只是汇总数据。
(对于时间序列图,我使用的是聚合函数。)
编辑:这是对您问题的第三个版本的非常优雅的回答:
df <- data.frame(letter = letters, freq = sample(1:100, length(letters)),
stringsAsFactors=F)
df = df %>% group_by(letter) %>% summarize(freq = sum(freq))
df.tots = df %>% group_by(is_vowel = letter %in% c('a','e','i','o','u')) %>%
summarize(freq=sum(freq))
# Now we just rbind your three summary rows onto the df, then pipe it into your ggplot
df %>%
rbind(c('vowels', df.tots[df.tots$is_vowel==T,]$freq)) %>%
rbind(c('consonants', df.tots[df.tots$is_vowel==F,]$freq)) %>%
rbind(c('total', sum(df.tots$freq))) %>%
ggplot( ... your_ggplot_command_goes_here ...)
#qplot(data=..., x=letter, y=freq, stat='identity', geom='histogram')
# To keep your x-axis in order, i.e. our summary rows at bottom,
# you have to explicitly set order of factor levels:
# df$letter = factor(df$letter, levels=df$letter)
备注:
- 我们需要
data.frame(... stringsAsFactors=F)
以便稍后可以追加
'vowels'、'consonants'、'total' 行,因为这些不会发生
在 'letters' 的因子水平
- 请注意 dplyr group_by(is_vowel = ...) 允许我们同时插入一个新列 (
mutate
),然后拆分该表达式 (group_by
), 全部在一条紧凑的生产线中。整洁的。从来不知道可以做到这一点。
- 你应该能够让
bind_rows
最后工作,我做不到。
编辑:第二个版本。你说你想做一个聚合,所以我们认为每个字母在 df 中都有 >1 条记录。您似乎只是将 df 拆分为元音和辅音,然后再次合并,所以我认为除了 is_vowel
之外不需要新的列。一种方法是使用 dplyr:
require(dplyr)
# I don't see why you don't just overwrite df here with df2, the df of totals...
df2 = df %>% group_by(letter) %>% summarize(freq = sum(freq))
letter freq
1 a 150
2 b 33
3 c 54
4 d 258
5 e 285
6 f 300
7 g 198
8 h 27
9 i 36
10 j 189
.. ... ...
# Now add a logical column, so we can split on it when aggregating
# df or df2 ....
df$is_vowel = df$letter %in% c('a','e','i','o','u')
# Then your total vowels are:
df %>% filter(is_vowel==T) %>% summarize(freq = sum(freq))
freq
312
# ... and total consonants ...
df %>% filter(is_vowel==F) %>% summarize(freq = sum(freq))
freq
1011
这是另一种方法,如果你想避免 dplyr,可以使用单行代码:
split(df, df$letter %in% c("a", "e", "i", "o", "u") )
顺便说一句,你可以通过从所有字母中减去元音来更容易地形成辅音列表(/集):
setdiff(letters, c("a", "e", "i", "o", "u"))
# "b" "c" "d" "f" "g" "h" "j" "k" "l" "m" "n" "p" "q" "r" "s" "t" "v" "w" "x" "y" "z"
你可以试试
v2 <- with(df, tapply(freq, c('consonants', 'vowels')[letter %in%
v1+1L], FUN=sum))
df1 <- rbind(df, data.frame(letter=c(names(v2),"Total"),
freq=c(v2, sum(v2)), stringsAsFactors=FALSE))
library(ggplot2)
ggplot(df1, aes(x=letter, y=freq)) +
geom_bar(stat='identity')
数据
set.seed(24)
df <- data.frame(letter= sample(letters,200, replace=TRUE),
freq = sample(1:100, 200, replace=TRUE), stringsAsFactors=FALSE)
v1 <- c("a", "e", "i", "o", "u")
我有一个包含英文字母及其出现频率的数据框。现在如果能知道元音和辅音的出现频率以及出现的总次数就好了——因为我想绘制所有这些信息,所以我需要将它们放在一个数据框中。
所以我经常遇到这样的情况:
df <- data.frame(letter = letters, freq = sample(1:100, length(letters)))
df_vowels <- data.frame(letter = "vowels", freq = sum(df[df$letter %in% c("a", "e", "i", "o", "u"), ]$freq))
df_consonants <- data.frame(letter = "consonants", freq = sum(df[!df$letter %in% c("a", "e", "i", "o", "u"), ]$freq))
df_totals <- data.frame(letter = "totals", freq = sum(df$freq))
df <- rbind(df, df_vowels, df_consonants, df_totals)
我这样做的方式是否正确,或者是否有更优雅的解决方案?
看来我的描述非常混乱:
基本上,我想向数据框中添加新类别(行)。在这个非常简单的示例中,它只是汇总数据。
(对于时间序列图,我使用的是聚合函数。)
编辑:这是对您问题的第三个版本的非常优雅的回答:
df <- data.frame(letter = letters, freq = sample(1:100, length(letters)),
stringsAsFactors=F)
df = df %>% group_by(letter) %>% summarize(freq = sum(freq))
df.tots = df %>% group_by(is_vowel = letter %in% c('a','e','i','o','u')) %>%
summarize(freq=sum(freq))
# Now we just rbind your three summary rows onto the df, then pipe it into your ggplot
df %>%
rbind(c('vowels', df.tots[df.tots$is_vowel==T,]$freq)) %>%
rbind(c('consonants', df.tots[df.tots$is_vowel==F,]$freq)) %>%
rbind(c('total', sum(df.tots$freq))) %>%
ggplot( ... your_ggplot_command_goes_here ...)
#qplot(data=..., x=letter, y=freq, stat='identity', geom='histogram')
# To keep your x-axis in order, i.e. our summary rows at bottom,
# you have to explicitly set order of factor levels:
# df$letter = factor(df$letter, levels=df$letter)
备注:
- 我们需要
data.frame(... stringsAsFactors=F)
以便稍后可以追加 'vowels'、'consonants'、'total' 行,因为这些不会发生 在 'letters' 的因子水平
- 请注意 dplyr group_by(is_vowel = ...) 允许我们同时插入一个新列 (
mutate
),然后拆分该表达式 (group_by
), 全部在一条紧凑的生产线中。整洁的。从来不知道可以做到这一点。 - 你应该能够让
bind_rows
最后工作,我做不到。
编辑:第二个版本。你说你想做一个聚合,所以我们认为每个字母在 df 中都有 >1 条记录。您似乎只是将 df 拆分为元音和辅音,然后再次合并,所以我认为除了 is_vowel
之外不需要新的列。一种方法是使用 dplyr:
require(dplyr)
# I don't see why you don't just overwrite df here with df2, the df of totals...
df2 = df %>% group_by(letter) %>% summarize(freq = sum(freq))
letter freq
1 a 150
2 b 33
3 c 54
4 d 258
5 e 285
6 f 300
7 g 198
8 h 27
9 i 36
10 j 189
.. ... ...
# Now add a logical column, so we can split on it when aggregating
# df or df2 ....
df$is_vowel = df$letter %in% c('a','e','i','o','u')
# Then your total vowels are:
df %>% filter(is_vowel==T) %>% summarize(freq = sum(freq))
freq
312
# ... and total consonants ...
df %>% filter(is_vowel==F) %>% summarize(freq = sum(freq))
freq
1011
这是另一种方法,如果你想避免 dplyr,可以使用单行代码:
split(df, df$letter %in% c("a", "e", "i", "o", "u") )
顺便说一句,你可以通过从所有字母中减去元音来更容易地形成辅音列表(/集):
setdiff(letters, c("a", "e", "i", "o", "u"))
# "b" "c" "d" "f" "g" "h" "j" "k" "l" "m" "n" "p" "q" "r" "s" "t" "v" "w" "x" "y" "z"
你可以试试
v2 <- with(df, tapply(freq, c('consonants', 'vowels')[letter %in%
v1+1L], FUN=sum))
df1 <- rbind(df, data.frame(letter=c(names(v2),"Total"),
freq=c(v2, sum(v2)), stringsAsFactors=FALSE))
library(ggplot2)
ggplot(df1, aes(x=letter, y=freq)) +
geom_bar(stat='identity')
数据
set.seed(24)
df <- data.frame(letter= sample(letters,200, replace=TRUE),
freq = sample(1:100, 200, replace=TRUE), stringsAsFactors=FALSE)
v1 <- c("a", "e", "i", "o", "u")