【问题标题】:Replacing zeroes with NA for values preceding non-zero对于非零之前的值,用 NA 替换零
【发布时间】:2018-08-14 14:38:19
【问题描述】:

我是 R 新手,并且一直在努力解决以下问题,所以我希望有人能够帮助我。

样本数据代表股票价格回报(每行是一个月)。真实数据集要大得多,其结构类似于以下输入:

输入:

stock1 <- c(0.01, -0.02, 0.01, 0.05, 0.04, -0.02)
stock2 <- c(0, 0, 0.02, 0.04, -0.03, 0.02)
stock3 <- c(0, 0, 0.02, 0, -0.01, 0.03)
stock4 <- c(0, -0.02, 0.01, 0, 0, -0.02)
df <- cbind(stock1,stock2,stock3,stock4)

     stock1 stock2 stock3 stock4
[1,]   0.01   0.00   0.00   0.00
[2,]  -0.02   0.00   0.00  -0.02
[3,]   0.01   0.02   0.02   0.01
[4,]   0.05   0.04   0.00   0.00
[5,]   0.04  -0.03  -0.01   0.00
[6,]  -0.02   0.02   0.03  -0.02

对于给定股票,在非零之前的任何零都表示缺失数据,而不是该期间的零回报。我想将这些值设置为 NA 所以我想实现的输出如下:

期望的输出:

stock1 <- c(0.01, -0.02, 0.01, 0.05, 0.04, -0.02)
stock2 <- c(NA, NA, 0.02, 0.04, -0.03, 0.02)
stock3 <- c(NA, NA, 0.02, 0, -0.01, 0.03)
stock4 <- c(NA, -0.02, 0.01, 0, 0, -0.02)
df <- cbind(stock1,stock2,stock3,stock4)

     stock1 stock2 stock3 stock4
[1,]   0.01     NA     NA     NA
[2,]  -0.02     NA     NA  -0.02
[3,]   0.01   0.02   0.02   0.01
[4,]   0.05   0.04   0.00   0.00
[5,]   0.04  -0.03  -0.01   0.00
[6,]  -0.02   0.02   0.03  -0.02

我尝试了一些方法,但它们似乎只适用于单个向量,而不是具有多列的数据集。我试过使用 lapply 来解决这个问题,但到目前为止还没有任何运气。我得到的最接近的如下所示。

我的单向量解决方案:

stock1[1:min(which(stock1!=0))-1 <- NA

我的多向量解决方案不起作用

lapply(df,function(x) x[1:min(which(x!=0))-1 <- NA]

非常感谢任何指导!谢谢!

【问题讨论】:

  • 只有第一个前导零应该被改变吗?这意味着,例如,如果stock1 &lt;- c(0.01, -0.02, 0.01, 0, 0, -0.02) 你也想把它们保持为 0,虽然有两个连续的零?在您的示例中,您在其他地方只有一个 0,但没有两个连续的。

标签: r


【解决方案1】:

存在三个问题。一、写作:

df <- cbind(stock1,stock2,stock3,stock4)

不创建数据框。它创建了一个矩阵。这是当您尝试使用lapply 时出现的问题,它将对数据框 的列进行操作,但对矩阵 的元素进行操作。相反,你应该写:

df <- data.frame(stock1,stock2,stock3,stock4)

其次,您在lapply 中使用的函数需要返回修改后的向量。否则,返回值会出乎意料(在这种情况下,赋值将返回单个NA,而lapply 将返回一行NAs 的数据框,而不是您想要的数据框) .

第三,当n 可以为零时(即,当第一个股票报价不为零时),您需要注意1:n,因为1:0 给出了序列c(1,0),而不是一个空序列。 (这可以说是 R 最愚蠢的功能之一。)

因此,以下内容将为您提供您想要的:

stock1 <- c(0.01, -0.02, 0.01, 0.05, 0.04, -0.02)
stock2 <- c(0, 0, 0.02, 0.04, -0.03, 0.02)
stock3 <- c(0, 0, 0.02, 0, -0.01, 0.03)
stock4 <- c(0, -0.02, 0.01, 0, 0, -0.02)
df <- data.frame(stock1,stock2,stock3,stock4)

as.data.frame(lapply(df, function(x) {
    n <- min(which(x != 0)) - 1
    if (n > 0)
        x[1:n] <- NA
    x
}))

输出如预期:

  stock1 stock2 stock3 stock4
1   0.01     NA     NA     NA
2  -0.02     NA     NA  -0.02
3   0.01   0.02   0.02   0.01
4   0.05   0.04   0.00   0.00
5   0.04  -0.03  -0.01   0.00
6  -0.02   0.02   0.03  -0.02

更新:正如@Daniel_Fischer 所说,有一个巧妙的技巧可以避免1:0 问题。你可以改写:

as.data.frame(lapply(df, function(x) {
    n <- min(which(x != 0)) - 1
    x[0:n] <- NA    # use 0:n instead of 1:n
    x
}))

这利用了 R 在这种类型的索引操作中忽略零的事实,所以:

x[0:0] <- NA    # same as x[0] <- NA and does nothing
x[0:1] <- NA    # same as x[1] <- NA
x[0:2] <- NA    # same as x[1:2] <- NA, etc.

【讨论】:

  • 哦,我看到@Daniel_Fischer 为n &gt; 0 问题提供了一个很好的解决方法。如果您执行x[0:n] &lt;- NA,则无论n 是零还是非零都可以,因此您也可以跳过if 语句。
  • 非常感谢,非常感谢您的帮助和及时回复!我仍在努力了解各种“数据结构”之间微妙但重要的区别,因此也感谢您指出 data.frame 和 as.data.frame 函数!
【解决方案2】:

这可能不是最优雅的方式,但我认为它有效

changeValues <- function(x){
   place <- min(which(diff(c(0,cumsum(x==0)))==0))-1;
   x[0:place] <- NA
   x
}

apply(df,2,changeValues)

编辑:对该函数的一些简要说明:首先,我创建一个向量,该向量在列中为零的每个位置增加,然后检查该向量在哪个位置不增加(=这意味着,没有两个彼此相邻的零),然后我仍然取其中的最小值,并确保这些只是前导零(这样矩阵内的值就不会改变)

【讨论】:

  • 好吧,现在还为时过早,所以我的回答肯定是过于复杂了,min(which(x!=0))-1 是获得place 的捷径...
【解决方案3】:
stock1 <- c(0.01, -0.02, 0.01, 0.05, 0.04, -0.02)
stock2 <- c(0, 0, 0.02, 0.04, -0.03, 0.02)
stock3 <- c(0, 0, 0.02, 0, -0.01, 0.03)
stock4 <- c(0, -0.02, 0.01, 0, 0, -0.02)
df <- data.frame(stock1,stock2,stock3,stock4) #the following function only works if df is actually a data.frame

df[] <- lapply(df, function(x) {ifelse(cumsum(x) == 0 & x == 0, NA, x)})

df

  stock1 stock2 stock3 stock4
1   0.01     NA     NA     NA
2  -0.02     NA     NA  -0.02
3   0.01   0.02   0.02   0.01
4   0.05   0.04   0.00   0.00
5   0.04  -0.03  -0.01   0.00
6  -0.02   0.02   0.03  -0.02

一些解释:首先检查每个单元格的累积colSum和当前单元格是否等于0。如果是,则返回NA,否则返回原始值。 df 后面的括号确保lapply 函数再次返回分配给dfdataframe

另外,如果您真的不需要 df 作为数据框,这也可以:

df <- cbind(stock1,stock2,stock3,stock4)
apply(df, 2, function(x) {ifelse(cumsum(x) == 0 & x == 0, NA, x)})

【讨论】:

    猜你喜欢
    • 2015-08-24
    • 2016-01-20
    • 2020-04-05
    • 2018-01-05
    • 2023-02-23
    • 1970-01-01
    • 1970-01-01
    • 2018-11-30
    • 2016-03-06
    相关资源
    最近更新 更多