在R中顺序计算列的中位数并将值存储在数据框中
Posted
技术标签:
【中文标题】在R中顺序计算列的中位数并将值存储在数据框中【英文标题】:Calculating median of a column sequentially in R and storing values in dataframe 【发布时间】:2022-01-09 21:02:48 【问题描述】:我在计算列中值的中位数时遇到了问题。 我在一列中有数百个值,但我想一次计算一个序列中五个值的中值,并将中值存储在 R 中的单独数据框中,并类似地继续直到可用数据值结束。
问题是 #VALUE! 有一些值,并且在计算中位数时,如果有这样的值,即 #VALUE! 并且值少于 5 个要取中位数,那么程序应该只取任何数量的可用值的中位数。 类似地,对于最后一个中值,如果可取中值的值少于 5 个,则应使用可用值的个数计算中值。
可从此处下载包含一列示例数据的 .csv 文件的链接。
LINK to FILE
如果有人可以帮助我,我将非常感激。
谢谢
【问题讨论】:
#VALUE!
错误的存在不是 R 的事情,我相信那只是 Excel 的事情。如果您看到了,您是否使用了一些 R/Excel 集成?无论如何,“一个序列中的五个值”听起来像是一个滚动计算,使用zoo::rollmedian
(通常为zoo::rollapply
)或slider
-package 等效函数之一(我不太熟悉)很容易完成。旁注:许多人不喜欢点击外部链接,链接会过时,在问题本身中有示例数据会很有帮助。见***.com/q/5963269。谢谢!
【参考方案1】:
你可以试试这个:
-
按 5 行序列分组
将
#VALUE!
替换为NA
转换为数字
用中位数总结
Speed %>%
group_by(group5 = rep(row_number(), each=5, length.out = n())) %>%
mutate(speed = ifelse(speed== "#VALUE!", NA, speed)) %>%
type.convert(as.is = TRUE) %>%
summarise(median = median(speed, na.rm = TRUE))
group5 median
<int> <dbl>
1 1 1.32
2 2 -4.97
3 3 -13.1
4 4 -14.3
5 5 6.89
6 6 -2.97
7 7 -11.6
8 8 -16.0
9 9 -18.6
10 10 -19.9
# ... with 72 more rows
【讨论】:
谢谢。输出正是我想要的,但是当我尝试运行代码时,它给了我以下错误: group_by(., group = rep(row_number(), each = 5, length.out = n())) 中的错误:找不到对象“速度”如何纠正? TarJae 在他们的控制台中将变量命名为Speed
。您在控制台中将其命名为什么?
Speed
是数据框的名称。 speed
是列名!
啊,明白了。对不起,我犯了一个愚蠢的错误。非常感谢【参考方案2】:
更新“翻滚窗口”(顶部,此处)与“滚动窗口”(下方,留作后代/参考)。仍在使用滚动窗口讨论顶部的dat
。
关于#VALUE!
(远在下面)的讨论可能仍然相关,我将在此处包含代码。
基础 R
dat$speed <- suppressWarnings(as.numeric(dat$speed))
aggregate(dat$speed, list(grp = (seq_len(nrow(dat)) - 1) %/% 5), FUN = median, na.rm = TRUE)
# grp x
# 1 0 3.4245
# 2 1 -4.9730
dplyr
library(dplyr)
dat %>%
mutate(speed = suppressWarnings(as.numeric(speed))) %>%
group_by(grp = (seq_len(n()) - 1) %/% 5) %>%
summarize(med5 = median(speed, na.rm = TRUE))
# # A tibble: 2 x 2
# grp med5
# <dbl> <dbl>
# 1 0 3.42
# 2 1 -4.97
数据表
library(data.table)
as.data.table(dat)[, speed := suppressWarnings(as.numeric(speed))
][, .(med5 = median(speed, na.rm = TRUE)), by = .(grp = (seq_len(nrow(dat)) - 1) %/% 5)][]
# grp med5
# <num> <num>
# 1: 0 3.4245
# 2: 1 -4.9730
(下面是滚动窗口,除了dat
数据的定义之外不再相关。)
我从该单列框架中复制了前 10 行,然后得到
dat <- structure(list(speed = c(0, 5.534, 1.315, 7.6865, -0.479, -0.4605, -4.311, -4.973, -7.69, -11.669)), row.names = c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"), class = "data.frame")
有了这个,基本的操作是这样的:
newvec <- zoo::rollmedian(dat$speed, 5)
newvec
# [1] 1.3150 1.3150 -0.4605 -0.4790 -4.3110 -4.9730
请注意,这会创建 nrow(dat) - (k - 1)
(20) 值,其中 k=5
(您的窗口)。一般来说,滚动操作倾向于减少,但如果需要,我们可以选择改变它。例如,我们可以保持它相同的长度,并用NA
填充两端;为此,我们可以将窗口“对齐”左、中或右:
zoo::rollmedian(dat$speed, 5, fill = NA, align = "left")
# [1] 1.3150 1.3150 -0.4605 -0.4790 -4.3110 -4.9730 NA NA NA NA
zoo::rollmedian(dat$speed, 5, fill = NA, align = "center")
# [1] NA NA 1.3150 1.3150 -0.4605 -0.4790 -4.3110 -4.9730 NA NA
zoo::rollmedian(dat$speed, 5, fill = NA, align = "right")
# [1] NA NA NA NA 1.3150 1.3150 -0.4605 -0.4790 -4.3110 -4.9730
让我来展示对齐方式如何适合这里。使用align="center"
(默认),我们看到:
dat$speed
# [1] 0.0000 5.5340 1.3150 7.6865 -0.4790 -0.4605 -4.3110 -4.9730 -7.6900 -11.6690
### `----------------------------------------'
### take the median of these values,
### and then assign that single value here:
### /
### ,---------------'
### /
# [1] NA NA 1.3150 1.3150 -0.4605 -0.4790 -4.3110 -4.9730 NA NA
dat$speed[1:5]
# [1] 0.0000 5.5340 1.3150 7.6865 -0.4790
median(dat$speed[1:5])
# [1] 1.315
对于下一个值,
# [1] 0.0000 5.5340 1.3150 7.6865 -0.4790 -0.4605 -4.3110 -4.9730 -7.6900 -11.6690
### `----------------------------------------'
### take the median of these values,
### and then assign that single value here:
### /
### ,---------------'
### /
# [1] NA NA 1.3150 1.3150 -0.4605 -0.4790 -4.3110 -4.9730 NA NA
dat$speed[2:6]
# [1] 5.5340 1.3150 7.6865 -0.4790 -0.4605
median(dat$speed[2:6])
# [1] 1.315
所以我们可以很容易地将它分配给带有data.frame(rollmed = newvec)
的新框架,无论是否有填充。如果您想将其分配回原始框架,可以这样做:
dat$rollmed <- zoo::rollmedian(dat$speed, 5, fill = NA, align = "center")
dat
# speed rollmed
# 1 0.0000 NA
# 2 5.5340 NA
# 3 1.3150 1.3150
# 4 7.6865 1.3150
# 5 -0.4790 -0.4605
# 6 -0.4605 -0.4790
# 7 -4.3110 -4.3110
# 8 -4.9730 -4.9730
# 9 -7.6900 NA
# 10 -11.6690 NA
至于您的#VALUE!
,它可能表现为character
列而不是numeric
,在这种情况下,您有一个额外的步骤之前以上所有。
我会将其中一个值更改为该错误:
dat$speed[5] <- "#VALUE!"
dat
# speed
# 1 0
# 2 5.534
# 3 1.315
# 4 7.6865
# 5 #VALUE!
# 6 -0.4605
# 7 -4.311
# 8 -4.973
# 9 -7.69
# 10 -11.669
str(dat)
# 'data.frame': 10 obs. of 1 variable:
# $ speed: chr "0" "5.534" "1.315" "7.6865" ...
(看到了吗?chr
。)
从这里,我们可以简单地将所有转换为数字,忽略我们得到的警告:
dat$speed <- suppressWarnings(as.numeric(dat$speed))
dat
# speed
# 1 0.0000
# 2 5.5340
# 3 1.3150
# 4 7.6865
# 5 NA
# 6 -0.4605
# 7 -4.3110
# 8 -4.9730
# 9 -7.6900
# 10 -11.6690
str(dat)
# 'data.frame': 10 obs. of 1 variable:
# $ speed: num 0 5.53 1.31 7.69 NA ...
从这里,我们可以再次做滚动中位数。请注意,我们现在的NA
略有变化:
dat$rollmed <- zoo::rollmedian(dat$speed, 5, fill = NA, align = "center")
dat$rollmed2 <- zoo::rollmedian(dat$speed, 5, fill = NA, align = "center", na.rm = TRUE)
dat
# speed rollmed rollmed2
# 1 0.0000 NA NA
# 2 5.5340 NA NA
# 3 1.3150 NA 3.42450
# 4 7.6865 NA 3.42450
# 5 NA NA 0.42725
# 6 -0.4605 NA -2.38575
# 7 -4.3110 NA -4.64200
# 8 -4.9730 -4.973 -4.97300
# 9 -7.6900 NA NA
# 10 -11.6690 NA NA
默认值(我们之前所做的)将为前一个 #VALUE!
+/- 4 行 (k-1
) 内的每一行返回一个 NA
中值;如果您愿意,我们可以添加na.rm=TRUE
;这不是滚动窗口的事情,这是一个一般统计问题,“空值是个问题”。
【讨论】:
谢谢@r2evans 的回答。实际上,我不想像您在基本操作开始时得到的答案那样进行滚动平均。相反,我想做 5 行的平均值,然后是接下来 5 行的平均值。我怎样才能修改代码给我呢? 是的,我误解了这一点。你需要澄清你的问题。顺便说一句,我经常发现翻滚窗口(这就是所谓的)通常与某些东西“对齐”,例如 5Hz 数据上的 1Hz,或工作日数据上的每周等。偶尔在没有“时间”或其他变量的情况下出现翻滚窗口固然有用,但您的数据中是否有任何“时间”成分? 不,我的数据没有“时间”。不过还是谢谢你。在回答主要问题时,您帮助我理解了许多其他事情。非常感谢。以上是关于在R中顺序计算列的中位数并将值存储在数据框中的主要内容,如果未能解决你的问题,请参考以下文章
R语言vtreat包自动处理dataframe的缺失值使用分组的中位数来标准化数据列中每个数据的值(和中位数表连接并基于中位数进行数据标化)计算数据列的中位数或者均值并进行数据标准化