r:使用`for`和`if`仅在数字变量上运行run函数

问题描述 投票:1回答:2

我有一个四列数据框,包括datevar1_sharevar2_sharetotal。我想将每个share指标与total相乘,以创建包含var1var2原始值的新变量。请参阅下面的代码(有点冗长)来构造包含共享变量的数据框:

df<- data.frame(dt= seq.Date(from = as.Date('2019-01-01'), 
    to= as.Date('2019-01-10'), by= 'day'),
    var1= round(runif(10, 3, 12), digits = 1), 
    var2= round(runif(10, 3, 12), digits = 1))
df$total<- apply(df[2:3], 1, sum)
ratio<- lapply(df[-1], function(x) x/df$total)
ratio<- data.frame(ratio)
df<- cbind.data.frame(df[1],ratio)
colnames(df)<- c('date', 'var1_share', 'var2_share', 'total')
df

最终的数据框应如下所示:

> df
date var1_share var2_share total
1  2019-01-01  0.5862069  0.4137931     1
2  2019-01-02  0.6461538  0.3538462     1
3  2019-01-03  0.3591549  0.6408451     1
4  2019-01-04  0.7581699  0.2418301     1
5  2019-01-05  0.3989071  0.6010929     1
6  2019-01-06  0.5132743  0.4867257     1
7  2019-01-07  0.5230769  0.4769231     1
8  2019-01-08  0.4969325  0.5030675     1
9  2019-01-09  0.5034965  0.4965035     1
10 2019-01-10  0.3254438  0.6745562     1

我在if循环中嵌套了一个for语句,希望返回一个名为share的新数据帧。我希望它在使用共享变量时跳过date我已经合并了is.numeric,因此它忽略了date,但是,当我运行它时,它只返回日期而不是所需的日期结果,每个变量的份额(如单独的列)和总列。见下面的代码:

for (i in df){
  share<- if(is.numeric(i)){
     i * df$total
    } else i
  share<- data.frame(share)
  return(share)
}
share

> share
share
1  2019-01-01
2  2019-01-02
3  2019-01-03
...

如何调整此函数以便share返回包含日期,变量1和2原始变量以及总数的数据框?

r for-loop if-statement
2个回答
2
投票

可以注意到,将向量(*)与data.frame相乘,将在数据帧上投射乘法列(乘以第1,2,3列等的向量)。因此,只需使用总列的*和要增加的列,即可完成此操作而无需“应用”。

或者您可以创建一个简单的函数来实现结果。以下就是这样一个例子。

Multi_share <- function(x, total_col = "total"){
  if(is.character(total_col))
    return(x[,sapply(x, is.numeric)[names(x) != total_col]] * x[, total_col])
  if(is.numeric(total_col) && NROW(total_col) == NROW(x))
    return(x[,sapply(x, is.numeric)] * total_col)
  stop("Total unrecognized. Must either be a 1 dimensional vector, a column matrix or a character specifying the total column in R.")
}
cbind(df, Multi_share(df))

也可以更改列的名称。


0
投票

也许你想要这样的东西?

share <-df[, sapply(df,is.numeric)]
share <-mapply(function(x) x*share$total, share[,names(share)!="total"])

第一行将仅返回数字列(因此日期已过滤)。第二个将乘以每列(总数除外)和总数。

© www.soinside.com 2019 - 2024. All rights reserved.