我有一个关于某些城镇居民按年龄划分的数据框。换句话说,我有这样的东西
Town Aged18 Aged19 Aged20 Aged21 Aged22 Aged23 Aged24 Aged25 Total
Rome 2 3 5 10 15 25 20 18 98
Milan 15 19 21 25 25 20 35 15 175
Turin 14 8 8 10 15 25 24 6 110
Florence 10 15 15 10 25 10 5 5 95
Bologna 15 10 25 10 15 10 25 20 130
我想创建一个新列,指示每个城镇的居民分布中位数在哪个“年龄”列中。换句话说,我想创建这样的东西
Town Aged18 Aged19 Aged20 Aged21 Aged22 Aged23 Aged24 Aged25 Total Median
Rome 2 3 5 10 15 25 20 18 98 23
Milan 15 19 21 25 25 20 35 15 175 22
Turin 14 8 8 10 15 25 24 6 110 22,5
Florence 10 15 15 10 25 10 5 5 95 21
Bologna 15 10 25 10 15 10 25 20 130 22
严格来说,我想创建一个循环,对每一列的内容求和,直到达到中位数为止。如果列的总数为奇数,则该位数对应于(n + 1)/ 2,而如果为偶数,它对应于(n / 2 +(n + 1)/ 2)/ 2。后者是我的数据帧中都灵的情况,我在22和23之间平均,因为它们分别对应于分别包含第55(110/2)和第56(111/2)个观测值的列。
因此,我希望新列不计算列值的中位数(这是我们可以通过rowMedian进行的操作),但是我希望它返回包含中位数观察值的列。
有人可以帮我吗?非常感谢,我希望这对尝试做类似事情的其他人也很有用。
答案 0 :(得分:2)
这里是使用tidyverse的一种方法。
首先,我将数据收集为长格式,这通常简化了组分析。我还将“年龄”列转换为数字。
然后,对于每个Town
,我计算该年龄段的累计人数。如果先前的累计计数少于一半,但我们将行标记为与中位数相对应,但当前的累计计数至少为一半。然后,针对特殊情况添加调整,其中Total为偶数,并且前一行累加等于一半。
library(tidyverse)
df_long <-
df %>%
gather(age, value, Aged18:Aged25) %>%
mutate(age = str_remove(age, "Aged") %>% as.numeric()) %>%
arrange(Town, age) %>% # Probably not necessary but doesn't hurt
group_by(Town) %>%
mutate(cuml_count = cumsum(value),
median = lag(cuml_count < Total / 2, default = FALSE) & cuml_count >= Total / 2,
median = if_else(Total %% 2 == 0 & lag(cuml_count, default = FALSE) == Total / 2,
TRUE, median))
这是视觉检查:
ggplot(df_long, aes(age, cuml_count/Total, color = median)) + geom_point() + facet_wrap(~Town)
最后,我们可以将原始表格与这些中位数结合起来
df2 <- df %>%
left_join(df_long,
filter(median) %>%
group_by(Town) %>%
summarize(median = mean(age)))
输出:
> df2
Town Aged18 Aged19 Aged20 Aged21 Aged22 Aged23 Aged24 Aged25 Total median
1 Rome 2 3 5 10 15 25 20 18 98 23.0
2 Milan 15 19 21 25 25 20 35 15 175 22.0
3 Turin 14 8 8 10 15 25 24 6 110 22.5
4 Florence 10 15 15 10 25 10 5 5 95 21.0
5 Bologna 15 10 25 10 15 10 25 20 130 22.0