【问题标题】:R - if-else applied to a listR - if-else 应用于列表
【发布时间】:2015-01-10 10:53:51
【问题描述】:

我是 R 新手,所以可能有些概念并不完全正确... 我有一组文件,我读入了一个列表(这里只显示了每个文件的前 3 行):

myfiles<-lapply(list.files(".",pattern="tab",full.names=T),read.table,skip="#")
myfiles
[[1]]
       V1  V2         V3
1   10001  33 -0.0499469
2   30001  65  0.0991478
3   50001  54  0.1564400

[[2]]
       V1  V2        V3
1   10001  62 0.0855260
2   30001  74 0.1536640
3   50001  71 0.1020960

[[3]]
       V1  V2          V3
1   10001  49 -0.04661360
2   30001  65  0.16961500
3   50001  61  0.07089600

我想应用 ifelse 条件来替换列中的值,然后返回完全相同的列表。但是,当我这样做时:

myfiles<-lapply(myfiles,function(x) ifelse(x$V2>50, x$V3, NA))
myfiles
[[1]]
 [1]         NA  0.0991478  0.1564400

[[2]]
 [1] 0.0855260 0.1536640 0.1020960

[[3]]
 [1]          NA  0.16961500  0.07089600

它实际上是我想要的,但只返回应用函数的列,我希望它返回与以前相同的列表,包含 3 列(但有替换)。

我想应该有一种简单的方法可以使用“应用”的一些变体来做到这一点,但我无法找到或解决它。

谢谢

【问题讨论】:

  • 如果要替换 V3 列,只需修改函数:lapply(myfiles,function(x) {x$V3&lt;-ifelse(x$V2&gt;50, x$V3, NA);x})。如果要添加另一个名为 newcolumnname 的列,只需将上述命令中的 x$V3 替换为 x$newcolumnname 即可。
  • 您要替换V2V3 中的值吗?
  • 我想根据 V2 上的条件替换 V3 中的值

标签: r list if-statement apply


【解决方案1】:

尝试为每个 df 添加一个 id 列并将它们绑定在一起:

for(i in 1:3) myfiles[[i]]$id = i
ddf = myfiles[[1]]
for(i in 2:3) ddf = rbind(ddf, myfiles[[i]])

然后在复合 df 上应用更改并再次拆分:

ddf$V3 = ifelse(ddf$V2>50, ddf$V3, NA)
myfiles = lapply(split(ddf, ddf$id), function(x) x[1:3])

myfiles
$`1`
     V1 V2        V3
1 10001 33        NA
2 30001 65 0.0991478
3 50001 54 0.1564400

$`2`
      V1 V2       V3
11 10001 62 0.085526
21 30001 74 0.153664
31 50001 71 0.102096

$`3`
      V1 V2       V3
12 10001 49       NA
22 30001 65 0.169615
32 50001 61 0.070896

【讨论】:

    【解决方案2】:

    也许这有帮助

     lapply(myfiles,within, V3 <- ifelse(V2 >50, V3, NA))
    
    
     #[[1]]
     #    V1 V2        V3
     #1 10001 33        NA
     #2 30001 65 0.0991478
     #3 50001 54 0.1564400
    
     #[[2]]
     #    V1 V2       V3
     #1 10001 62 0.085526
     #2 30001 74 0.153664
     #3 50001 71 0.102096
    
    #[[3]]
    #     V1 V2       V3
    #1 10001 49       NA
    #2 30001 65 0.169615
    #3 50001 61 0.070896
    

    更新

    另一种选择是使用freaddata.table 读取文件,这会很快

    library(data.table)
    files <- list.files(pattern='tab')
    lapply(files, function(x) fread(x)[V2<=50,V3:=NA] )
    #[[1]]
    #     V1 V2        V3
    #1: 10001 33        NA
    #2: 30001 65 0.0991478
    #3: 50001 54 0.1564400
    
    #[[2]]
    #     V1 V2       V3
    #1: 10001 62 0.085526
    #2: 30001 74 0.153664
    #3: 50001 71 0.102096
    
    #[[3]]
    #     V1 V2       V3
    #1: 10001 49       NA
    #2: 30001 65 0.169615
    #3: 50001 61 0.070896
    

    或者正如@Richie Cotton 所说,您也可以使用rbindlist 将数据集绑定在一起,然后一步完成操作。

     library(tools)
     dt1 <- rbindlist(lapply(files, function(x) 
          fread(x)[,id:= basename(file_path_sans_ext(x))] ))[V2<=50, V3:=NA]
    
     dt1
     #     V1 V2        V3   id
     #1: 10001 33        NA tab1
     #2: 30001 65 0.0991478 tab1
     #3: 50001 54 0.1564400 tab1
     #4: 10001 62 0.0855260 tab2
     #5: 30001 74 0.1536640 tab2
     #6: 50001 71 0.1020960 tab2
     #7: 10001 49        NA tab3
     #8: 30001 65 0.1696150 tab3
     #9: 50001 61 0.0708960 tab3
    

    【讨论】:

    • 为什么 '=' 在这里不起作用: lapply(myfiles,within, V3 = ifelse(V2 >50, V3, NA)) ?它抛出错误: eval 中的错误(expr,envir,enclos):缺少参数,没有默认值
    • @rnso 可能这个链接给出了一些想法r4stats.com/2013/01/22/comparing-tranformation-styles
    【解决方案3】:

    这似乎比应有的困难,因为您使用的是数据框列表而不是单个数据框。您可以在dplyr 中使用rbind_all 将所有数据帧合并为一个。

    library(dplyr)
    # Some variable renaming for clarity:
    # myfiles now refers to the file names; mydata now contains the data
    myfiles <- list.files(pattern="tab", full.names=TRUE) 
    mydata <- lapply(myfiles, read.table, skip="#")
    
    # Get the number of rows in each data frame
    n_rows <- vapply(mydata, nrow, integer(1))
    # Combine the list of data frames into a single data frame
    all_mydata <- rbind_all(mydata)
    # Add an identifier to see which data frame the row came from.
    all_mydata$file <- rep(myfiles, each = n_rows)
    
    # Now update column 3
    is.na(all_mydata$V3) <- all_mydata$V2 < 50
    

    【讨论】:

      【解决方案4】:

      您可以使用lapplytransform/within。有三种可能:

      • a) ifelse

        lapply(myfiles, transform, V3 = ifelse(V2 > 50, V3, NA))
        
      • b) 数学运算符(可能更有效)

        lapply(myfiles, transform, V3 = NA ^ (V2 <= 50) * V3)
        
      • c) is.na&lt;-

        lapply(myfiles, within, is.na(V3) <- V2 < 50)
        

      结果

      [[1]]
           V1 V2        V3
      1 10001 33        NA
      2 30001 65 0.0991478
      3 50001 54 0.1564400
      
      [[2]]
           V1 V2       V3
      1 10001 62 0.085526
      2 30001 74 0.153664
      3 50001 71 0.102096
      
      [[3]]
           V1 V2       V3
      1 10001 49       NA
      2 30001 65 0.169615
      3 50001 61 0.070896
      

      【讨论】:

      • 对于这 3 种可能性的处理时间是否有任何偏好?我要使用 transform+ifelse (a),因为它对我来说似乎更具可读性。谢谢
      • @PedroA 我更喜欢第三种解决方案。 ifelse 版本显然是效率最低的版本。
      • 为什么 ' 50, V3, NA)) ?它只显示原始 myfiles,没有任何 NA 值。
      • @rnso 你必须在transform函数中使用=而不是&lt;-
      猜你喜欢
      • 2015-10-28
      • 2021-08-28
      • 2015-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多