我想创建 4 个虚拟变量,将每个季度称为 Q1、Q2、Q3、Q4,这将取决于日期格式的销售月份。
像这样:
Date Q1 Q2 Q3 Q4
01/01/2017 1 0 0 0
02/01/2017 0 1 0 0
03/01/2017 0 0 1 0
04/01/2017 0 0 0 1
我尝试使用lubridate包使用month(Date(提取销售月份,然后尝试在这些行上创建虚拟变量Q1,Q2,Q3,Q4(不完全相同的代码,但尝试使用此逻辑来创建变量(:
df$Q1 <- ifelse(month(Date) = *"first month of every quarter"*,1,0)
df$Q2 <- ifelse(month(Date) = *"second month of every quarter"*,1,0)
df$Q3 <- ifelse(month(Date) = *"third month of every quarter"*,1,0)
df$Q4 <- ifelse(month(Date) = *"fourth month of every quarter"*,1,0)
但是这种方法无法获得如上所述的矩阵。
请帮助完成相同的工作,或者如果有更聪明的方法可以完成此操作,请告诉我。
这是使用因子和model.matrix
的基本 R 方法。最棘手的部分是正确设置季度因子变量的月份。
假设我们从如下所示的字符向量开始。首先,转换为日期向量。
dates<- as.Date(dates, "%m/%d/%Y")
现在,将其放入 data.frame 并使用factor
添加一个 Quarter 变量。
dat <- data.frame(Date=dates,
mnthQrtr=factor(as.integer(format(dates, "%m")) %% 3,
levels=c(1:2, 0), labels=c(paste0("MQ", c(1:3)))))
在这里,模运算符返回值 0 到 3,其中 3 对应于季度中的第四个月,因此 levels 参数必须考虑到这一点。
现在,使用model.matrix
创建二进制变量,并使用cbind
将它们固定在 .
dat <- cbind(dat, model.matrix(~mnthQrtr-1, dat))
这返回
dat
Date mnthQrtr mnthQrtrMQ1 mnthQrtrMQ2 mnthQrtrMQ3
1 2017-01-01 MQ1 1 0 0
2 2017-02-01 MQ2 0 1 0
3 2017-03-01 MQ3 0 0 1
4 2017-04-01 MQ1 1 0 0
数据
dates <- c("01/01/2017", "02/01/2017", "03/01/2017", "04/01/2017")
我们可以使用tidyverse
library(tidyverse)
df1 %>%
mutate(Qs = paste0("Q", month(mdy(Date))), ind = 1) %>%
spread(Qs, ind, fill = 0)
# Date Q1 Q2 Q3 Q4
#1 01/01/2017 1 0 0 0
#2 02/01/2017 0 1 0 0
#3 03/01/2017 0 0 1 0
#4 04/01/2017 0 0 0 1
数据
df1 <- structure(list(Date = c("01/01/2017", "02/01/2017", "03/01/2017",
"04/01/2017")), .Names = "Date", row.names = c(NA, -4L),
class = "data.frame")
编辑:这个问题没有明确说明,OP的意图有不同的解释。现在,OP澄清了他在下面的第二个答案之后。
答案 1
问题从这句话开始:我想创建 4 个虚拟变量,将每个季度称为 Q1、Q2、Q3、Q4,这将取决于日期格式的销售月份加上一个示例矩阵。这可以解释为OP想要确定给定日期所属的季度,并以宽格式"以图形方式"显示此季度。
这可以使用dcast()
函数重塑和quarter()
函数从lubridate
实现:
# create sample data
DF <- data.frame(Date = seq(as.Date("2017-01-01"), length.out = 4, by = "3 months"))
# reshape
data.table::dcast(DF, Date ~ paste0("Q", lubridate::quarter(DF$Date)), length,
value.var = "Date")
Date Q1 Q2 Q3 Q4 1 2017-01-01 1 0 0 0 2 2017-04-01 0 1 0 0 3 2017-07-01 0 0 1 0 4 2017-10-01 0 0 0 1
dcast()
功能可从两个软件包获得:reshape2
和data.table
。
答案 2
如果 OP 要求每个季度内的月份编号,即第 1 个月、第 2 个月或第 3 个月,这里有一个替代解决方案,它使用toOrdinal
包将基数转换为序数
DF <- data.frame(Date = seq(as.Date("2017-01-01"), length.out = 12, by = "1 months"))
month_in_quarter <- function(x)
sprintf("%s_M_in_Qtr", sapply((month(x) - 1) %% 3 + 1, toOrdinal::toOrdinal))
data.table::dcast(DF, Date ~ month_in_quarter(Date), length, value.var = "Date")
Date 1st_M_in_Qtr 2nd_M_in_Qtr 3rd_M_in_Qtr 1 2017-01-01 1 0 0 2 2017-02-01 0 1 0 3 2017-03-01 0 0 1 4 2017-04-01 1 0 0 5 2017-05-01 0 1 0 6 2017-06-01 0 0 1 7 2017-07-01 1 0 0 8 2017-08-01 0 1 0 9 2017-09-01 0 0 1 10 2017-10-01 1 0 0 11 2017-11-01 0 1 0 12 2017-12-01 0 0 1
另一个使用伟大的dummies
包来创建虚拟变量的选项。只需使用zoo
包创建"季度"列。
加载包:
require(dummies)
require(zoo)
创建一些测试数据:
df<-data.frame(date =seq(as.Date("2017/1/1"), as.Date("2017/4/1"), "months"))
创建新的季度列,说明日期属于哪个季度:
df$Quarter<-format(as.yearqtr(df$date), "Q%q")
为分类变量创建虚拟变量:
df<-dummy.data.frame(df, sep="_")
调整列名称以与问题保持一致:
colnames(df)<-gsub("Quarter_", "", colnames(df))
使用 'dt' 和 'get_dummies':
步骤:
- 在包含日期的列上使用"dt.quarter"。
- 在步骤 1 中创建的列上使用"get_dummies"。
例:
数据:
df = pd.DataFrame(pd.date_range(start = '2017', periods = 4, freq = 'Q'), columns = ['Dates'])
- 新建列
df['Quarter'] = df['Dates'].dt.quarter
- 傻瓜
pd.get_dummies(df, columns = ['Quarter'])