【问题标题】:Group data frame columns by their dates (which comprise column titles) and summarize instances of 1s and 0s in R按日期(包括列标题)对数据框列进行分组,并总结 R 中 1 和 0 的实例
【发布时间】:2017-12-12 20:04:48
【问题描述】:

我遇到了一些烦人的编码问题,非常感谢您的帮助。

以下是一些示例数据:

ID     "2013-03-20"    "2013-04-09"    "2013-04-11"    "2013-04-17"    
5167f            0               0               0               1  
1214m            0               0               0               0  
1844f            0               1               1               0  
2113m            0               0               1               1  

问题来了:请注意示例数据框的列名如何包含日期,并且某些日期可能彼此接近。 ID 列是观察的简单唯一标识符。

这是我的目标:

(1) 我希望能够首先根据它们是否在 2 周(或 14 天)范围内(即由从 @ 开始的 2 周增量定义)对列进行分组987654323@ 直到"2016-12-20");因此,如果它们确实在相同的范围内,它们将收到相同的标识符(对于新的数据框;例如,Period1 用于在 "2013-03-20""2013-04-03" 之间的任何日期)。

(2) 将所有日期列分配给特定时期后,我想按以下方式汇总每个时期的单元格数据(0 和 1):如果任何1 出现在特定时期对于个人(完全),那么该个人将在整个期间收到 1(此外,如果个人在该期间只有 0,那么它将在该单个期间收到 0)。

(3) 定义此工作流程后,我想根据月份代码按季节和年份对日期进行分组(例如,WinterYYYY = 十二月、一月、二月;SpringYYYY = 三月、四月、五月; SummerYYYY = 六月、七月、八月;FallYYYY = 九月、十月、十一月)生成新的数据框。

总而言之,手动演示产品:

(目标 1 和 2 的最终产品;即仅针对示例数据中的前两列 [括号中的日期范围仅供参考])

ID     Period1 ("2013-03-20" - "2013-04-03")        Period2 ("2013-04-04" - "2013-04-18")      
5167f                                    0                                 1    
1214m                                    0                                 0    
1844f                                    0                                 1    
2113m                                    0                                 1    

(目标 2 和 3 的最终产品;即样本数据中的所有列[括号中的月份范围仅供参考])

ID                Spring2013  (March - May)    
5167f                                    1  
1214m                                    0  
1844f                                    1  
2113m                                    1

也许,dplyr 包中的某些内容可能有用,但我不太确定。

提前感谢您的帮助。请随时提出任何后续问题以进行澄清。

-AD-

【问题讨论】:

  • 如果您正在使用该列,为什么不转置DateFrame

标签: r date merge dplyr grouping


【解决方案1】:

这是一个使用来自tidyverse 的函数的解决方案。

# Load packages
library(tidyverse)
library(data.table)
library(lubridate)

# Create example data frames
dt <- fread("ID     '2013-03-20'    '2013-04-09'    '2013-04-11'    '2013-04-17'    
5167f            0               0               0               1  
                 1214m            0               0               0               0  
                 1844f            0               1               1               0  
                 2113m            0               0               1               1")

关键是准备一个表格,显示日期和分组变量之间的关联,例如期间、月份或季节。在本例中,dt_merge 就是这样的表。

dt_merge <- data_frame(
  # Create a column showing the beginning date
  Date1 = seq(from = ymd("2013-03-20"), to = ymd("2016-12-20"), by = "2 weeks")) %>%
  # Create  a column showing the end date of each period
  mutate(Date2 = lead(Date1)) %>%
  # Adjust Date1
  mutate(Date1 = if_else(Date1 == ymd("2013-03-20"), Date1, Date1 + 1)) %>%
  # Remove the last row
  drop_na(Date2) %>%
  # Create date list
  mutate(Dates = map2(Date1, Date2, function(x, y){ seq(x, y, by = "day") })) %>%
  unnest() %>%
  # Create Group ID
  mutate(RunID = group_indices_(., dots. = c("Date1", "Date2"))) %>%
  # Create Period ID
  mutate(Period = paste0("Period", RunID)) %>%
  # Add a column showing Month
  mutate(Month = month(Dates)) %>%
  # Add a column showing Year
  mutate(Year = year(Dates)) %>%
  # Add a column showing season
  mutate(Season = case_when(
    Month %in% 3:5            ~ "Spring",
    Month %in% 6:8            ~ "Summer",
    Month %in% 9:11           ~ "Fall",
    Month %in% c(12, 1, 2)    ~ "Winter",
    TRUE                      ~ NA_character_
  )) %>%
  # Combine Season and Year
  mutate(SeasonYear = paste0(Season, Year)) %>%
  select(-Date1, -Date2, -RunID)

在这一步之后,生成你想要的输出就变得很容易了。在此示例中,dt3 是第一个最终产品。 dt4 是第二个产品。

dt2 <- dt %>%
  # Reshape the data frame
  gather(Date, Value, -ID) %>%
  # Convert Date to date class
  mutate(Date = ymd(Date)) %>%
  # Join dt_merge
  left_join(dt_merge, by = c("Date" = "Dates"))

# Product 1
dt3 <- dt2 %>%
  group_by(ID, Period) %>%
  summarise(Value = max(Value)) %>%
  spread(Period, Value)

# Product 2
dt4 <- dt2 
  group_by(ID, SeasonYear) %>%
  summarise(Value = max(Value)) %>%
  spread(SeasonYear, Value) 

【讨论】:

  • 感谢您的全面回答,@ycw。我还没有完全测试它,但是在第一次尝试之后,我在dt_merge 部分遇到了一个未解决的错误could not find function 'if_else',尽管我已经调用了dplyr 库。你知道我该如何纠正这个问题吗?
  • if_else 在 dplyr 中 0.7.1 (rdocumentation.org/packages/dplyr/versions/0.7.1/topics/if_else)。将您的 dplyr 更新到最新版本可能会有所帮助。否则我不知道。
  • 谢谢,@ycw。这就是解决方案。我的dplyr 版本是从过期的快照存储库安装的。您的回答提供了精确的解决方案。非常感谢!
  • 我很乐意提供帮助。如果这个答案有用,请在左上角标记绿色符号接受它。
  • 关于为什么在代码的连接步骤之后所有可能的句点都不会填充输出的任何想法?我最近将您的解决方案调整为按 1 周间隔对日期进行分组,但我注意到 left_join 之后的最终输出(例如,对于 dt3)不包括新的完整时间段的所有可能的周间隔(即 1-145) 2013 年 3 月 20 日至“2015 年 12 月 31 日”。如果我的描述没有意义,我明天可以发布代码,以帮助澄清这一点。
【解决方案2】:

请先把你的数据整理好。

library(dplyr)
data <- gather(data, date, value, -ID )

那就试试吧:

library(lubridate)
data$date  <- ymd(data$date)
data <-  mutate(data, period = date - as.Date("2013-03-20")) #difference in days
data <- mutate(data, period2 = ceiling(as.numeric(data$period)/14))
data$period2 <- ifelse(data$period2 == 0, 1, data$period2) #change period 0 to period 1

newdat <- data %>% 
          group_by(ID, period2) %>%
          summarise(result = ifelse(sum(value)>0, 1, 0))

使用spread() 函数改回原始格式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-01
    相关资源
    最近更新 更多