Почему слияние не работает со значениями даты?

#r

#r

Вопрос:

Я пытаюсь объединить два фрейма данных по дате в R.
В первом фрейме данных записываются ежедневные температуры. В нем всего 28 строк, и даты не повторяются.

 head(df1)

Day MaxTemp MinTemp
2019-06-15 23.8 14.4
2019-06-16 24.9 11.7
2019-06-17 23.2 8.7
  

Второй фрейм данных записывает почасовые температуры, и поэтому содержит еще много строк с повторяющимися датами.

 head(df2)

Day Hour Temp
2019-06-15 14 22.8
2019-06-15 15 22.4
2019-06-15 16 21.9
  

Я хотел бы объединить данные, чтобы они выглядели примерно так:

 Day MaxTemp MinTemp Hour Temp 
2019-06-15 14 22.8 23.8 14.4
2019-06-15 15 22.4 23.8 14.4
2019-06-15 16 21.9 23.8 14.4
  

Но в итоге я получаю:

 allData <-merge(df1, df2, by="Day", all.y=T)

head(allData)

Day Hour Temp MaxTemp MinTemp
2019-06-15 14 22.8 NA NA
2019-06-15 15 22.4 NA NA
2019-06-15 16 21.9 NA NA
  

Или, если я попробую «all = T» в аргументах, я получу «Ошибка в x [[n]][i] <- значение[[n]] : замена имеет нулевую длину».

У кого-нибудь есть идеи, как я могу это исправить?

Редактировать:

 # head of df1

df1 <- structure(list(Day = structure(list(sec = c(0, 0, 0, 0, 0, 0), 
min = c(0L, 0L, 0L, 0L, 0L, 0L), hour = c(0L, 0L, 0L, 0L, 
0L, 0L), mday = 15:20, mon = c(5L, 5L, 5L, 5L, 5L, 5L), year = c(119L, 
119L, 119L, 119L, 119L, 119L), wday = c(6L, 0L, 1L, 2L, 3L, 
4L), yday = 165:170, isdst = c(1L, 1L, 1L, 1L, 1L, 1L), zone = c("CDT", 
"CDT", "CDT", "CDT", "CDT", "CDT"), gmtoff = c(NA_integer_, 
NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_
)), class = c("POSIXlt", "POSIXt")), Max = c(23.8, 24.9, 23.2, 22.4, 25.1, 24.4), Min = c(14.4, 11.7, 8.7, 8.7, 9.8, 10)), row.names = c(NA, 6L), class ="data.frame")

# head of df2
df2 <- structure(list(Date = structure(list(sec = c(0, 0, 0, 0, 0, 0), 
min = c(0L,30L, 0L, 30L, 0L, 30L), hour = c(14L, 14L, 15L, 15L, 16L, 16L),
mday = c(15L, 15L, 15L, 15L, 15L, 15L), mon = c(5L, 5L, 5L, 5L, 5L, 5L), 
year = c(119L, 119L, 119L, 119L, 119L, 119L), wday = c(6L, 6L, 6L, 6L, 6L,
6L), yday = c(165L,165L, 165L, 165L, 165L, 165L), isdst = c(1L, 1L, 1L, 1L,
1L, 1L), zone =c("CDT", "CDT", "CDT", "CDT", "CDT", "CDT"), gmtoff = 
c(NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_,
NA_integer_)),class = c("POSIXlt","POSIXt")), Temp = c(22.8, 22.4, 22.4, 
22.3,21.9, 21.3), Hour =c(14L, 14L, 15L, 15L, 16L, 16L), Day =
structure(c(18062,18062, 18062, 18062, 18062, 18062), class = "Date")), 
row.names= c(NA, 6L), class = "data.frame")
  

Комментарии:

1. Вместо того, чтобы делиться head(df1) , можете ли вы поделиться dput(head(df1)) ? Это расскажет нам, как именно закодированы ваши значения, и позволит нам скопировать / вставить код в R, чтобы запустить его самостоятельно.

2. Возможно, это обман чего-то, но это не обман этого вопроса: единственное упоминание class в этом вопросе и ответах на него содержится в сравнительном анализе, а не в качестве проблемы. В остальном вопрос касается правильного использования merge и ожидания его возвращаемого значения.

3. Приношу свои извинения, если я неправильно истолковал вопрос / статус dupe, это не было преднамеренным.

4. Я не открываю его назло тебе, акрун, просто указываю, почему я снова открыл его, несмотря на твое закрытие.

5. здесь также это не намеренно. Я обнаружил, что слияние является очень часто задаваемым вопросом. Поправьте меня, если я ошибаюсь. Обычно я не проверяю, кто написал ответ, прежде чем заменять тег

Ответ №1:

Подтверждено вашими dput выводами:

 class(df1$Day)
# [1] "POSIXlt" "POSIXt" 
class(df2$Day)
# [1] "Date"
  

Вам нужно преобразовать одно значение в класс другого, возможно, df1$Day это одно и то же время суток для каждого значения (в этом наборе), тогда вы можете сделать

 merge(df1, df2, by = "Day", all.y = TRUE)
#          Day Max Min                Date Temp Hour
# 1 2019-06-15  NA  NA 2019-06-15 14:00:00 22.8   14
# 2 2019-06-15  NA  NA 2019-06-15 14:30:00 22.4   14
# 3 2019-06-15  NA  NA 2019-06-15 15:00:00 22.4   15
# 4 2019-06-15  NA  NA 2019-06-15 15:30:00 22.3   15
# 5 2019-06-15  NA  NA 2019-06-15 16:00:00 21.9   16
# 6 2019-06-15  NA  NA 2019-06-15 16:30:00 21.3   16

df1$Day <- as.Date(df1$Day)

merge(df1, df2, by = "Day", all.y = TRUE)
#          Day  Max  Min                Date Temp Hour
# 1 2019-06-15 23.8 14.4 2019-06-15 14:00:00 22.8   14
# 2 2019-06-15 23.8 14.4 2019-06-15 14:30:00 22.4   14
# 3 2019-06-15 23.8 14.4 2019-06-15 15:00:00 22.4   15
# 4 2019-06-15 23.8 14.4 2019-06-15 15:30:00 22.3   15
# 5 2019-06-15 23.8 14.4 2019-06-15 16:00:00 21.9   16
# 6 2019-06-15 23.8 14.4 2019-06-15 16:30:00 21.3   16
  

Я рискну и скажу, что class ваши Day столбцы отличаются.

При использовании «необработанных данных», скопированных из вопроса, Day будут строки для обоих фреймов:

 df1 <- read.table(header = TRUE, text = "
Day MaxTemp MinTemp
2019-06-15 23.8 14.4
2019-06-16 24.9 11.7
2019-06-17 23.2 8.7")

df2 <- read.table(header = TRUE, text = "
Day Hour Temp
2019-06-15 14 22.8
2019-06-15 15 22.4
2019-06-15 16 21.9")

str(lapply(df1, class))
# List of 3
#  $ Day    : chr "character"
#  $ MaxTemp: chr "numeric"
#  $ MinTemp: chr "numeric"
merge(df1, df2, by = "Day")
#          Day MaxTemp MinTemp Hour Temp
# 1 2019-06-15    23.8    14.4   14 22.8
# 2 2019-06-15    23.8    14.4   15 22.4
# 3 2019-06-15    23.8    14.4   16 21.9
  

Если я преобразовываю одно из них в Date класс:

 df1$Day <- as.Date(df1$Day)
str(lapply(df1, class))
# List of 3
#  $ Day    : chr "Date"
#  $ MaxTemp: chr "numeric"
#  $ MinTemp: chr "numeric"

merge(df1, df2, by = "Day", all.y = TRUE)
#          Day MaxTemp MinTemp Hour Temp
# 1 2019-06-15      NA      NA   14 22.8
# 2 2019-06-15      NA      NA   15 22.4
# 3 2019-06-15      NA      NA   16 21.9
  

Исправления включают:

  1. Преобразование другого фрейма Day в дату:

     df2$Day <- as.Date(df2$Day)
    merge(df1, df2, by = "Day", all.y = TRUE)
    #          Day MaxTemp MinTemp Hour Temp
    # 1 2019-06-15    23.8    14.4   14 22.8
    # 2 2019-06-15    23.8    14.4   15 22.4
    # 3 2019-06-15    23.8    14.4   16 21.9
      
  2. Преобразование обоих Day столбцов обратно в character (или factor ):

     df1$Day <- as.character(df1$Day)
    df2$Day <- as.character(df2$Day)
    merge(df1, df2, by = "Day", all.y = TRUE)
    #          Day MaxTemp MinTemp Hour Temp
    # 1 2019-06-15    23.8    14.4   14 22.8
    # 2 2019-06-15    23.8    14.4   15 22.4
    # 3 2019-06-15    23.8    14.4   16 21.9
      

    Хотя в этом случае вполне вероятно (и, возможно, даже рекомендуется), что в какой-то момент вы преобразуете их обратно в Date (поскольку, в конце концов, это числовой тип данных).