从数据框中删除某些行的函数
Function to remove certain rows from dataframe
我正在尝试编写一个从数据框中删除某些行的函数。
为简单起见,让我们假设删除的条件是该行中至少有一个 NA。
df = data.frame(c("A","B","C"),c(1,NA,3))
fn = function (d) {
for (x in 1:nrow(d)) { for (y in 1:ncol(d)) {
if(is.na(d[x,y])) d = d[-x,]
}}}
fn(df)
PS:我知道有更好的方法可以删除至少有一个 NA 的行,即 df = df[-which(!complete.cases(df)] 但我有兴趣找出为什么我写的代码不起作用。
你需要明确地return d
从你的函数
df <- data.frame(X1 = c("A","B","C"), X2 = c(1,NA,3))
fn <- function (d) {
for (x in 1:nrow(d)) {
for (y in 1:ncol(d)) {
if(is.na(d[x,y])) d = d[-x,]
}
}
d # return d
}
fn(df)
> fn(df)
X1 X2
1 A 1
3 C 3
R 隐式 return 是最后一个操作的结果,但这是对第三行 if (...)
求值的结果,returned NULL
> foo <- fn(df) # using your fn()
> foo
NULL
您可以在函数末尾显式调用 return(d)
,但由于 R 也在最后一个语句中调用 return()
,这就像调用 return(return(d))
。因此,您只需在函数的最后一行使用 d
,R 就会执行正确的操作。
不使用 return()
的主要例外情况(即当您应该使用它时)是在您可能希望 return 尽早从函数中使用的情况下。
最后,与其循环遍历对象的行和列,不如考虑按行工作。 R 是矢量化的,因此您可以在整行上执行 is.na()
(例如),然后您的 if()
语句将是 if (any(is.na(d[i, ]))
,其中 i
是循环索引,例如:
fn2 <- function (d) {
for (i in 1:nrow(d)) {
if (any(is.na(d[i,]))) {
d <- d[-i, ]
}
}
d # return d
}
> fn2(df)
X1 X2
1 A 1
3 C 3
有更有效的方法可以做到这一点,但如果您以矢量化方式思考,您将开始编写更简单、更快速的 R 代码。
函数式编程风格
我认为 OP 缺少的是您不能直接修改作为参数传递的变量。这就是函数式编程风格。
访问https://en.wikipedia.org/wiki/Functional_programming
事实上,函数体中的变量是作为参数传递的变量的副本。所以你正在制作副本。
这就是为什么您必须 return 复制并将其重新分配给变量的原因。
df <- data.frame(X1 = c("A","B","C"), X2 = c(1,NA,3))
fn <- function (d) {
for (x in 1:nrow(d)) {
for (y in 1:ncol(d)) {
if(is.na(d[x,y])) d = d[-x,]}}
d} # return d
df <- fn(df)
df
现在如 OP 所愿
我正在尝试编写一个从数据框中删除某些行的函数。 为简单起见,让我们假设删除的条件是该行中至少有一个 NA。
df = data.frame(c("A","B","C"),c(1,NA,3))
fn = function (d) {
for (x in 1:nrow(d)) { for (y in 1:ncol(d)) {
if(is.na(d[x,y])) d = d[-x,]
}}}
fn(df)
PS:我知道有更好的方法可以删除至少有一个 NA 的行,即 df = df[-which(!complete.cases(df)] 但我有兴趣找出为什么我写的代码不起作用。
你需要明确地return d
从你的函数
df <- data.frame(X1 = c("A","B","C"), X2 = c(1,NA,3))
fn <- function (d) {
for (x in 1:nrow(d)) {
for (y in 1:ncol(d)) {
if(is.na(d[x,y])) d = d[-x,]
}
}
d # return d
}
fn(df)
> fn(df)
X1 X2
1 A 1
3 C 3
R 隐式 return 是最后一个操作的结果,但这是对第三行 if (...)
求值的结果,returned NULL
> foo <- fn(df) # using your fn()
> foo
NULL
您可以在函数末尾显式调用 return(d)
,但由于 R 也在最后一个语句中调用 return()
,这就像调用 return(return(d))
。因此,您只需在函数的最后一行使用 d
,R 就会执行正确的操作。
不使用 return()
的主要例外情况(即当您应该使用它时)是在您可能希望 return 尽早从函数中使用的情况下。
最后,与其循环遍历对象的行和列,不如考虑按行工作。 R 是矢量化的,因此您可以在整行上执行 is.na()
(例如),然后您的 if()
语句将是 if (any(is.na(d[i, ]))
,其中 i
是循环索引,例如:
fn2 <- function (d) {
for (i in 1:nrow(d)) {
if (any(is.na(d[i,]))) {
d <- d[-i, ]
}
}
d # return d
}
> fn2(df)
X1 X2
1 A 1
3 C 3
有更有效的方法可以做到这一点,但如果您以矢量化方式思考,您将开始编写更简单、更快速的 R 代码。
函数式编程风格
我认为 OP 缺少的是您不能直接修改作为参数传递的变量。这就是函数式编程风格。
访问https://en.wikipedia.org/wiki/Functional_programming
事实上,函数体中的变量是作为参数传递的变量的副本。所以你正在制作副本。
这就是为什么您必须 return 复制并将其重新分配给变量的原因。
df <- data.frame(X1 = c("A","B","C"), X2 = c(1,NA,3))
fn <- function (d) {
for (x in 1:nrow(d)) {
for (y in 1:ncol(d)) {
if(is.na(d[x,y])) d = d[-x,]}}
d} # return d
df <- fn(df)
df
现在如 OP 所愿