将仅包含ISO周的数据集聚合成月份

3

我的数据存储在一个类似于以下结构的数据帧中:

df2 <- data.frame(Year = c("2007"), Week = c(1:12), Measurement = c(rnorm(12, mean = 4, sd = 1)))

很不幸,我没有每个测量的完整日期(例如缺少天数),只有年份和周数(这些是ISO周)。

现在我想将一个月的中位数测量值(例如特定年份每月的每周测量值)汇总到一个新列“Months”中。我没有找到一种方便的方法来做到这一点,而不需要测量的确切日期。非常感谢任何意见!

4个回答

5
当需要将一周分配到一个月中时,可以应用一年中第一周的规则,尽管ISO 8601并不考虑这种情况。(来源于Wikipedia)
例如,2007年的第5周属于二月份,因为第5周的星期四是二月份的第一天。
我使用了data.tableISOweek包。请查看示例,了解如何计算一周所属的月份,然后您可以按月进行任何聚合。
require(data.table)
require(ISOweek)

df2 <- data.table(Year = c("2007"), Week = c(1:12),
                  Measurement = c(rnorm(12, mean = 4, sd = 1)))

# Generate Thursday as year, week of the year, day of week according to ISO 8601
df2[, thursday_ISO := paste(Year, sprintf("W%02d", Week), 4, sep = "-")]

# Convert Thursday to date format
df2[, thursday_date := ISOweek2date(thursday_ISO)]

# Compute month
df2[, month := format(thursday_date, "%m")]
df2

Uwe提出计算年月字符串的建议。

# Compute year-month
df2[, yr_mon := format(ISOweek2date(sprintf("%s-W%02d-4", Year, Week)), "%Y-%m")]
df2

最后,您可以通过将中位数作为一列添加到新表中或进行聚合来完成操作。
df2[, median(Measurement), by = yr_mon]

df2[, median := median(Measurement), by = yr_mon]
df2

1
谢谢,这对我很有帮助!我选择了你的答案,因为它更适合在我的数据中实施其他年份。 - Roggan
3
每周的星期四所在的月份是一个很好的选择。这确保了整个星期被分配到大部分天数属于的那个月。然而,为了保险起见,我建议创建一个年-月字符串并简化代码,即 yr_mon := format(ISOweek2date(sprintf("%i-W%02i-4", Year, Week))) - Uwe
2
刚刚注意到您没有包含聚合部分。因此,完整的答案应该是 library(data.table); setDT(df2)[, median(Measurement), by = .(Yr_Mon = format(ISOweek::ISOweek2date(sprintf("%s-W%02d-4", Year, Week)), "%Y-%m"))] - Uwe
@Uwe,谢谢!刚刚注意到你是ISOweek的作者。非常感谢你提供这个包! - djhurio
非常抱歉我花了这么长时间才接受答案。非常感谢你的解释!! - Roggan

2
如果我理解正确,您不知道确切的日期,只知道一周的周数和年份。我的答案以一年的第一天作为起始日期,然后根据此计算一周的间隔。您可能可以进一步完善这个答案。
基于mnel的回答,使用lubridate包
library(lubridate)

# Prepare week, month, year information ready for the merge
# Make sure you have all the necessary dates
wmy <- data.frame(Day = seq(ymd('2007-01-01'),ymd('2007-04-01'), 
                            by = 'weeks')) 
wmy <- transform(wmy, 
                 Week = isoweek(Day),
                 Month = month(Day),
                 Year = isoyear(Day))

# Merge this information with your data
merge(df2, wmy, by = c("Year", "Week"))

   Year Week Measurement        Day Month
1  2007    1    3.704887 2007-01-01     1
2  2007   10    1.974533 2007-03-05     3
3  2007   11    4.797286 2007-03-12     3
4  2007   12    4.291169 2007-03-19     3
5  2007    2    4.305010 2007-01-08     1
6  2007    3    3.374982 2007-01-15     1
7  2007    4    3.600008 2007-01-22     1
8  2007    5    4.315184 2007-01-29     1
9  2007    6    4.887142 2007-02-05     2
10 2007    7    4.155411 2007-02-12     2
11 2007    8    4.711943 2007-02-19     2
12 2007    9    2.465862 2007-02-26     2

感谢您提供这么详细的答案!它确实非常有效,但是我选择接受另一个答案,因为它在我的代码中稍后使用 ISOweek 包时提供了更多的灵活性。 - Roggan
请注意,基于ISO周的年份可能与日历年份不同。例如,ISOweek :: ISOweek(“2010-01-01”)返回“2009-W53”,ISOweek :: ISOweek(“2011-01-01”)返回“2010-W52”。请参阅?strptime中的%G%g。有关定义一年中的周的不同约定,请参见[此答案](https://dev59.com/FVcO5IYBdhLWcg3wmSuR#45587644)。 - Uwe
1
@Uwe 谢谢。我知道了, lubridate :: isoweek(“2010-01-01”) 返回 53lubridate :: year(“2010-01-01”) 返回 2010。 我应该使用 lubridate :: isoyear(“2010-01-01”),它会返回 2009 - Paul Rougieux

1
使用 dplyr,您可以尝试以下操作:
require(dplyr)

df2 %>% mutate(Date = as.Date(paste("1", Week, Year, sep = "-"), format = "%w-%W-%Y"),
            Year_Mon = format(Date,"%Y-%m")) %>% group_by(Year_Mon) %>%
            summarise(result = median(Measurement))

正如@djhrio指出的那样,星期四被用来确定一个月中的周数。所以只需在上面的代码中将paste("1",替换为paste("4",即可。

2
OP指出他正在使用ISO周。因此,使用年份周的英国定义“% W”和从星期日开始编号的工作日“% w”(ISO周从星期一开始)的答案是明显错误的(请参见“?strptime”)。还要注意,属于ISO周的年份可能与日历年份不同。请参阅此答案以讨论不同的约定。 - Uwe
3
注意,这个解决方案适用于 2007 年,但是在 2008 年和其他当年的 1 月 1 日是周二、周三或周四时将不起作用,因为使用“%W”对周数进行编号不符合 ISO 标准。根据“strptime”帮助文档:“%W:一年中的周数,使用周一作为第一天(通常年初的第一个星期一为第一周的第一天)进行十进制编号。” - djhurio
@Uwe和djhurio,我不知道。感谢你们的意见! - count

0

在dplyr中,这可以相对简单地完成。

library(dplyr)

df2 %>% 
  mutate(Month = rep(1:3, each = 4)) %>% 
  group_by(Month) %>% 
  summarise(MonthlyMedian = stats::median(Measurement))

基本上,添加一个新列来定义您的月份。我假设因为你没有天数,你将每个月分配4周? 然后,您只需按照您的月变量进行分组并计算中位数。非常简单

希望这可以帮助到您


1
这是有问题的,因为2007年的第5周仍然在一月份。 - count
1
@count,实际上2007年的第5周在二月份,因为一周的月份是根据ISO标准中一周的星期四来定义的。2007-W05的星期四是2007-02-01。 - djhurio
@djhrio 很有意思,我不知道这一点。然而,在这种情况下,仅仅分配每个月的4周可能会产生不准确的结果。 - count
你会用什么方法来称呼你刚刚创建的第13个月呢? :-) 如果你每个月分配4周,而一年有52或53周,那么你最终将得到13个4周的时间段(加上1或2天)。在我看来,这太过简化了。 - Uwe
@Uwe,这个例子包含了12周的时间,但没有表明是否超过了一年,因此进行了超级简化。 - Quinn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接