2016-11-01 2 views
3

Wenn ich die folgenden data.frame habe:Ist es möglich, Zeilen in R data.frame zusammenzuführen?

> df <- data.frame(x = c('a', 'b*', 'c'), y = c('d', 'e', 'f')) 
> df 
    x y 
1 a d 
2 b* e 
3 c f 

Gibt es eine klare Art und Weise Zeilen zu identifizieren, in denen die df$x Einträge umfassen den String-Wert *, dann diese Bedingung verwenden, um die Zeichenfolge Einträge dieser Zeile zu zwingen, mit der Reihe zusammengefügt wird vorhergehende selbst, in einem data.frame wie folgt resultierende:

> df 
    x y 
1 a b* d e 
2 c f 

ich gehe davon aus, dass der erste Teil des Problems (Identifizierung der x Zeilenwerte, die `* enthalten) in einem durchgeführt werden ziemlich geradliniger Weg mit regulären Ausdruck Sitzungen. Ich habe Probleme beim Identifizieren, wie eine data.frame-Zeilenzusammenführung mit der davor liegenden Zeile erzwungen wird.

Eine besonders knifflige Herausforderung ist, wenn mehrere Einträge in einer Zeile das Muster haben, z.

> df <- data.frame(x = c('a', 'b*', 'c*'), y = c('d', 'e', 'f')) 
> df 
    x y 
1 a d 
2 b* e 
3 c* f 

In diesem Fall sollte die resultierende data.frame wie folgt aussehen:

> df 
     x  y 
1 a b* c* d e f 

Die wichtigste Frage, die ich finde, ist, dass nach einer Iteration einer Schleife ausgeführt wird, der die Saiten von df[2,] Pasten in df[1,], der data.frame Index paßt sich nicht an die neue data.frame Größe:

> df 
    x y 
1 a b* d e 
3 c* f 

So anschließende Indizierung unterbrochen wird.

+1

Was ist Ihre gewünschte Ausgabe für den neuen 'df'? –

+0

Ich habe Änderungen an meiner Frage hinzugefügt, um die gewünschte Ausgabe anzuzeigen und die Schwierigkeiten, denen ich begegne, besser zu erklären. – kathystehl

Antwort

4

Hier eine Ausgangslösung:

# Creating the data frame 
df <- data.frame(x = c('a', 'b*', 'c'), y = c('d', 'e', 'f'),stringsAsFactors = FALSE) 
df 

# Creating a vector of rows with * 
ast <- grepl("\\*",df$x) 

# For loop 
for(i in seq(length(ast),1,-1)){ 
    if(ast[i]){ 
    df[i-1,"x"] <- paste(df[i-1,"x"],df[i,"x"],sep=" ") 
    df[i-1,"y"] <- paste(df[i-1,"y"],df[i,"y"],sep=" ") 
    df <- df[-i,] 
    } 
} 

Das ist eine erste Lösung, weil Sie noch zu verwalten haben, wenn die erste Zeile hat * und andere Situationen wie diese. Ich hoffe, das hilft schon.

+0

Irgendwelche Gedanken darüber, wie man mit mehreren aufeinanderfolgenden Reihen mit der Bedingung umgehen soll? Wenn Sie eine Zeile nach oben zusammenführen, wird die Indexierung durcheinander gebracht (zB wenn 'c *' der 'df [3,1] '- Eintrag ist. – kathystehl

+0

Deshalb zähle ich in der for-Schleife rückwärts. Ich füge beispielsweise die Zeile zusammen 3 mit der Zeile 2, dann lösche ich die Zeile 3. Alles oben auf der Zeile 3 bleibt gleich und der Schleifenindex wird immer noch funktionieren. –

2

Die Zeilen werden nicht zusammengeführt, aber für die Zeilen, die ein * enthalten, wird der Wert der vorherigen Zeile eingefügt, und dann werden Zeilen mit einem * in der folgenden Zeile gelöscht.

library(dplyr) 

df <- data.frame(x = c('a', 'b*', 'c'), y = c('d', 'e', 'f')) 

df <- mutate(df, 
      Operator = grepl("\\*",x), # Check for * 
      lagged.x = lag(x, n = 1), # Get x value from 1 row ago 
      lagged.y = lag(y, n = 1), # Get y value from 1 row ago 
      x = ifelse(Operator, paste(lagged.x, x),x), # if there is * paste lagged x 
      y = ifelse(Operator, paste(lagged.y, y),y), # if there is * paste lagged y 
      lead.Operator = lead(Operator, n = 1)  # Check if next row has a * 
) 

# keep only rows that had no * in following row and that had no following row (last row) 
df <- filter(df, !lead.Operator | is.na(lead.Operator)) 

# Select just the x and y columns 
df <- select(df, x, y) 
2

Hier gibt es 3 Alternativen (für die Basis R ein, nahm ich an x und y Zeichen sind eher Faktor. Ich habe auch Ihre Daten kompliziert mehr, um verschiedene Szenarien zur Deckung)

(Ein bisschen mehr komplizierte Datensatz)

df <- data.frame(x = c('p','a', 'b*', 'c*', 'd', 'h*', 'j*', 'l*', 'n'), 
       y = c('r','d', 'e', 'f', 'g', 'i', 'k', 'm', 'o'), 
       stringsAsFactors = FALSE) 

Base-R

aggregate(. ~ ID, 
      transform(df, ID = cumsum(!grepl("*", x, fixed = TRUE))), 
      paste, collapse = " ") 
# ID   x  y 
# 1 1   p  r 
# 2 2 a b* c* d e f 
# 3 3 d h* j* l* g i k m 
# 4 4   n  o 

data.table

library(data.table) 
setDT(df)[, lapply(.SD, paste, collapse = " "), 
      by = .(ID = cumsum(!grepl("*", df[["x"]], fixed = TRUE)))] 
# ID   x  y 
# 1: 1   p  r 
# 2: 2 a b* c* d e f 
# 3: 3 d h* j* l* g i k m 
# 4: 4   n  o 

dplyr

library(dplyr) 
df %>% 
    group_by(ID = cumsum(!grepl("*", x, fixed = TRUE))) %>% 
    summarise_all(funs(paste(., collapse = " "))) 

# # A tibble: 4 x 3 
#  ID   x  y 
# <int>  <chr> <chr> 
# 1  1   p  r 
# 2  2 a b* c* d e f 
# 3  3 d h* j* l* g i k m 
# 4  4   n  o 
Verwandte Themen