Об'єднати два кадри даних і створити кілька стовпців у R

Припустимо, що ми маємо два кадри даних, як показано нижче:

df1 <- data.frame(Team1 = c("A","B","C"), Team2 = c("D","E","F"), Winner = c("A","E","F"))

df2 <- data.frame(Country = c("A","B","C","D","E","F"), Index = c(1,2,3,4,5,6))

Я хочу створити три колонки в df2 як Team1_index, Team2_index і Winner_index.

Team1 Team2 Winner Team1_index Team2_index Winner_index
A     D      A           1           4            1
B     E      E           2           5            5
C     F      F           3           6            6

Я пробував багато способів, але не зміг. Поради та рекомендації!

0

7 Відповіді

Щоб отримати нові стовпці як фактори:

df1[paste0(colnames(df1),"_index")] <- lapply(df1,factor,df2$Country,df2$Index)
#   Team1 Team2 Winner Team1_index Team2_index Winner_index
# 1     A     D      A           1           4            1
# 2     B     E      E           2           5            5
# 3     C     F      F           3           6            6

Щоб отримати нові стовпці як числові:

df1[paste0(colnames(df1),"_index")] <-
  lapply(df1,function(x) as.numeric(as.character(factor(x,df2$Country,df2$Index))))
#   Team1 Team2 Winner Team1_index Team2_index Winner_index
# 1     A     D      A           1           4            1
# 2     B     E      E           2           5            5
# 3     C     F      F           3           6            6

Зауважте, що для цього конкретного випадку (індекс з 1 збільшується на 1) ця коротша версія працює:

df1[paste0(colnames(df1),"_index")] <-
  lapply(df1,function(x) as.numeric(factor(x,df2$Country)))
1
додано

Якщо у вас є більше стовпців, ви можете шукати більш системні рішення, але якщо це дійсно лише три випадки, це має робити:

library("tidyverse")
df1 <- data.frame(Team1 = c("A","B","C"), Team2 = c("D","E","F"), Winner = c("A","E","F"))
df2 <- data.frame(Country = c("A","B","C","D","E","F"), Index = c(1,2,3,4,5,6))

df1 %>% 
  left_join(df2 %>% rename(Team1 = Country), by = "Team1") %>% 
  rename(Team1_Index = Index) %>% 
  left_join(df2 %>% rename(Team2 = Country), by = "Team2") %>% 
  rename(Team2_Index = Index) %>%
  left_join(df2 %>% rename(Winner = Country), by = "Winner") %>% 
  rename(Winner_Index = Index) 
#> Warning: Column `Team1` joining factors with different levels, coercing to
#> character vector
#> Warning: Column `Team2` joining factors with different levels, coercing to
#> character vector
#> Warning: Column `Winner` joining factors with different levels, coercing to
#> character vector
#>   Team1 Team2 Winner Team1_Index Team2_Index Winner_Index
#> 1     A     D      A           1           4            1
#> 2     B     E      E           2           5            5
#> 3     C     F      F           3           6            6

Можна спокійно ігнорувати застереження.

1
додано
Легкий вихід. Дякую!
додано Автор nerdakgul, джерело

Якщо ви просто маєте невелике число стовпців, ви можете використовувати функцію збігу, як у прикладі:

df1$Team1_index <- df2$Index[match(df1$Team1, df2$Country)]
df1$Team2_index <- df2$Index[match(df1$Team2, df2$Country)]
df1$Winner_index <- df2$Index[match(df1$Winner, df2$Country)]
df1
1
додано
Це працювало для мене. Дякую!
додано Автор nerdakgul, джерело

Ви можете використовувати chartr . Це враховуватиме стовпець країни та стовпець індексу:

df3=as.matrix(setNames(df1,paste0(names(df1),"_index")))

cbind(df1,chartr(paste0(df2$Country,collapse=""),paste0(df2$Index,collapse=""),df3))

  Team1 Team2 Winner Team1_index Team2_index Winner_index
1     A     D      A           1           4            1
2     B     E      E           2           5            5
3     C     F      F           3           6            6

Ви також можете:

cbind(df1,do.call(chartr,c(as.list(sapply(unname(df2),paste,collapse="")),list(df3))))

  Team1 Team2 Winner Team1_index Team2_index Winner_index
1     A     D      A           1           4            1
2     B     E      E           2           5            5
3     C     F      F           3           6            6
0
додано
Це зберігає стовпці індексу як фактори
додано Автор Moody_Mudskipper, джерело

Ось інший варіант, який використовує матч і cbind .

df3 <- as.matrix(df1)
colnames(df3) <- paste0(colnames(df3), "_index")

# match the positions
df3[] <- match(df3, df2$Country)
cbind(df1, df3)
#  Team1 Team2 Winner Team1_index Team2_index Winner_index
#1     A     D      A           1           4            1
#2     B     E      E           2           5            5
#3     C     F      F           3           6            6

df3 is created as a matrix, i.e. a vector with dimensions attribute, such that we can replace its entries with the result of match (a vector) right away and don't need to repeat the code for every column.

Або за один раз

df1[paste0(colnames(df1), "_index")] <- match(as.matrix(df1), df2$Country)

Зауважте, що це ігнорує стовпець index df2 .


Завдяки @Moody_Mudskipper ми могли б також написати це більш загальне як

df1[paste0(colnames(df1), "_index")] <- lapply(df1, function(x) df2$Index[match(x, df2$Country)])
0
додано
можна переписати як df1 [paste0 (колонки (df3), "_index")] <- lapply (df1, match, df2 $ Country) , але стовпець індекс ігнорується, значення просто припускаються бути рівним номеру рядка
додано Автор Moody_Mudskipper, джерело
Це дасть загальне рішення: df1 [paste0 (colnames (df3), "_index")] <- lapply (df1, function (x) df2 $ Index [матч (x, df2 $ Country)])
додано Автор Moody_Mudskipper, джерело
@Moody_Mudskipper Дякуємо за корисні коментарі. (Просто df3 має бути df1
додано Автор markus, джерело
Cool! Дякую.
додано Автор nerdakgul, джерело

Це в основному те ж саме, що і відповідь giocomai, просто використовує purrr , щоб усунути дублювання:

library(rlang)
library(dplyr)

getIndexCols <- function(df1, df2, colName){
     idxColName <- sym(paste0(colName, "_Index"))
     df1 %>% left_join(df2 %>% rename(!! sym(colName) := Country, !! idxColName := Index))
}


names(df1) %>% purrr::map(~ getIndexCols(df1, df2, .)) %>% reduce(~ left_join(.x, .y))
0
додано
Складна простота. Дякую!
додано Автор nerdakgul, джерело

У мене є майже рішення з data.table, за допомогою melt і dacst для зміни форми

library(data.table)

df1 <- data.table(Team1 = c("A","B","C"), Team2 = c("D","E","F"), Winner = c("A","E","F")) 
df2 <- data.table(Country = c("A","B","C","D","E","F"), Index = c(1,2,3,4,5,6))

melt(data = df1 , id.vars = )
plouf <- merge(df2,melt(df1,measure = 1:2), by.x = "Country", by.y = "value")
plouf[,winneridx := Index[Country == Winner]]
dcast(plouf,Country+winneridx~variable,value.var = "Index")


   Country winneridx Team1 Team2
1:       A         1     1    NA
2:       B         5     2    NA
3:       C         6     3    NA
4:       D         1    NA     4
5:       E         5    NA     5
6:       F         6    NA     6
0
додано