2016-04-08 21 views
5

Ho un frame dati con dati settimanali per sezione. Ogni sezione ha circa 104 settimane di dati e ci sono 83 sezioni in totale.Unisci/Unisci frame dati/tabella in base a criteri -> o <

Ho un secondo frame di dati con la settimana di inizio e fine per sezione su cui voglio filtrare il frame dati principale.

In entrambe le tabelle la settimana è una combinazione di anno e settimana, ad es. 201.501 ed è sempre da settimane da 1 a 52.

Quindi, nell'esempio di seguito voglio filtrare sezione A da settimane 201.401-201.404, sezione B da settimane 201551 a 201603.

inizialmente ho pensato che avrei potuto aggiungere un colonna aggiuntiva al mio frame dati Weeks_Filter che è un numero sequenziale dall'inizio e alla fine delle settimane per ogni sezione (duplicando ogni riga per ogni settimana), quindi unire le 2 tabelle e mantenere tutti i dati dalla tabella Weeks_Filter (all. y = TRUE) perché questo ha funzionato su un piccolo campione che ho fatto, ma non so come aggiungere le settimane sequenziali poiché possono durare diversi anni.

Week <- c("201401","201402","201403","201404","201405", "201451", "201552", "201601", "201602", "201603") 
Section <- c(rep("A",5),rep("B",5)) 
df <- data.frame(cbind(Week, Section)) 

Section <- c("A", "B") 
Start <- c("201401","201551") 
End <- c("201404","201603") 
Weeks_Filter <- data.frame(cbind(Section, Start, End)) 

risposta

-2
require(data.table) 

df <- merge(df, Weeks_Filter) 
df[, -1] <- apply(df[, -1], 2, function(x) as.numeric(as.character(x))) 
df <- data.table(df) 

df[Week >= Start & Week <= End, .SD, by = Section] 

L'uscita è,

Section Start End Week 
1:  A 201401 201404 201401 
2:  A 201401 201404 201402 
3:  A 201401 201404 201403 
4:  A 201401 201404 201404 
5:  B 201551 201603 201552 
6:  B 201551 201603 201601 
7:  B 201551 201603 201602 
8:  B 201551 201603 201603 
+0

Grazie. Ha funzionato perfettamente. – MidnightDataGeek

+0

Mi chiedo, perché la risposta si sta abbassando. Alle persone piace una soluzione complessa piuttosto che una più semplice. – TheRimalaya

+0

la risposta ha funzionato bene per me. Sono nuovo di R e nonostante utilizzo il link fornito di seguito non sono riuscito a far funzionare la risposta. – MidnightDataGeek

1

Utilizzando dplyr

  • si possono combinare le trame di dati
  • gruppo dalla sezione
  • filtro in base alle colonne di inizio e fine

Un problema è che il vostro ' le settimane sono caratteri e diventano fattori nel modo in cui li hai codificati. Ho preso la scorciatoia e li ho semplicemente resi numerici, ma consiglierei di utilizzare lubridate per creare questi vettori di classe Date appropriati.

library(dplyr) 
tempdf <- full_join(df, Weeks_Filter) 
tempdf$Week <- as.numeric(as.character(tempdf$Week)) 
tempdf$Start <- as.numeric(as.character(tempdf$Start)) 
tempdf$End <- as.numeric(as.character(tempdf$End)) 


tempdf_filt <- tempdf %>% 
    group_by(Section) %>% 
    filter(Week >= Start, 
     Week <= End) 

Sembra che ci sia un problema nei dati che "201451" deve essere "201551", ma per il resto restituisce ciò che si vuole:

> tempdf_filt 
Source: local data frame [8 x 4] 
Groups: Section [2] 

    Week Section Start End 
    (dbl) (fctr) (dbl) (dbl) 
1 201401  A 201401 201404 
2 201402  A 201401 201404 
3 201403  A 201401 201404 
4 201404  A 201401 201404 
5 201552  B 201551 201603 
6 201601  B 201551 201603 
7 201602  B 201551 201603 
8 201603  B 201551 201603 
+1

un anno è 52 settimane;) – eddi

+0

@ johnSG Grazie - ho avuto un refuso lì dentro. Sto cercando di padroneggiare data.table così l'ho usato ma anche questo ha funzionato bene. – MidnightDataGeek

+0

@eddi Ho avuto un refuso nell'indicare l'errore di battitura (karma). 201501 -> 201551. corretto ora – JohnSG

0

Forse la creazione di un vettore di tutte le settimane desiderati avrebbe funzionato per il filtro. Ecco un esempio di massima con base di R:

# get weeks 
allWeeks <- as.character(1:52) 
allWeeks <- ifelse(nchar(allWeeks)==1, paste0("0",allWeeks), allWeeks) 
# get all year-weeks 
allWeeks <- paste0(2014:2015, allWeeks) 

# filter vector to select desired weeks 
keepWeeks <- keepWeeks[grep("201(40[1-4]|55[12]|60[123]))", allWeeks)] 

dfKeeper <- df[df$Week %in% keepWeeks,] 

ho cercato di costruire un'espressione regolare che cattura i periodi che si desidera, ma potrebbe essere necessario modificare un po '.

4

L'ultima development version di data.table aggiunge non equi unisce (e in quelle più vecchie è possibile utilizzare foverlaps):

setDT(df) # convert to data.table in place 
setDT(Weeks_Filter) 

# fix the column types - you have factors currently, converting to integer 
df[, Week := as.integer(as.character(Week))] 
Weeks_Filter[, `:=`(Start = as.integer(as.character(Start)), 
        End = as.integer(as.character(End)))] 

# the actual magic 
df[df[Weeks_Filter, on = .(Section, Week >= Start, Week <= End), which = T]] 
#  Week Section 
#1: 201401  A 
#2: 201402  A 
#3: 201403  A 
#4: 201404  A 
#5: 201552  B 
#6: 201601  B 
#7: 201602  B 
#8: 201603  B 
+4

ora possiamo anche usare il prefisso 'x' ora .. (particolarmente utile per fare riferimento alle colonne di join di x)' df [Weeks_Filter,. (X.Week, Section), su =. (Section, Week> = Start, Week < = Fine)] ' – Arun

+0

@eddi grazie per la risposta. Non ero in grado di replicare la tua risposta e penso che sia perché non ho la stessa versione di data.table. L'errore che ho avuto è stato: impossibile trovare la funzione "." – MidnightDataGeek

+0

Utilizzare il collegamento nella risposta per ottenere l'ultima versione. – eddi

Problemi correlati