2017-07-08 3 views
3

Ich versuche Spalte „Grade“, um mehrere Spalten zu trennen nach ihrem Thema und die NoteWie eine Spalte auf mehrere Spalte (komplexe Spalte) trennen

grade<-read.csv("https://raw.githubusercontent.com/tuyenhavan/Statistics/Dataset/High_school_Grade.csv",sep=";") 

# Rename the column names 

    names(grade)<-c("Student_ID","Name","Venue","Grade") 

    head(grade) 

    # Separate `Grade` into `subject` variables and coresponding `Grade`columns 
    library(tidyverse) 


    df<- grade %>% separate(Grade,paste("V",1:7,sep="_"),sep=":") 

    head(df) 

    # It still is not separating `subject ` and `grade` independently 

    # Here is what I want it to look like 

    new_df<-df[c(1:5),c(1:4)] 

    new_df<-data.frame(new_df, V2=c(1:5)) # the same for V2,4,5,6,,7 to separate subject and grade 

    new_df 

Ich versuche dplyr zu verwenden und stringr, konnte aber nicht produzieren das Ergebnis wie erwartet

Antwort

1

In meiner Lösung unten habe ich Funktionen aus den tidyverse und rebus Paketen verwendet. Das rebus-Paket erstellt reguläre Ausdrücke Stück für Stück mit lesbarem Code.

library(tidyverse) 
library(rebus) 
grade<-read.csv("https://raw.githubusercontent.com/tuyenhavan/Statistics/Dataset/High_school_Grade.csv", 
       sep = ";", stringsAsFactors = FALSE) 

grade_new <- grade %>% 
    mutate(DIEM_THI2 = str_replace_all(DIEM_THI, pattern = ":" %R% one_or_more(SPC), "-")) %>% 
    separate_rows(DIEM_THI2, sep = one_or_more(SPC)) %>% 
    separate(DIEM_THI2, c("SUBJECT", "GRADE"), sep = "-") %>% 
    spread(SUBJECT,GRADE) 

Der resultierende Datenrahmen sieht wie folgt aus:

head(grade_new[,5:12]) 
# Biology Chemitry English Geography History Literature Math Physics 
# 1 6.00  6.00 <NA>  <NA> <NA>  7.50 4.25 6.80 
# 2 5.80  6.00 <NA>  <NA> <NA>  6.00 5.75 <NA> 
# 3 <NA>  <NA> <NA>  8.00 4.50  7.75 2.25 <NA> 
# 4 <NA>  <NA> <NA>  7.25 7.50  7.75 3.25 <NA> 
# 5 <NA>  <NA> <NA>  7.75 4.50  8.25 1.75 <NA> 
# 6 <NA>  6.60 6.78  <NA> <NA>  7.00 8.75 8.40 

Der Code kann wie folgt verstanden werden:

  1. Alle Kolon + Raum Substrings mit Bindestrichen ersetzt werden. d.h. "Math: 4.25 Literature: 7.50" wird "Math-4.25 Literature-7.50". Dies geschieht mit der str_replace_all Funktion. Lassen Sie uns die neue Variable DIEM_THI2 aufrufen.
  2. Die separate_rows Funktion teilt die Leerzeichen getrennte Säule, DIEM_THI2 in getrennte Reihen d.h. "Math-4.25" und "Literature-7.50" Spanne über zwei verschiedene Reihen.
  3. DIEM_THI2 Die Säule ist in zwei Spalten getrennt, d.h. SUBJECT und GRADE wo die früheren Werte wie "Math" enthält, "Literature" und letztere enthält Werte wie "4.25" und "7.50".
  4. Das Schlüssel-Wert-Paar oder das SUBJECT-GRADE-Paar sind auf mehrere Spalten verteilt.
+0

Vielen Dank @HNSKD. Das ist wirklich einfach zu verstehen – Tuyen

4

Hier ist ein Versuch mit tidyverse package.After alles zum Umwandeln des Charakters (dh grade[] <- lapply(grade, as.character)) schaffen wir eine benutzerdefinierte Funktion, die die subject:grade sortiert zurückgibt für jede StudentID. Wir verwenden dann unnest, um es lang zu machen, und verwenden separate, um es in zwei Spalten aufzuteilen; Subject und Grade. Schließlich wir spread, um eine Spalte für jedes Thema zu erhalten.

library(tidyverse) 

#This function could definetely be more elegant or even avoided 
# but this is as far as my regex knowledge allows me to go 

mysplit <- function(x){ 
    y <- strsplit(x, ':\\s+|\\s+')[[1]] 
    z <- paste0(y[c(T, F)], ': ', y[c(F, T)]) 
    return(z[order(sub(':.*', '', z))]) 
} 

grade %>% 
    mutate(Grade = lapply(Grade, mysplit)) %>% 
    unnest() %>% 
    separate(Grade, into = c('Subject', 'Grade'), sep = ': ') %>% 
    spread(Subject, Grade) 

, die sie als so aufgeteilt werden:

...  Biology Chemitry English Geography History Literature Math Physics 
... 1 6.00  6.00 <NA>  <NA> <NA>  7.50 4.25 6.80 
... 2 5.80  6.00 <NA>  <NA> <NA>  6.00 5.75 <NA> 
... 3 <NA>  <NA> <NA>  8.00 4.50  7.75 2.25 <NA> 
... 4 <NA>  <NA> <NA>  7.25 7.50  7.75 3.25 <NA> 
... 5 <NA>  <NA> <NA>  7.75 4.50  8.25 1.75 <NA> 
... 6 <NA>  6.60 6.78  <NA> <NA>  7.00 8.75 8.40 
. 
. 

Zum besseren Verständnis der Funktion sollten Sie es brechen. Sagen tha x ist folgende:

x 
#[1] "Math: 4.25 Literature: 7.50 Physics: 6.80 Chemitry: 6.00 Biology: 6.00" 

Split es jeden space oder : space folgendes Vektor

y <- strsplit(x, ':\\s+|\\s+')[[1]] 
y 
#[1] "Math"  "4.25"  "Literature" "7.50"  "Physics" "6.80"  "Chemitry" "6.00"  "Biology" "6.00" 

Fügen Sie ihn zusammen zu bekommen, zuerst alle ersten Elemente (dh die Themen, y[c(TRUE, FALSE)]) und dann alle zweiten Elemente (dh die Klassen y[c(FALSE, TRUE)]), mit einem : Separator

z <- paste0(y[c(T, F)], ': ', y[c(F, T)]) 
z 
#[1] "Math: 4.25"  "Literature: 7.50" "Physics: 6.80" "Chemitry: 6.00" "Biology: 6.00" 

Schließlich gibt es eine sortierte (basierend auf den Worten sub(':.*', '', z)) Vektor

z[order(sub(':.*', '', z))] 
#[1] "Biology: 6.00" "Chemitry: 6.00" "Literature: 7.50" "Math: 4.25"  "Physics: 6.80" 

Wie @rosscova wies darauf hin, Strings müssen nicht sortiert werden, was diese viel vereinfacht (Funktion nicht benötigt wird, nachdem alle), dh

grade %>% 
    mutate(Grade = strsplit(Grade, '[0-9]\\s+')) %>% 
    unnest() %>% 
    separate(Grade, into = c('Subject', 'Grade'), sep = ': ') %>% 
    spread(Subject, Grade) 
+0

Dank @Sotos. Das ist sehr schwer für mich zu folgen. Könnten Sie bitte das schreiben, ohne 'Funktion' zu verwenden? – Tuyen

+0

Was meinst du? Die Funktion wird benötigt, um die Stufenvariable – Sotos

+0

zu teilen. Vielen Dank für Ihren Kommentar. Aber dieses ist sehr schwer zu verstehen. Könnten Sie mehr erklären oder haben wir andere Möglichkeiten, dies zu erreichen? Mysplit <- function (x) { y <- strsplit (x, ': \\ s + | \ s +') [[1]] z < - paste0 (y [c (T, F)], ':', y [c (F, T)]) Rückgabe (z [Reihenfolge (sub (':. *', '', z))]) } – Tuyen

Verwandte Themen