修复由 9 表示的 NA(例如:99、999、9999)匹配 data.table(或 fread)中的列宽
Fixing NAs represented by 9s (ex: 99, 999, 9999) matching column width in data.table (or in fread)
文本文件中的数据通常具有表示 NA 的 9 的可变长度序列。也就是说,表示 NA 的 9 的数量取决于每个变量中的字符数。例如:
- 一个 2 位数的州代码将有 99 代表 NAs
- 一个 3 位变量将有 999 代表 NA。请注意,在这种情况下,99 可能是合法的(非 NA)值。
清理这些值的最佳方法是什么?
请注意,在fread
中,na.values=c('99','999')
不是一个理想的选择,因为它会破坏3位变量中合法的99个值。
假设我有 data.table
d
和两组数字列
cols_2digit <- c('a','b')
cols_3digit <- c('c','d')
如何一次性用 NA 替换每组所有列中的 9 序列?组数有限,一组一个命令即可。
OBS:这些可变长度的 NA 代码让人想起固定宽度的文件 (fwf),即使现代文件以 csv 格式提供(对于跨列的 NA 可能采用标准的“999999”值)。
我们可以通过遍历 'cols_2digit' 或 'cols_3digit' 中指定的列来使用 set
并在适当的位置更改列中的值
for(j in cols_2digit) set(d, i = which(d[[j]] == '99'), j = j, value = NA_character_)
for(j in cols_3digit) set(d, i = which(d[[j]] == '999'), j = j, value = NA_character_)
或者另一种选择是Map
d[, c(cols_2digit, col2_3digit) :=
Map(function(dat, y) lapply(dat, function(x)
fifelse(x, x == y, NA_character_)), list(.SD[, ..cols_2digit],
.SD[, ..cols_3digit]), list('99', '999')) ]
此外,不是在不同的集合上这样做,另一种选择是根据最大频率找到列宽
Mode <- function(x) {
ux <- unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
d[, lapply(.SD, function(x) {
# get the most frequent column width
colwidth <- Mode(nchar(x))
# if it is max
# colwidth <- max(nchar(x))
# get the elements that are only 9 from start (`^`) to end (`$`)
i1 <- grepl('^9+$', x)
# do the assignment based on the index
x[i1][nchar(x[i1]) == colwidth] <- NA_character_
x
})]
文本文件中的数据通常具有表示 NA 的 9 的可变长度序列。也就是说,表示 NA 的 9 的数量取决于每个变量中的字符数。例如:
- 一个 2 位数的州代码将有 99 代表 NAs
- 一个 3 位变量将有 999 代表 NA。请注意,在这种情况下,99 可能是合法的(非 NA)值。
清理这些值的最佳方法是什么?
请注意,在fread
中,na.values=c('99','999')
不是一个理想的选择,因为它会破坏3位变量中合法的99个值。
假设我有 data.table
d
和两组数字列
cols_2digit <- c('a','b')
cols_3digit <- c('c','d')
如何一次性用 NA 替换每组所有列中的 9 序列?组数有限,一组一个命令即可。
OBS:这些可变长度的 NA 代码让人想起固定宽度的文件 (fwf),即使现代文件以 csv 格式提供(对于跨列的 NA 可能采用标准的“999999”值)。
我们可以通过遍历 'cols_2digit' 或 'cols_3digit' 中指定的列来使用 set
并在适当的位置更改列中的值
for(j in cols_2digit) set(d, i = which(d[[j]] == '99'), j = j, value = NA_character_)
for(j in cols_3digit) set(d, i = which(d[[j]] == '999'), j = j, value = NA_character_)
或者另一种选择是Map
d[, c(cols_2digit, col2_3digit) :=
Map(function(dat, y) lapply(dat, function(x)
fifelse(x, x == y, NA_character_)), list(.SD[, ..cols_2digit],
.SD[, ..cols_3digit]), list('99', '999')) ]
此外,不是在不同的集合上这样做,另一种选择是根据最大频率找到列宽
Mode <- function(x) {
ux <- unique(x)
ux[which.max(tabulate(match(x, ux)))]
}
d[, lapply(.SD, function(x) {
# get the most frequent column width
colwidth <- Mode(nchar(x))
# if it is max
# colwidth <- max(nchar(x))
# get the elements that are only 9 from start (`^`) to end (`$`)
i1 <- grepl('^9+$', x)
# do the assignment based on the index
x[i1][nchar(x[i1]) == colwidth] <- NA_character_
x
})]