将月份“因素”分类为 data.frame 中的时间段
categorize month `factor` to time periods in data.frame
更新(下面的初始问题)
感谢 @akrun and @ulfelder 我意识到我最初的例子不够复杂,因为我只有一年的时间。涵盖几年的数据可能更真实,对其他人更有用。
换句话说,我的数据是,
df <- structure(list(yr_month = structure(1:7, .Label = c("2014-1", "2014-2",
"2014-3", "2015-4", "2016-4", "2016-6", "2017-7"), class = "factor"),
a = c(4.14, 2.83, 3.71, 4.15, 4.63, 4.91, 5.31), b = c(4.25,
3.5, 3.5, 3.5, 3.5, 3.5, 5)), .Names = c("yrQ", "a", "b"
), row.names = c(NA, 7L), class = "data.frame")
df
# yrQ a b
# 1 2014-1 4.14 4.25
# 2 2014-2 2.83 3.50
# 3 2014-3 3.71 3.50
# 4 2015-4 4.15 3.50
# 5 2016-4 4.63 3.50
# 6 2016-6 4.91 3.50
# 7 2017-7 5.31 5.00
我想创建一个涵盖 2014 年 3 月之前、2014-3、2014-3 和 2016-4 之间以及 2016-4 之后的类别。所以我得到了这样的东西,
# yr.cat yrQ a b
# 1 "A" 2014-1 4.14 4.25
# 2 "A" 2014-2 2.83 3.50
# 3 "B" 2014-3 3.71 3.50
# 4 "B" 2015-4 4.15 3.50
# 5 "B" 2016-4 4.63 3.50
# 6 "C" 2016-6 4.91 3.50
# 7 "C" 2017-7 5.31 5.00
初始问题
假设我有这样的数据集,
df <- structure(list(yr_month = structure(1:7, .Label = c("2016-1", "2016-2",
"2016-3", "2016-4", "2016-5", "2016-6", "2016-7"), class = "factor"),
a = c(4.14, 2.83, 3.71, 4.15, 4.63, 4.91, 5.31), b = c(4.25,
3.5, 3.5, 3.5, 3.5, 3.5, 5)), .Names = c("yrQ", "a", "b"
), row.names = c(NA, 7L), class = "data.frame")
df
# yrQ a b
# 1 2016-1 4.14 4.25
# 2 2016-2 2.83 3.50
# 3 2016-3 3.71 3.50
# 4 2016-4 4.15 3.50
# 5 2016-5 4.63 3.50
# 6 2016-6 4.91 3.50
# 7 2016-7 5.31 5.00
现在,我可以使用ifelse()
对a
数值变量进行分类。像这样,
df$a.cat <- ifelse(df$a < 3.8, c("tiny"), ifelse(df$a < 4.8, c("medium"), c("huge")) )
df
# yrQ a b a.cat
# 1 2016-1 4.14 4.25 medium
# 2 2016-2 2.83 3.50 tiny
# 3 2016-3 3.71 3.50 tiny
# 4 2016-4 4.15 3.50 medium
# 5 2016-5 4.63 3.50 medium
# 6 2016-6 4.91 3.50 huge
# 7 2016-7 5.31 5.00 huge
但是,如果我想创建一个表示某些时间段的变量怎么办。比如说 2016 年 3 月 2016-3
之前、2016-3
和 2016-5
之间以及 2016-5
之后。我意识到我可以将数据转换为 ts
,然后使用 window()
将其剪切,然后将其放回原处,但是没有更聪明的方法来使用 if else on yrQ
?
这是我想去的地方,
yr.cat yrQ a b
1 "A" 2016-1 4.14 4.25
2 "A" 2016-2 2.83 3.50
3 "B" 2016-3 3.71 3.50
4 "B" 2016-4 4.15 3.50
5 "B" 2016-5 4.63 3.50
6 "C" 2016-6 4.91 3.50
7 "C" 2016-7 5.31 5.00
我们可以在从 'yrQ'
中提取月份子字符串后使用 cut
df$yr.cat <- cut(as.numeric(sub(".*-", "", df$yrQ)),
breaks = c(-Inf,2, 5, Inf), labels = LETTERS[1:3])
df$yr.cat
#[1] A A B B B C C
#Levels: A B C
基于更新的示例
cut(as.numeric(sub("-", ".", df$yrQ)),
breaks = c(-Inf, 2014.2, 2016.5, Inf), labels = LETTERS[1:3])
#[1] A A B B B C C
#Levels: A B C
问题中提供的输入数据似乎与数据结构中不同点的 yrQ
和 yr_month
引用同一列不一致。我们假设这个输入是相同的,只是我们用 yr_month
替换了 .Names
中的 yrQ
(暗示 year/qtr 而不是 year/month)与list()
.
中显示的同名一致
df <- structure(list(yr_month = structure(1:7, .Label = c("2014-1", "2014-2",
"2014-3", "2015-4", "2016-4", "2016-6", "2017-7"), class = "factor"),
a = c(4.14, 2.83, 3.71, 4.15, 4.63, 4.91, 5.31), b = c(4.25,
3.5, 3.5, 3.5, 3.5, 3.5, 5)), .Names = c("yr_month", "a", "b"
), row.names = c(NA, 7L), class = "data.frame")
问题中的示例数据只有一位数字的月份,但我们假设它需要工作,即使混合了一位数字(一月、二月、...、九月)和两位数字(十月、十一月) , 十二月) 个月.
1) 转换为 "yearmon"
class(如果我们需要对该列做其他事情,这也可能有帮助)并与每个切割点并将它们相加,给出一个数字 0、1 或 2,分别代表之前、之间和之后。然后加 1 并将其用作类别名称向量的下标(此处为 LETTERS
)。只需添加更多比较项,就可以将其扩展到更多类别。
library(zoo)
df$yr_month <- as.yearmon(df$yr_month) ##
transform(df, yr.cat = LETTERS[ (yr_month >= "2014-03") + (yr_month > "2016-04") + 1])
给予:
yr_month a b yr.cat
1 Jan 2014 4.14 4.25 A
2 Feb 2014 2.83 3.50 A
3 Mar 2014 3.71 3.50 B
4 Apr 2015 4.15 3.50 B
5 Apr 2016 4.63 3.50 B
6 Jun 2016 4.91 3.50 C
7 Jul 2017 5.31 5.00 C
2) 要在没有任何包的情况下执行此操作,请将 (1) 中标记为 ## 的行更改为下面的代码行。在这里,我们将 yr_month
转换为 "Date"
class,然后删除其字符表示的日部分。这为月份保留了 2 位数字,以便 1 位和 2 位月份之间的比较可以正常进行。 (在 (1) "yearmon"
class 中自动处理。)
df$yr_month <- sub("...$", "", as.Date(paste0(df$yr_month, -1)))
已修改进行了多次修改。
更新(下面的初始问题)
感谢 @akrun and @ulfelder 我意识到我最初的例子不够复杂,因为我只有一年的时间。涵盖几年的数据可能更真实,对其他人更有用。
换句话说,我的数据是,
df <- structure(list(yr_month = structure(1:7, .Label = c("2014-1", "2014-2",
"2014-3", "2015-4", "2016-4", "2016-6", "2017-7"), class = "factor"),
a = c(4.14, 2.83, 3.71, 4.15, 4.63, 4.91, 5.31), b = c(4.25,
3.5, 3.5, 3.5, 3.5, 3.5, 5)), .Names = c("yrQ", "a", "b"
), row.names = c(NA, 7L), class = "data.frame")
df
# yrQ a b
# 1 2014-1 4.14 4.25
# 2 2014-2 2.83 3.50
# 3 2014-3 3.71 3.50
# 4 2015-4 4.15 3.50
# 5 2016-4 4.63 3.50
# 6 2016-6 4.91 3.50
# 7 2017-7 5.31 5.00
我想创建一个涵盖 2014 年 3 月之前、2014-3、2014-3 和 2016-4 之间以及 2016-4 之后的类别。所以我得到了这样的东西,
# yr.cat yrQ a b
# 1 "A" 2014-1 4.14 4.25
# 2 "A" 2014-2 2.83 3.50
# 3 "B" 2014-3 3.71 3.50
# 4 "B" 2015-4 4.15 3.50
# 5 "B" 2016-4 4.63 3.50
# 6 "C" 2016-6 4.91 3.50
# 7 "C" 2017-7 5.31 5.00
初始问题
假设我有这样的数据集,
df <- structure(list(yr_month = structure(1:7, .Label = c("2016-1", "2016-2",
"2016-3", "2016-4", "2016-5", "2016-6", "2016-7"), class = "factor"),
a = c(4.14, 2.83, 3.71, 4.15, 4.63, 4.91, 5.31), b = c(4.25,
3.5, 3.5, 3.5, 3.5, 3.5, 5)), .Names = c("yrQ", "a", "b"
), row.names = c(NA, 7L), class = "data.frame")
df
# yrQ a b
# 1 2016-1 4.14 4.25
# 2 2016-2 2.83 3.50
# 3 2016-3 3.71 3.50
# 4 2016-4 4.15 3.50
# 5 2016-5 4.63 3.50
# 6 2016-6 4.91 3.50
# 7 2016-7 5.31 5.00
现在,我可以使用ifelse()
对a
数值变量进行分类。像这样,
df$a.cat <- ifelse(df$a < 3.8, c("tiny"), ifelse(df$a < 4.8, c("medium"), c("huge")) )
df
# yrQ a b a.cat
# 1 2016-1 4.14 4.25 medium
# 2 2016-2 2.83 3.50 tiny
# 3 2016-3 3.71 3.50 tiny
# 4 2016-4 4.15 3.50 medium
# 5 2016-5 4.63 3.50 medium
# 6 2016-6 4.91 3.50 huge
# 7 2016-7 5.31 5.00 huge
但是,如果我想创建一个表示某些时间段的变量怎么办。比如说 2016 年 3 月 2016-3
之前、2016-3
和 2016-5
之间以及 2016-5
之后。我意识到我可以将数据转换为 ts
,然后使用 window()
将其剪切,然后将其放回原处,但是没有更聪明的方法来使用 if else on yrQ
?
这是我想去的地方,
yr.cat yrQ a b
1 "A" 2016-1 4.14 4.25
2 "A" 2016-2 2.83 3.50
3 "B" 2016-3 3.71 3.50
4 "B" 2016-4 4.15 3.50
5 "B" 2016-5 4.63 3.50
6 "C" 2016-6 4.91 3.50
7 "C" 2016-7 5.31 5.00
我们可以在从 'yrQ'
中提取月份子字符串后使用cut
df$yr.cat <- cut(as.numeric(sub(".*-", "", df$yrQ)),
breaks = c(-Inf,2, 5, Inf), labels = LETTERS[1:3])
df$yr.cat
#[1] A A B B B C C
#Levels: A B C
基于更新的示例
cut(as.numeric(sub("-", ".", df$yrQ)),
breaks = c(-Inf, 2014.2, 2016.5, Inf), labels = LETTERS[1:3])
#[1] A A B B B C C
#Levels: A B C
问题中提供的输入数据似乎与数据结构中不同点的 yrQ
和 yr_month
引用同一列不一致。我们假设这个输入是相同的,只是我们用 yr_month
替换了 .Names
中的 yrQ
(暗示 year/qtr 而不是 year/month)与list()
.
df <- structure(list(yr_month = structure(1:7, .Label = c("2014-1", "2014-2",
"2014-3", "2015-4", "2016-4", "2016-6", "2017-7"), class = "factor"),
a = c(4.14, 2.83, 3.71, 4.15, 4.63, 4.91, 5.31), b = c(4.25,
3.5, 3.5, 3.5, 3.5, 3.5, 5)), .Names = c("yr_month", "a", "b"
), row.names = c(NA, 7L), class = "data.frame")
问题中的示例数据只有一位数字的月份,但我们假设它需要工作,即使混合了一位数字(一月、二月、...、九月)和两位数字(十月、十一月) , 十二月) 个月.
1) 转换为 "yearmon"
class(如果我们需要对该列做其他事情,这也可能有帮助)并与每个切割点并将它们相加,给出一个数字 0、1 或 2,分别代表之前、之间和之后。然后加 1 并将其用作类别名称向量的下标(此处为 LETTERS
)。只需添加更多比较项,就可以将其扩展到更多类别。
library(zoo)
df$yr_month <- as.yearmon(df$yr_month) ##
transform(df, yr.cat = LETTERS[ (yr_month >= "2014-03") + (yr_month > "2016-04") + 1])
给予:
yr_month a b yr.cat
1 Jan 2014 4.14 4.25 A
2 Feb 2014 2.83 3.50 A
3 Mar 2014 3.71 3.50 B
4 Apr 2015 4.15 3.50 B
5 Apr 2016 4.63 3.50 B
6 Jun 2016 4.91 3.50 C
7 Jul 2017 5.31 5.00 C
2) 要在没有任何包的情况下执行此操作,请将 (1) 中标记为 ## 的行更改为下面的代码行。在这里,我们将 yr_month
转换为 "Date"
class,然后删除其字符表示的日部分。这为月份保留了 2 位数字,以便 1 位和 2 位月份之间的比较可以正常进行。 (在 (1) "yearmon"
class 中自动处理。)
df$yr_month <- sub("...$", "", as.Date(paste0(df$yr_month, -1)))
已修改进行了多次修改。