Объединить неравные кадры данных и заменить отсутствующие строки на 0 - PullRequest
59 голосов
/ 11 мая 2011

У меня есть два data.frames, один с только символами, а другой с символами и значениями.

df1 = data.frame(x=c('a', 'b', 'c', 'd', 'e'))
df2 = data.frame(x=c('a', 'b', 'c'),y = c(0,1,0))
merge(df1, df2)
  x y
1 a 0
2 b 1
3 c 0 

Я хочу объединить df1 и df2. Символы a, b и c слились хорошо и также имеют 0, 1, 0, но d и e ничего не имеют. Я хочу d и e также в таблице слияния, с условием 0 0. Таким образом, для каждой отсутствующей строки в df2 data.frame 0 должен быть помещен в таблицу df1, например:

  x y
1 a 0
2 b 1
3 c 0
4 d 0
5 e 0

Ответы [ 5 ]

87 голосов
/ 11 мая 2011

Взгляните на страницу помощи для слияния. Параметр all позволяет указать различные типы слияний. Здесь мы хотим установить all = TRUE. Это приведет к слиянию, возвращаемому NA для значений, которые не совпадают, которые мы можем обновить до 0 с помощью is.na():

zz <- merge(df1, df2, all = TRUE)
zz[is.na(zz)] <- 0

> zz
  x y
1 a 0
2 b 1
3 c 0
4 d 0
5 e 0

Обновлено много лет спустя, чтобы ответить на следующий вопрос

Вам необходимо определить имена переменных во второй таблице данных, с которой вы не объединяете - для этого я использую setdiff(). Проверьте следующее:

df1 = data.frame(x=c('a', 'b', 'c', 'd', 'e', NA))
df2 = data.frame(x=c('a', 'b', 'c'),y1 = c(0,1,0), y2 = c(0,1,0))

#merge as before
df3 <- merge(df1, df2, all = TRUE)
#columns in df2 not in df1
unique_df2_names <- setdiff(names(df2), names(df1))
df3[unique_df2_names][is.na(df3[, unique_df2_names])] <- 0 

Создано в 2019-01-03 пакетом Представление (v0.2.1)

7 голосов
/ 11 мая 2011

Или, в качестве альтернативы коду @ Chase, недавний фанат plyr с опытом работы в базах данных:

require(plyr)
zz<-join(df1, df2, type="left")
zz[is.na(zz)] <- 0
3 голосов
/ 12 мая 2011

Другая альтернатива с data.table.

ПРИМЕРНЫЕ ДАННЫЕ

dt1 <- data.table(df1)
dt2 <- data.table(df2)
setkey(dt1,x)
setkey(dt2,x)

код

dt2[dt1,list(y=ifelse(is.na(y),0,y))]
2 голосов
/ 27 марта 2014

Я использовал ответ, данный Чейзом (ответил 11 мая '11 в 14:21), но я добавил немного кода, чтобы применить это решение к моей конкретной проблеме.

У меня был фрейм тарифов (пользователь, загрузка) и фрейм итогов (пользователь, загрузка), который должен объединять пользователь, и я хотел включить каждый тариф, даже если не было соответствующего итога. Однако не может быть пропущенных итогов, и в этом случае выбор строк для замены NA на ноль не удастся.

Первая строка кода выполняет слияние. Следующие две строки изменяют имена столбцов в объединенном фрейме. Оператор if заменяет NA на ноль, но только если есть строки с NA.

# merge rates and totals, replacing absent totals by zero
graphdata <- merge(rates, totals, by=c("user"),all.x=T)
colnames(graphdata)[colnames(graphdata)=="download.x"] = "download.rate"
colnames(graphdata)[colnames(graphdata)=="download.y"] = "download.total"
if(any(is.na(graphdata$download.total))) {
    graphdata[is.na(graphdata$download.total),]$download.total <- 0
}
1 голос
/ 23 марта 2019

Предполагая, что df1 имеет все значения x, представляющие интерес, вы можете использовать dplyr::left_join() для слияния, а затем либо base::replace() или tidyr::replace_na() для замены NA s на 0 s:

library(tidyverse)

# dplyr only:
df_new <- 
  left_join(df1, df2, by = 'x') %>% 
  mutate(y = replace(y, is.na(y), 0))

# dplyr and tidyr:
df_new <- 
  left_join(df1, df2, by = 'x') %>% 
  mutate(y = replace_na(y, 0))

# In the sample data column `x` is a factor, which will give a warning with the join. This can be prevented by converting to a character before the join:
df_new <- 
  left_join(df1 %>% mutate(x = as.character(x)), 
            df2 %>% mutate(x = as.character(x)), 
            by = 'x') %>% 
    mutate(y = replace(y, is.na(y), 0))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...