R/Dplyr: Dataframe -用0填充NA/NULL值,每行要填充的列基于每行特定值中的值

rta7y2nd  于 2023-05-11  发布在  其他
关注(0)|答案(1)|浏览(117)

我是新来这个社区的。
我正在尝试用R编写代码,但代码有点问题。

#Create dataframe with 5 rows and 3 columns
my_dataframe=data.frame(Student_Id = c( '1012501', '1012502', '1012503', '1012504', '1012505', '1012506'),  
                        Student_Nm = c( 'John Doe', 'John Smith', 'John Simon', 'Jane Powel', 'Jane Smith', 'Jane Simon'),  
                        School_Cd = c( '808971', '808972', '808973', '808974', '808975', '808976'),     
                        Grade = c(1,1,2,2,3,4),     
                        Age = c(6,6,7,7,8,9),   
                        Join_Month_Count = c(36,18,2,9,3,22),   
                        New_Student_FL = c(0,0,1,0,1,0),    
                        Subject = c( 'Math', 'Science', 'Geography', 'Social_Study', 'Music', 'Math'),  
                        Mar_22 = c(NA,NA,NA,NA,NA,NA),  
                        Apt_22 = c(NA,9,NA,NA,NA,2),    
                        May_22 = c(12,NA,NA,NA,NA,9),   
                        Jun_22 = c(NA,8,NA,NA,NA,8),    
                        Jul_22 = c(1,NA,NA,8,NA,NA),    
                        Aug_22 = c(NA,NA,NA,NA,NA,7),   
                        Sep_22 = c(9,8,NA,NA,NA,NA),    
                        Oct_22 = c(NA,NA,NA,8,NA,NA),   
                        Nov_22 = c(26,NA,NA,NA,NA,4),   
                        Dec_22 = c(NA,7,NA,NA,NA,NA),   
                        Jan_23 = c(4,6,NA,8,NA,1),  
                        Feb_23 = c(8,NA,4,NA,12,1),     
                        Mar_23 = c(9,NA,NA,8,NA,5))

#Display dataframe
print(my_dataframe)

示例表如下:

1.我正在尝试用0填充数据框的列(9到21)中现有的NA或Null值。从第9列到第21列(样本数据中的Mar_22到Mar_23)。
1.该公式需要检查“Join_Month_Count”的值是什么,以及
1.从22(总列计数+1)中减去“Join_Month_Count”值以获得目标列索引。如果索引小于9,则起始列索引将为9,否则从计算的索引列开始到最后一列,并且
1.将任何NA/NULL值填写为0
例如:在示例数据集中,第1行:第9栏至第21栏,NA将填写0第2行:第9栏至第21栏,NA将填写0第3行:第20列到第21列,NA将填充0,每隔一列将保持为第4行:第13列到第21列,NA将填充0,每隔一列将保持为第5行:第19列到第21列,NA将填充0,每隔一列将保持为第6行:第9列至第21列,NA将填充0
目前,我正在使用一个for循环,如下所示,但它不工作。代码用0填充所有Na。有没有更简单、更快的方法?
R代码如下。

for(i in 1:nrow(my_dataframe)){
  ref_val = 22 - my_dataframe[i,6]    ## 6 is the index of the "Join_Month_Count" column
  
  if(ref_val < 9){          ## 9 is the column index of the month start
    ref_val = 9
  }

my_dataframe[ , ref_val:21][is.na(my_dataframe[ , ref_val:21])] <- 0
}

and this 

# Replace NA on multiple columns by Index
library("tidyr")
library("dplyr")
my_dataframe <- my_dataframe %>% 
  mutate(across(c(Sep_22:Mar_23),~ ifelse(is.na(.), 0, .)))

The Following Seems to work, but really Slow

for(i in 1:nrow(my_dataframe)){
  ref_val = 22 - my_dataframe[i,6]    ## 6 is the index of the "Join_Month_Count" column
  
  if(ref_val < 9){          ## 9 is the column index of the month start
    ref_val = 9
  }
  print(ref_val)
  my_dataframe[i, ref_val:21][is.na(my_dataframe[i, ref_val:21])] <- 0
}

#Display dataframe
print(my_dataframe)

谢谢JC

3gtaxfhh

3gtaxfhh1#

这是一个基本的R方法。

tmp <- lapply(pmin(pmax(22 - my_dataframe$Join_Month_Count, 9), 21) - 8,
              function(z) replace(rep(NA, 13), z:13, 0))
str(tmp, vec.len = 13)
# List of 6
#  $ : num [1:13] 0 0 0 0 0 0 0 0 0 0 0 0 0
#  $ : num [1:13] 0 0 0 0 0 0 0 0 0 0 0 0 0
#  $ : num [1:13] NA NA NA NA NA NA NA NA NA NA NA 0 0
#  $ : num [1:13] NA NA NA NA 0 0 0 0 0 0 0 0 0
#  $ : num [1:13] NA NA NA NA NA NA NA NA NA NA 0 0 0
#  $ : num [1:13] 0 0 0 0 0 0 0 0 0 0 0 0 0
tmp <- setNames(do.call(rbind.data.frame, tmp), names(my_dataframe)[9:21])
tmp
#   Mar_22 Apt_22 May_22 Jun_22 Jul_22 Aug_22 Sep_22 Oct_22 Nov_22 Dec_22 Jan_23 Feb_23 Mar_23
# 1      0      0      0      0      0      0      0      0      0      0      0      0      0
# 2      0      0      0      0      0      0      0      0      0      0      0      0      0
# 3     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA      0      0
# 4     NA     NA     NA     NA      0      0      0      0      0      0      0      0      0
# 5     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA      0      0      0
# 6      0      0      0      0      0      0      0      0      0      0      0      0      0

第一步创建一个相同形状的列data.frame9:21),如果我们想用0替换NA s,则使用0,否则使用NA
这样,我们就可以在所需的列上使用dplyr::coalesce列方式:

my_dataframe[,9:21] <- Map(dplyr::coalesce, my_dataframe[,9:21], tmp)
my_dataframe
#   Student_Id Student_Nm School_Cd Grade Age Join_Month_Count New_Student_FL      Subject Mar_22 Apt_22 May_22 Jun_22 Jul_22 Aug_22 Sep_22 Oct_22 Nov_22 Dec_22 Jan_23 Feb_23 Mar_23
# 1    1012501   John Doe    808971     1   6               36              0         Math      0      0     12      0      1      0      9      0     26      0      4      8      9
# 2    1012502 John Smith    808972     1   6               18              0      Science      0      9      0      8      0      0      8      0      0      7      6      0      0
# 3    1012503 John Simon    808973     2   7                2              1    Geography     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA      4      0
# 4    1012504 Jane Powel    808974     2   7                9              0 Social_Study     NA     NA     NA     NA      8      0      0      8      0      0      8      0      8
# 5    1012505 Jane Smith    808975     3   8                3              1        Music     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA      0     12      0
# 6    1012506 Jane Simon    808976     4   9               22              0         Math      0      2      9      8      0      7      0      0      4      0      1      1      5

相关问题