我遇到了一个稍微复杂的问题。我有一个列表,其元素是数据帧。在这些数据帧中,保证只是两个特定命名列中的一个,它包含一个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的启发,尝试这种方法。
我意识到这是一个非常具体且有点复杂的问题,但如果有人知道如何继续,我会非常感谢任何帮助。
答案 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
的数据框列表中使用它,您不应该使用map
或mutate
来执行此操作< / 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