通过数据循环设置值>;或<;变量为R中的NA
我有一个包含整数、字符和数字的列的数据框。实际的数据集比下面给出的例子要大得多,但下面的是一个可以接受的小得多的模拟 我正在尝试循环遍历数据,并将任何大于通过数据循环设置值>;或<;变量为R中的NA,r,loops,na,R,Loops,Na,我有一个包含整数、字符和数字的列的数据框。实际的数据集比下面给出的例子要大得多,但下面的是一个可以接受的小得多的模拟 我正在尝试循环遍历数据,并将任何大于平均值+(3*标准偏差)且小于平均值-(3*标准偏差)的值更改为NA,仅在数字列中。如果一列包含整数或字符,循环应跳过它并继续到下一列。此外,大多数列已经包含一些NA值,并且将有许多值属于平均值+/-(3*sd)。这些价值观需要保持现状 此脚本的最终目标是在具有相同结构的未来数据集上使用它,虽然我对包的建议持开放态度,但如果可能,我希望使用循环
平均值+(3*标准偏差)
且小于平均值-(3*标准偏差)
的值更改为NA
,仅在数字列中。如果一列包含整数或字符,循环应跳过它并继续到下一列。此外,大多数列已经包含一些NA
值,并且将有许多值属于平均值+/-(3*sd)
。这些价值观需要保持现状
此脚本的最终目标是在具有相同结构的未来数据集上使用它,虽然我对包的建议持开放态度,但如果可能,我希望使用循环。然而,我远非R方面的专家,我很乐意接受任何人给我的建议
我已经为整个脚本制定了一个结构,但它在第一个next
语句之后停止
剧本:
data = data.frame(test_data)
for (i in colnames(data)){
if (class(data$i) == "numeric"){
m = mean(data$i, na.rm=TRUE)
sd = sd(data$i, na.rm=TRUE)
}
else
next
for (j in 1:nrow(data)){
if (data$i[j,] > (m + 3*sd)){
data$i[j,] <- NA
}
else if (data$i[j,] < (m - 3*sd)){
data$i[j,] <- NA
}
else
next
}
}
提前感谢您提供的任何帮助,我非常感谢 使用
dplyr
并使用scale()
将数值变量转换为z分数,这可以简化为:
library(dplyr)
test_data %>%
mutate_if(is.numeric, ~replace(.x, abs(scale(.x)) > 3, NA))
下面是一个解决方案,使用
purrr
包中的map\u df
函数,没有任何循环(抱歉:):
library(purrr)
Trait1 = c(1.1, 1.2, 1.35, 1.1, 1.2, NA, 1000, 1.5, 1.4, 1.6)
Trait2 = c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J")
Trait3 = c(125.1, 119.3, 118.4, NA, 1.1, 122.3, 123.4, 125.7, 121.5, 121.7)
test_data = data.frame(Trait1, Trait2, Trait3)
map_df(test_data,function(x) {
if(class(x) == "numeric"){
x[x <= (mean(x,na.rm = T) - 3*sd(x,na.rm = T)) | x>= (mean(x,na.rm = T) + 3*sd(x,na.rm = T))] = NA
}
return(x)
}
)
库(purrr)
Trait1=c(1.1,1.2,1.35,1.1,1.2,NA,1000,1.5,1.4,1.6)
Trait2=c(“A”、“B”、“c”、“D”、“E”、“F”、“G”、“H”、“I”、“J”)
Trait3=c(125.1193118.4,NA,1.1122.3123.4125.7121.5121.7)
测试数据=数据帧(Trait1、Trait2、Trait3)
地图测向(测试数据,功能(x){
如果(类别(x)=“数值”){
x[x=(平均值(x,na.rm=T)+3*sd(x,na.rm=T))]=na
}
返回(x)
}
)
如果您希望您的平均值
和sd
计算与NA
,请将NA.rm=T
更改为NA.rm=F
NB:请注意,在这种情况下,没有任何值大于或小于平均值减去或加上三个标准偏差。如果您认为列
Trait1
中的1000
是您的“可疑”点,请重新考虑,因为它不大于mean+3*sd
。我建议在不同的数据集上进行测试。对于这类事情,我一直在使用base::ifelse()
,并结合使用:
库(tidyverse)
图书馆(magrittr)
图书馆(tidylog)
测试数据%%
#当(且仅当)变量为数值时对其进行变异。。。
如果(是数字,
#…然后,如果它符合以下标准。。。
~z~如果还有其他人(
测试=.x>平均值(.x,na.rm=TRUE)+3*sd(.x,na.rm=TRUE)|
.x<平均值(.x,na.rm=TRUE)-3*sd(.x,na.rm=TRUE)|
.x%>%为.na,
#…替换为NA。如果没有。。。
是=不适用,
#……照原样走!
否=.x
))
注意上面的lambda函数,使用~
和.x
与Vitali上面所说的相呼应,该代码没有改变虚拟数据中的任何内容。为了确保绝对可靠,我加载了tidylog
,这是一个整洁的包,每当运行tidyverse函数时,它都会打印数据帧更改
编辑:感谢Vitali指出原始代码无法推广。我还去除了很多绒毛。如果需要使用循环,以下方法应该可以:
for (i in colnames(data)){
if (class(data[,i]) == "numeric"){
m = mean(data[,i], na.rm=TRUE)
sd = sd(data[,i], na.rm=TRUE)
for (j in 1:nrow(data)){
if (is.na(data[j,i])==F&(data[j,i] > (m + 3*sd)|data[j,i] < (m - 3*sd))){
data[j,i] <- NA
}
}
}
}
for(i在colnames(数据)中){
if(类(数据[,i])=“数值”){
m=平均值(数据[,i],na.rm=真)
sd=sd(数据[,i],na.rm=TRUE)
适用于(j/1:nrow(数据)){
如果(is.na(data[j,i])==F&(data[j,i]>(m+3*sd)| data[j,i]<(m-3*sd))){
数据[j,i]不幸的是,您的代码在将来是不可推广的(而且是未知的)数据集,因为对于未知数据,您不会知道Trait2
不是numeric
scale
,这是关键。@LateMail-您是对的,值得一提。已编辑的.Base R翻译为:nums 3]我非常喜欢这个解决方案!您的示例值中没有一个使用该标准替换据我所知。
library(tidyverse)
library(magrittr)
library(tidylog)
test_data %<>%
# Mutate any variable if (and only if) it's numeric...
mutate_if(is.numeric,
# ...then, if it meets the following criteria...
~ ifelse(
test = .x > mean(.x, na.rm = TRUE) + 3 * sd(.x, na.rm = TRUE) |
.x < mean(.x, na.rm = TRUE) - 3 * sd(.x, na.rm = TRUE) |
.x %>% is.na,
# ...replace with NA. If it doesn't...
yes = NA,
# ...leave as is!
no = .x
))
for (i in colnames(data)){
if (class(data[,i]) == "numeric"){
m = mean(data[,i], na.rm=TRUE)
sd = sd(data[,i], na.rm=TRUE)
for (j in 1:nrow(data)){
if (is.na(data[j,i])==F&(data[j,i] > (m + 3*sd)|data[j,i] < (m - 3*sd))){
data[j,i] <- NA
}
}
}
}