检查列表中每个元素中是否存在变量&条件变异

时间:2018-05-04 09:19:17

标签: r

我遇到了一个稍微复杂的问题。我有一个列表,其元素是数据帧。在这些数据帧中,保证只是两个特定命名列中的一个,它包含一个POSIXct变量。我需要在这些列上执行条件mutate,将它们从POSIXct格式化为'%d.%m.%Y'。请考虑这个例子:

library(lubridate)
rm(list = ls())

data <- list(a = tibble(ServiceStart = now(), y = 1),
             b = tibble(y = 1, BillDate = now()))

format(now(), format='%d.%m.%Y')

这可能看起来相当简单,但我希望这可以自动运行,例如我想要一个条件命令,它可以识别何时变异变量ServiceStart以及何时变异变量BillDate。到目前为止,我已经想出了这个:

if("ServiceStart" %in% names(data[[1]]))
{
  data %>%
    map(~mutate(., ServiceStart = format(data[[1]]$ServiceStart, format='%d.%m.%Y')))
} else {
  data %>%
    map(~mutate(., BillDate = format(data[[1]]$BillDate, format='%d.%m.%Y')))
}

这显然不起作用,因为data[[1]]告诉R仅定位列表的第一个数据帧,当我希望它单独为列表的每个元素执行时。

我认为有必要进一步说明我为什么要这样做: 为了简化/加速数据清理过程,我编写了一个简短的脚本,将给定文件夹中的所有Excel文件作为列表元素导入。然后,我使用map()从列中删除所有非字母数字字符。我使用lapply()将列表中的每个元素(所有数据帧)导出为已清理的Excel文件,从而完成此过程。这按预期工作:

library(tidyverse)
library(readxl)
library(writexl)
rm(list = ls())

dir.create(file.path("data", "cleaned")) #create "cleaned" folder if needed

filenames <- list.files("data", pattern="*.xlsx", full.names = TRUE) #extract file names

data_raw <- lapply(filenames, read_xlsx) #import all files as elements of list

data_edit <- data_raw %>%  #clean column from non-alphanumeric characters (main purpose!)
  map(~mutate(., InitiatorZSR = str_replace_all(InitiatorZSR, "[^[:alnum:]]", "")))

names(data_edit) <- substr(filenames, 6, 7) #name dataframes within list (usually a number)

files <- list.files("data", pattern="*.xlsx", full.names = F)
filenames <- paste("data/cleaned/", files, sep = "") #prepare export to "cleaned" folder

lapply(seq_along(data_edit), function(i){
  write_xlsx(data_edit[[i]], filenames[i])
}) #export all elements of list as excel files to folder "cleaned"

问题是导入文件中的'%d.%m.%Y'格式的日期列在使用readxl导入时不幸被解析为POSIXct,我无法禁用它。这使得文件无法使用。 因为这个脚本是用任何通用导入文件自动编写的,所以我不能手动定位和改变这些列,因为这会破坏目的。

我受到这篇文章Opening all files in a folder, and applying a function的启发,尝试这种方法。

我意识到这是一个非常具体且有点复杂的问题,但如果有人知道如何继续,我会非常感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

您正在寻找rapply

rapply(data,format,"POSIXct",how = "replace",format="%d---%m----%Y")#You can use any fromating you want
$a
# A tibble: 1 x 2
  ServiceStart        y
  <chr>           <dbl>
1 04---05----2018    1.

$b
# A tibble: 1 x 2
      y BillDate       
  <dbl> <chr>          
1    1. 04---05----2018

答案 1 :(得分:2)

我希望我能正确理解你的问题,这对你有帮助。

您可以将条件转换为函数,然后在lapply的数据框列表中使用它,您不应该使用mapmutate来执行此操作< / p>

library(lubridate)

data <- list(a = tibble(ServiceStart = now(), y = 1),
         b = tibble(y = 1, BillDate = now()))

format_col <- function(x) {
    if("ServiceStart" %in% names(x))
    {
        x$ServiceStart <- format(x$ServiceStart, format='%d.%m.%Y')
        x
    } else {
        x$BillDate <- format(x$BillDate, format='%d.%m.%Y')
        x
    }
}

data <- lapply(data, format_col)

data

# $a
# # A tibble: 1 x 2
#   ServiceStart     y
#   <chr>        <dbl>
# 1 04.05.2018    1.00

# $b
# # A tibble: 1 x 2
#   y BillDate  
#   <dbl> <chr>     
# 1  1.00 04.05.2018