替换因子列中的 <NA>
Replace <NA> in a factor column
我想用有效值替换因子列中的 <NA>
值。但我找不到办法。此示例仅用于演示。原始数据来自我要处理的一个国外csv文件
df <- data.frame(a=sample(0:10, size=10, replace=TRUE),
b=sample(20:30, size=10, replace=TRUE))
df[df$a==0,'a'] <- NA
df$a <- as.factor(df$a)
可能看起来像这样
a b
1 1 29
2 2 23
3 3 23
4 3 22
5 4 28
6 <NA> 24
7 2 21
8 4 25
9 <NA> 29
10 3 24
现在我想用数字替换 <NA>
值。
df[is.na(df$a), 'a'] <- 88
In `[<-.factor`(`*tmp*`, iseq, value = c(88, 88)) :
invalid factor level, NA generated
我想我错过了关于因子的基本 R 概念。我是吗?
我不明白为什么它不起作用。我认为 invalid factor level
意味着 88
不是该因素的有效水平,对吗?所以我要告诉factor列还有一个层次?
因子变量的基本概念是它只能取特定值,即levels
。不在 levels
中的值无效。
你有两种可能:
如果您有遵循此概念的变量,请确保在创建它时定义所有级别,即使是那些没有对应值的级别。
或者将变量设为字符变量并使用它。
PS:这些问题往往是数据导入导致的。例如,您在那里显示的内容看起来应该是数字变量而不是因子变量。
1) addNA 如果 fac
是一个因子 addNA(fac)
是相同的因子,但添加了 NA 作为一个水平。参见 ?addNA
要强制 NA 级别为 88:
facna <- addNA(fac)
levels(facna) <- c(levels(fac), 88)
给予:
> facna
[1] 1 2 3 3 4 88 2 4 88 3
Levels: 1 2 3 4 88
1a) 可以这样写成一行:
`levels<-`(addNA(fac), c(levels(fac), 88))
2) factor 也可以使用 factor
的各种参数在一行中完成,如下所示:
factor(fac, levels = levels(addNA(fac)), labels = c(levels(fac), 88), exclude = NULL)
2a) 或等效的:
factor(fac, levels = c(levels(fac), NA), labels = c(levels(fac), 88), exclude = NULL)
3) ifelse 另一种做法是:
factor(ifelse(is.na(fac), 88, paste(fac)), levels = c(levels(fac), 88))
4) forcats forcats 包有一个函数:
library(forcats)
fct_explicit_na(fac, "88")
## [1] 1 2 3 3 4 88 2 4 88 3
## Levels: 1 2 3 4 88
注:我们使用了下面的输入fac
fac <- structure(c(1L, 2L, 3L, 3L, 4L, NA, 2L, 4L, NA, 3L), .Label = c("1",
"2", "3", "4"), class = "factor")
更新: 改进了 (1) 并添加了 (1a)。稍后添加 (4).
问题是 NA
不是那个因素的水平:
> levels(df$a)
[1] "2" "4" "5" "9" "10"
您无法立即更改它,但可以使用以下方法:
df$a <- as.numeric(as.character(df$a))
df[is.na(df$a),1] <- 88
df$a <- as.factor(df$a)
> df$a
[1] 9 88 3 9 5 9 88 8 3 9
Levels: 3 5 8 9 88
> levels(df$a)
[1] "3" "5" "8" "9" "88"
另一种方法是:
#check levels
levels(df$a)
#[1] "3" "4" "7" "9" "10"
#add new factor level. i.e 88 in our example
df$a = factor(df$a, levels=c(levels(df$a), 88))
#convert all NA's to 88
df$a[is.na(df$a)] = 88
#check levels again
levels(df$a)
#[1] "3" "4" "7" "9" "10" "88"
如果使用 factor
函数,我的方法会有点传统:
a <- factor(a,
exclude = NULL,
levels = c(levels(a), NA),
labels = c(levels(a), "None"))
您可以将 "None" 替换为您想要的适当替换(例如 0L)
我遇到了类似的问题,我想添加我认为最实用(也最简洁)的解决方案:
将列转换为 character
列,使用 mutate
和一个简单的 ifelse
语句将 NA
值更改为您想要的因子水平是(我选择了“None”),将其转换回 factor
列:
df %>% mutate(
a = as.character(a),
a = ifelse(is.na(a), "None", a),
a = as.factor(a)
)
干净且无痛,因为当 factor
列中出现 NA
值时,您实际上不必涉足这些值。你绕过了怪异并最终得到一个干净的 factor
变量。
此外,为了回应下面关于多列的评论:您可以将语句包装在一个函数中并使用 mutate_if
到 select 所有因子变量,或者,如果您知道关注的列,mutate_at
应用该函数:
replace_factor_na <- function(x){
x <- as.character(x)
x <- if_else(is.na(x), "None", x)
x <- as.factor(x)
}
df <- df %>%
mutate_if(is.factor, replace_factor_na)
我想用有效值替换因子列中的 <NA>
值。但我找不到办法。此示例仅用于演示。原始数据来自我要处理的一个国外csv文件
df <- data.frame(a=sample(0:10, size=10, replace=TRUE),
b=sample(20:30, size=10, replace=TRUE))
df[df$a==0,'a'] <- NA
df$a <- as.factor(df$a)
可能看起来像这样
a b
1 1 29
2 2 23
3 3 23
4 3 22
5 4 28
6 <NA> 24
7 2 21
8 4 25
9 <NA> 29
10 3 24
现在我想用数字替换 <NA>
值。
df[is.na(df$a), 'a'] <- 88
In `[<-.factor`(`*tmp*`, iseq, value = c(88, 88)) :
invalid factor level, NA generated
我想我错过了关于因子的基本 R 概念。我是吗?
我不明白为什么它不起作用。我认为 invalid factor level
意味着 88
不是该因素的有效水平,对吗?所以我要告诉factor列还有一个层次?
因子变量的基本概念是它只能取特定值,即levels
。不在 levels
中的值无效。
你有两种可能:
如果您有遵循此概念的变量,请确保在创建它时定义所有级别,即使是那些没有对应值的级别。
或者将变量设为字符变量并使用它。
PS:这些问题往往是数据导入导致的。例如,您在那里显示的内容看起来应该是数字变量而不是因子变量。
1) addNA 如果 fac
是一个因子 addNA(fac)
是相同的因子,但添加了 NA 作为一个水平。参见 ?addNA
要强制 NA 级别为 88:
facna <- addNA(fac)
levels(facna) <- c(levels(fac), 88)
给予:
> facna
[1] 1 2 3 3 4 88 2 4 88 3
Levels: 1 2 3 4 88
1a) 可以这样写成一行:
`levels<-`(addNA(fac), c(levels(fac), 88))
2) factor 也可以使用 factor
的各种参数在一行中完成,如下所示:
factor(fac, levels = levels(addNA(fac)), labels = c(levels(fac), 88), exclude = NULL)
2a) 或等效的:
factor(fac, levels = c(levels(fac), NA), labels = c(levels(fac), 88), exclude = NULL)
3) ifelse 另一种做法是:
factor(ifelse(is.na(fac), 88, paste(fac)), levels = c(levels(fac), 88))
4) forcats forcats 包有一个函数:
library(forcats)
fct_explicit_na(fac, "88")
## [1] 1 2 3 3 4 88 2 4 88 3
## Levels: 1 2 3 4 88
注:我们使用了下面的输入fac
fac <- structure(c(1L, 2L, 3L, 3L, 4L, NA, 2L, 4L, NA, 3L), .Label = c("1",
"2", "3", "4"), class = "factor")
更新: 改进了 (1) 并添加了 (1a)。稍后添加 (4).
问题是 NA
不是那个因素的水平:
> levels(df$a)
[1] "2" "4" "5" "9" "10"
您无法立即更改它,但可以使用以下方法:
df$a <- as.numeric(as.character(df$a))
df[is.na(df$a),1] <- 88
df$a <- as.factor(df$a)
> df$a
[1] 9 88 3 9 5 9 88 8 3 9
Levels: 3 5 8 9 88
> levels(df$a)
[1] "3" "5" "8" "9" "88"
另一种方法是:
#check levels
levels(df$a)
#[1] "3" "4" "7" "9" "10"
#add new factor level. i.e 88 in our example
df$a = factor(df$a, levels=c(levels(df$a), 88))
#convert all NA's to 88
df$a[is.na(df$a)] = 88
#check levels again
levels(df$a)
#[1] "3" "4" "7" "9" "10" "88"
如果使用 factor
函数,我的方法会有点传统:
a <- factor(a,
exclude = NULL,
levels = c(levels(a), NA),
labels = c(levels(a), "None"))
您可以将 "None" 替换为您想要的适当替换(例如 0L)
我遇到了类似的问题,我想添加我认为最实用(也最简洁)的解决方案:
将列转换为 character
列,使用 mutate
和一个简单的 ifelse
语句将 NA
值更改为您想要的因子水平是(我选择了“None”),将其转换回 factor
列:
df %>% mutate(
a = as.character(a),
a = ifelse(is.na(a), "None", a),
a = as.factor(a)
)
干净且无痛,因为当 factor
列中出现 NA
值时,您实际上不必涉足这些值。你绕过了怪异并最终得到一个干净的 factor
变量。
此外,为了回应下面关于多列的评论:您可以将语句包装在一个函数中并使用 mutate_if
到 select 所有因子变量,或者,如果您知道关注的列,mutate_at
应用该函数:
replace_factor_na <- function(x){
x <- as.character(x)
x <- if_else(is.na(x), "None", x)
x <- as.factor(x)
}
df <- df %>%
mutate_if(is.factor, replace_factor_na)