2017-11-24 4 views
3

Ich habe Schwierigkeiten mit dplyr Joins zu arbeiten, wenn ich nicht den Standard "col1" = "col2" Join verwenden. Hier sind zwei Beispiele für das, was ich erlebt habe.Wie mache ich einen dplyr inner_join col1> col2

Erstens:

library(dplyr) 

tableA <- data.frame(col1= c("a","b","c","d"), 
        col2 = c(1,2,3,4)) 

inner_join(tableA, tableA, by = c("col1"!="col1")) %>% 
    select(col1, col2.x) %>% 
    arrange(col1, col2.x) 

Error: by must be a (named) character vector, list, or NULL for natural joins (not recommended in production code), not logical

Wenn ich diesen Code zu replizieren, aber die Verwendung von SQL ich die folgende:

con <- DBI::dbConnect(RSQLite::SQLite(), ":memory:") 

copy_to(con, tableA) 

tbl(con, sql("select a.col1, b.col2 
       from 
       tableA as a 
       inner join 
       tableA as b 
       on a.col1 <> b.col1")) %>% 
    arrange(col1, col2) 

Ergebnisse von SQL-Abfrage:

# Source:  SQL [?? x 2] 
# Database: sqlite 3.19.3 [:memory:] 
# Ordered by: col1, col2 
    col1 col2 
    <chr> <dbl> 
1  a  2 
2  a  3 
3  a  4 
4  b  1 
5  b  3 
6  b  4 
7  c  1 
8  c  2 
9  c  4 
10  d  1 
# ... with more rows 

Zweiter Teil ist ähnlich wie die letzte:

inner_join(tableA, tableA, by = c("col1" > "col1")) %>% 
    select(col1, col2.x) %>% 
    arrange(col1, col2.x) 

Error: by must be a (named) character vector, list, or NULL for natural joins (not recommended in production code), not logical

Sql-Äquivalent:

tbl(con, sql("select a.col1, b.col2 
       from tableA as a 
       inner join tableA as b 
       on a.col1 > b.col1")) %>% 
    arrange(col1, col2) 

Ergebnisse aus der zweiten SQL-Abfrage:

# Source:  SQL [?? x 2] 
# Database: sqlite 3.19.3 [:memory:] 
# Ordered by: col1, col2 
    col1 col2 
    <chr> <dbl> 
1  b  1 
2  c  1 
3  c  2 
4  d  1 
5  d  2 
6  d  3 

Wer weiß, wie diese SQL-Beispiele erstellen, aber dplyr Code?

Antwort

3

Für Ihren ersten Fall:

library(dplyr) 
library(tidyr) 

expand(tableA, col1, col2) %>% 
    left_join(tableA, by = 'col1') %>% 
    filter(col2.x != col2.y) %>% 
    select(col1, col2 = col2.x) 

Das Ergebnis:

# A tibble: 12 x 2 
    col1 col2 
    <fctr> <dbl> 
1  a  2 
2  a  3 
3  a  4 
4  b  1 
5  b  3 
6  b  4 
7  c  1 
8  c  2 
9  c  4 
10  d  1 
11  d  2 
12  d  3 

Für Ihren zweiten Fall:

expand(tableA, col1, col2) %>% 
    left_join(tableA, by = 'col1') %>% 
    filter(col2.x < col2.y) %>% 
    select(col1, col2 = col2.x) 

Das Ergebnis:

# A tibble: 6 x 2 
    col1 col2 
    <fctr> <dbl> 
1  b  1 
2  c  1 
3  c  2 
4  d  1 
5  d  2 
6  d  3 
+0

Dieser Wille würde auf Datenrahmen in R. perfekt für Arbeit Was passiert, wenn der Datenrahmen auf einer Datenbank vorschlagen würde, und Sie verwenden dplyr auf die Datenbank zu verbinden. Ich werde das Hauptthema bearbeiten, um dies hervorzuheben. –

+1

@DyfanJones bei der Anfrage zusätzliche Frage, es ist besser, neue zu fragen – h3rm4n

1

Eine Lösung mit dplyr und tidyr. Die Idee besteht darin, den Datenrahmen zu erweitern und dann eine Verknüpfung mit dem ursprünglichen Datenrahmen durchzuführen. Verwenden Sie danach fill von tidyr, um NA zu vorherigen Datensätzen zu füllen. Filtern Sie schließlich Datensätze mit denselben Werten und NA.

library(dplyr) 
library(tidyr) 

tableB <- tableA %>% 
    complete(col1, col2) %>% 
    left_join(tableA %>% mutate(col3 = col2), by = c("col1", "col2")) %>% 
    group_by(col1) %>% 
    fill(col3, .direction = "up") %>% 
    filter(col2 != col3, !is.na(col3)) %>% 
    select(-col3) %>% 
    ungroup() 
tableB 
# # A tibble: 6 x 2 
# col1 col2 
# <chr> <dbl> 
# 1  b  1 
# 2  c  1 
# 3  c  2 
# 4  d  1 
# 5  d  2 
# 6  d  3 

DATA

tableA <- data.frame(col1= c("a","b","c","d"), 
        col2 = c(1,2,3,4), stringsAsFactors = FALSE)