如何将纪元分成年、月等
How to split epochs into year, month, etc
我有一个包含许多时间列的数据框。我想为年、月、日等的每个时间添加列。
这是我目前的情况:
library(dplyr)
library(lubridate)
times <- c(133456789, 143456789, 144456789 )
train2 <- data.frame(sent_time = times, open_time = times)
time_col_names <- c("sent_time", "open_time")
dt_part_names <- c("year", "month", "hour", "wday", "day")
train3 <- as.data.frame(train2)
dummy <- lapply(time_col_names, function(col_name) {
pct_times <- as.POSIXct(train3[,col_name], origin = "1970-01-01", tz = "GMT")
lapply(dt_part_names, function(part_name) {
part_col_name <- paste(col_name, part_name, sep = "_")
train3[, part_col_name] <- rep(NA, nrow(train3))
train3[, part_col_name] <- factor(get(part_name)(pct_times))
})
})
一切似乎都正常,除了从未创建或分配的列。确实提取了组件,并且分配成功且没有错误,但是 train3 没有任何新列。
当我在嵌套的 lapply 上下文之外调用它时,我已经检查过它是否有效:
train3[, "x"] <- rep(NA, nrow(train3))
在这种情况下,确实创建了列 x。
人们通常认为,与 for
循环相比,apply
系列在性能方面具有优势。但是 for
循环与 *apply()
系列循环之间最重要的区别是后者 设计为没有副作用 。
没有副作用有利于开发干净、结构良好且简洁的代码。如果 希望 有副作用,就会出现问题,这通常是代码设计有缺陷的症状。
这里有一个简单的例子来说明这一点:
myvector <- 10:1
sapply(myvector,prod,2)
# [1] 20 18 16 14 12 10 8 6 4 2
看起来是对的,对吧? sapply()
循环似乎将 myvec
的条目乘以二(当然,这个结果本来可以更容易地实现,但这只是讨论 *apply()
功能的一个简单示例) .
然而,经过检查,我们发现这个操作根本没有改变myvector
:
> myvector
# [1] 10 9 8 7 6 5 4 3 2 1
那是因为sapply()
没有副作用修改myvector
。在此示例中,sapply()
循环等效于命令 print(myvector*2)
,而不是 myvector <- myvector * 2
。 *apply()
循环 return 一个对象,但它们不会修改原始对象。
如果真的想改变循环内的对象,超赋值运算符<<-
是必要的,以修改循环范围外的对象。几乎不应该这样做,在这种情况下,事情变得非常难看。例如,下面的循环确实改变了我的 myvector
:
sapply(seq_along(myvector), function(x) myvector[x] <<- myvector[x]*2)
> myvector
# [1] 20 18 16 14 12 10 8 6 4 2
R 中的编码不应该是这样的。请注意,在这种更复杂的情况下,如果使用普通赋值运算符 <-
而不是 <<-
,则 myvector
保持不变。正确的做法是给*apply
编辑的对象赋值return,而不是在循环内修改它。
在 OP 描述的特定情况下,如果循环中的命令正确,变量 dummy
可能包含所需的输出。但是不能期望对象 train3
在循环内被修改。为此,<<-
运算符是必要的。
fortunes::fortune(212)
中提到的一句话可能总结了问题:
Basically R is reluctant to let you shoot yourself in the foot unless
you are really determined to do so. -- Bill Venables
我有一个包含许多时间列的数据框。我想为年、月、日等的每个时间添加列。
这是我目前的情况:
library(dplyr)
library(lubridate)
times <- c(133456789, 143456789, 144456789 )
train2 <- data.frame(sent_time = times, open_time = times)
time_col_names <- c("sent_time", "open_time")
dt_part_names <- c("year", "month", "hour", "wday", "day")
train3 <- as.data.frame(train2)
dummy <- lapply(time_col_names, function(col_name) {
pct_times <- as.POSIXct(train3[,col_name], origin = "1970-01-01", tz = "GMT")
lapply(dt_part_names, function(part_name) {
part_col_name <- paste(col_name, part_name, sep = "_")
train3[, part_col_name] <- rep(NA, nrow(train3))
train3[, part_col_name] <- factor(get(part_name)(pct_times))
})
})
一切似乎都正常,除了从未创建或分配的列。确实提取了组件,并且分配成功且没有错误,但是 train3 没有任何新列。
当我在嵌套的 lapply 上下文之外调用它时,我已经检查过它是否有效:
train3[, "x"] <- rep(NA, nrow(train3))
在这种情况下,确实创建了列 x。
人们通常认为,与 for
循环相比,apply
系列在性能方面具有优势。但是 for
循环与 *apply()
系列循环之间最重要的区别是后者 设计为没有副作用 。
没有副作用有利于开发干净、结构良好且简洁的代码。如果 希望 有副作用,就会出现问题,这通常是代码设计有缺陷的症状。
这里有一个简单的例子来说明这一点:
myvector <- 10:1
sapply(myvector,prod,2)
# [1] 20 18 16 14 12 10 8 6 4 2
看起来是对的,对吧? sapply()
循环似乎将 myvec
的条目乘以二(当然,这个结果本来可以更容易地实现,但这只是讨论 *apply()
功能的一个简单示例) .
然而,经过检查,我们发现这个操作根本没有改变myvector
:
> myvector
# [1] 10 9 8 7 6 5 4 3 2 1
那是因为sapply()
没有副作用修改myvector
。在此示例中,sapply()
循环等效于命令 print(myvector*2)
,而不是 myvector <- myvector * 2
。 *apply()
循环 return 一个对象,但它们不会修改原始对象。
如果真的想改变循环内的对象,超赋值运算符<<-
是必要的,以修改循环范围外的对象。几乎不应该这样做,在这种情况下,事情变得非常难看。例如,下面的循环确实改变了我的 myvector
:
sapply(seq_along(myvector), function(x) myvector[x] <<- myvector[x]*2)
> myvector
# [1] 20 18 16 14 12 10 8 6 4 2
R 中的编码不应该是这样的。请注意,在这种更复杂的情况下,如果使用普通赋值运算符 <-
而不是 <<-
,则 myvector
保持不变。正确的做法是给*apply
编辑的对象赋值return,而不是在循环内修改它。
在 OP 描述的特定情况下,如果循环中的命令正确,变量 dummy
可能包含所需的输出。但是不能期望对象 train3
在循环内被修改。为此,<<-
运算符是必要的。
fortunes::fortune(212)
中提到的一句话可能总结了问题:
Basically R is reluctant to let you shoot yourself in the foot unless you are really determined to do so. -- Bill Venables