运行 当第一个 ID 全部丢失时,sapply 中的函数返回错误结果
Running a function in sapply is returning faulty results when first ID is all missing
我有一个非常奇怪的具体问题,我正在努力解决 google,所以我希望我可以向别人展示。
我编写了一个函数,可以根据一些条件填充一些缺失的数据。例如,对于这样的面板数据:
library(tidyverse)
library(data.table)
dt <- data.frame(id = c(rep('a', 5),
rep('b', 5),
rep('c', 5)),
var1 = c(rep('', 4), 'bonjour',
'bye', NA, 'bye', 'bye', NA,
'hi', 'hi', NA, 'hi', 'hi'),
year = c(2005:2009,
1995:1998, 2002,
1995:1999))
dt
id var1 year
1: a 2005
2: a 2006
3: a 2007
4: a 2008
5: a bonjour 2009
6: b bye 1995
7: b <NA> 1996
8: b bye 1997
9: b bye 1998
10: b <NA> 2002
11: c hi 1995
12: c hi 1996
13: c <NA> 1997
14: c hi 1998
15: c hi 1999
我使用以下函数来更新一些缺失值:
fill.in <- function(var, yr, finyr) {
leadv <- lead(var, n=1, order_by = yr)
lagv <- lag(var, n=1, order_by = yr)
leadyr <- lead(yr, n=1, order_by = yr)
lagyr <- lag(yr, n=1, order_by = yr)
# ------- build the updated var w/ sequential conditions
# keep the var as it is if not missing
try1 <- ifelse(test = !is.na(var),
yes = var,
no = NA)
# fill in if the lead and lag match and no more than 2 missing years
try2 <- ifelse(test = is.na(try1) & leadv == lagv &
abs(leadyr-lagyr) <= 3 &
!is.na(leadv),
yes = leadv,
no = try1)
# fill in with the lag if it's the final year of observed data
ifelse(test = is.na(try2) & yr == finyr &
abs(yr-lagyr) <= 3 & !is.na(lagv),
yes = lagv,
no = try2)
}
经过一些设置,总的来说我得到了不错的结果:
# ------------ Set-up
# real data is big so use data.table
setDT(dt)
dt[, finalyr := max(year), by = id]
# don't want to fill in factor values
dt$var1 <- as.character(dt$var1)
# make empty strings NAs
dt[, var1 := na_if(var1, '')]
# useful for when i'm filling in many variables
fill.in.vs <- c('var1')
fixed.vnames <- paste0('fixed.', fill.in.vs)
# ------------ Call the function and results
dt[, (fixed.vnames) := sapply(.SD,
FUN = fill.in,
year,
finalyr,
simplify = FALSE, USE.NAMES = FALSE),
by = id, .SDcols = fill.in.vs]
# this gives me what I want:
dt
id var1 year finalyr fixed.var1
1: a <NA> 2005 2009 <NA>
2: a <NA> 2006 2009 <NA>
3: a <NA> 2007 2009 <NA>
4: a <NA> 2008 2009 <NA>
5: a bonjour 2009 2009 bonjour
6: b bye 1995 2002 bye
7: b <NA> 1996 2002 bye
8: b bye 1997 2002 bye
9: b bye 1998 2002 bye
10: b <NA> 2002 2002 <NA>
11: c hi 1995 1999 hi
12: c hi 1996 1999 hi
13: c <NA> 1997 1999 hi
14: c hi 1998 1999 hi
15: c hi 1999 1999 hi
问题是当第一组 ID——例如所有 'a' 值——有空字符串,我将其转换为 NA
s,“固定”变量的 all 值最终为 NA
s还有。
所以使用相同的代码但使用以下数据,我在新变量中得到了所有 NA
s:
# id of 'a' now is all empty strings in var1:
dt <- data.frame(id = c(rep('a', 5),
rep('b', 5),
rep('c', 5)),
var1 = c(rep('', 5),
'bye', NA, 'bye', 'bye', NA,
'hi', 'hi', NA, 'hi', 'hi'),
year = c(2005:2009,
1995:1998, 2002,
1995:1999))
# which results in this final data after running the same code above:
dt
id var1 year finalyr fixed.var1
1: a <NA> 2005 2009 NA
2: a <NA> 2006 2009 NA
3: a <NA> 2007 2009 NA
4: a <NA> 2008 2009 NA
5: a <NA> 2009 2009 NA
6: b bye 1995 2002 NA
7: b <NA> 1996 2002 NA
8: b bye 1997 2002 NA
9: b bye 1998 2002 NA
10: b <NA> 2002 2002 NA
11: c hi 1995 1999 NA
12: c hi 1996 1999 NA
13: c <NA> 1997 1999 NA
14: c hi 1998 1999 NA
15: c hi 1999 1999 NA
为简洁起见,我不会向您展示我尝试过的所有内容,但会展示一些关于何时发生的观察结果:
- 如果我不将空字符串转换为
NA
,第一个 ID 中的所有空字符串都不是问题。
- 如果 第一个 ID 全部为空字符串,我只会得到这个结果;如果是第二盘,结果还可以。
- 我如何将
""
转换为 NA
并不重要,也就是说,这不是 na_if
的问题,因为当我使用 ifelse
.[= 时也会发生这种情况46=]
总的来说,我对正在发生的事情或如何进一步调查它感到很困惑。如果有任何帮助,我将不胜感激。
当我运行你的代码时,我收到这个警告:
1: In
[.data.table(dt, ,
:=((fixed.vnames), sapply(.SD, FUN = fill.in, : Coercing 'character' RHS to 'logical' to match the type of the target column (column 0 named '').
我得到了两次,一次是第二组,一次是第三组。
正如它所说,变量 fixed.var1
被初始化为逻辑变量(对于组 id==a
);然后将稍后添加的值转换为相同的 class 'logical'.
这里的罪魁祸首是您的函数 fill.in()
,因为例如
logicalVar <- fill.in( var=rep(NA,5), yr=2005:2009, finyr=rep(2009,5)); class(logicalVar)
returns 是一个逻辑变量。
因此,您需要做的就是将 as.character()
包裹在函数的 return 周围。
我有一个非常奇怪的具体问题,我正在努力解决 google,所以我希望我可以向别人展示。
我编写了一个函数,可以根据一些条件填充一些缺失的数据。例如,对于这样的面板数据:
library(tidyverse)
library(data.table)
dt <- data.frame(id = c(rep('a', 5),
rep('b', 5),
rep('c', 5)),
var1 = c(rep('', 4), 'bonjour',
'bye', NA, 'bye', 'bye', NA,
'hi', 'hi', NA, 'hi', 'hi'),
year = c(2005:2009,
1995:1998, 2002,
1995:1999))
dt
id var1 year
1: a 2005
2: a 2006
3: a 2007
4: a 2008
5: a bonjour 2009
6: b bye 1995
7: b <NA> 1996
8: b bye 1997
9: b bye 1998
10: b <NA> 2002
11: c hi 1995
12: c hi 1996
13: c <NA> 1997
14: c hi 1998
15: c hi 1999
我使用以下函数来更新一些缺失值:
fill.in <- function(var, yr, finyr) {
leadv <- lead(var, n=1, order_by = yr)
lagv <- lag(var, n=1, order_by = yr)
leadyr <- lead(yr, n=1, order_by = yr)
lagyr <- lag(yr, n=1, order_by = yr)
# ------- build the updated var w/ sequential conditions
# keep the var as it is if not missing
try1 <- ifelse(test = !is.na(var),
yes = var,
no = NA)
# fill in if the lead and lag match and no more than 2 missing years
try2 <- ifelse(test = is.na(try1) & leadv == lagv &
abs(leadyr-lagyr) <= 3 &
!is.na(leadv),
yes = leadv,
no = try1)
# fill in with the lag if it's the final year of observed data
ifelse(test = is.na(try2) & yr == finyr &
abs(yr-lagyr) <= 3 & !is.na(lagv),
yes = lagv,
no = try2)
}
经过一些设置,总的来说我得到了不错的结果:
# ------------ Set-up
# real data is big so use data.table
setDT(dt)
dt[, finalyr := max(year), by = id]
# don't want to fill in factor values
dt$var1 <- as.character(dt$var1)
# make empty strings NAs
dt[, var1 := na_if(var1, '')]
# useful for when i'm filling in many variables
fill.in.vs <- c('var1')
fixed.vnames <- paste0('fixed.', fill.in.vs)
# ------------ Call the function and results
dt[, (fixed.vnames) := sapply(.SD,
FUN = fill.in,
year,
finalyr,
simplify = FALSE, USE.NAMES = FALSE),
by = id, .SDcols = fill.in.vs]
# this gives me what I want:
dt
id var1 year finalyr fixed.var1
1: a <NA> 2005 2009 <NA>
2: a <NA> 2006 2009 <NA>
3: a <NA> 2007 2009 <NA>
4: a <NA> 2008 2009 <NA>
5: a bonjour 2009 2009 bonjour
6: b bye 1995 2002 bye
7: b <NA> 1996 2002 bye
8: b bye 1997 2002 bye
9: b bye 1998 2002 bye
10: b <NA> 2002 2002 <NA>
11: c hi 1995 1999 hi
12: c hi 1996 1999 hi
13: c <NA> 1997 1999 hi
14: c hi 1998 1999 hi
15: c hi 1999 1999 hi
问题是当第一组 ID——例如所有 'a' 值——有空字符串,我将其转换为 NA
s,“固定”变量的 all 值最终为 NA
s还有。
所以使用相同的代码但使用以下数据,我在新变量中得到了所有 NA
s:
# id of 'a' now is all empty strings in var1:
dt <- data.frame(id = c(rep('a', 5),
rep('b', 5),
rep('c', 5)),
var1 = c(rep('', 5),
'bye', NA, 'bye', 'bye', NA,
'hi', 'hi', NA, 'hi', 'hi'),
year = c(2005:2009,
1995:1998, 2002,
1995:1999))
# which results in this final data after running the same code above:
dt
id var1 year finalyr fixed.var1
1: a <NA> 2005 2009 NA
2: a <NA> 2006 2009 NA
3: a <NA> 2007 2009 NA
4: a <NA> 2008 2009 NA
5: a <NA> 2009 2009 NA
6: b bye 1995 2002 NA
7: b <NA> 1996 2002 NA
8: b bye 1997 2002 NA
9: b bye 1998 2002 NA
10: b <NA> 2002 2002 NA
11: c hi 1995 1999 NA
12: c hi 1996 1999 NA
13: c <NA> 1997 1999 NA
14: c hi 1998 1999 NA
15: c hi 1999 1999 NA
为简洁起见,我不会向您展示我尝试过的所有内容,但会展示一些关于何时发生的观察结果:
- 如果我不将空字符串转换为
NA
,第一个 ID 中的所有空字符串都不是问题。 - 如果 第一个 ID 全部为空字符串,我只会得到这个结果;如果是第二盘,结果还可以。
- 我如何将
""
转换为NA
并不重要,也就是说,这不是na_if
的问题,因为当我使用ifelse
.[= 时也会发生这种情况46=]
总的来说,我对正在发生的事情或如何进一步调查它感到很困惑。如果有任何帮助,我将不胜感激。
当我运行你的代码时,我收到这个警告:
1: In
[.data.table(dt, ,
:=((fixed.vnames), sapply(.SD, FUN = fill.in, : Coercing 'character' RHS to 'logical' to match the type of the target column (column 0 named '').
我得到了两次,一次是第二组,一次是第三组。
正如它所说,变量 fixed.var1
被初始化为逻辑变量(对于组 id==a
);然后将稍后添加的值转换为相同的 class 'logical'.
这里的罪魁祸首是您的函数 fill.in()
,因为例如
logicalVar <- fill.in( var=rep(NA,5), yr=2005:2009, finyr=rep(2009,5)); class(logicalVar)
returns 是一个逻辑变量。
因此,您需要做的就是将 as.character()
包裹在函数的 return 周围。