2012-10-22 11 views
6

mam długie listy ciągów znaków takich jak ta maszyna czytelny przykład:Właściwe użycie gsub/wyrażeń regularnych w R?

A <- list(c("Biology","Cell Biology","Art","Humanities, Multidisciplinary; Psychology, Experimental","Astronomy & Astrophysics; Physics, Particles & Fields","Economics; Mathematics, Interdisciplinary Applications; Social Sciences, Mathematical Methods","Geriatrics & Gerontology","Gerontology","Management","Operations Research & Management Science","Computer Science, Artificial Intelligence; Computer Science, Information Systems; Engineering, Electrical & Electronic","Economics; Mathematics, Interdisciplinary Applications; Social Sciences, Mathematical Methods; Statistics & Probability")) 

Tak to wygląda następująco:

> A 
[[1]] 
[1] "Biology" 
[2] "Cell Biology" 
[3] "Art" 
[4] "Humanities, Multidisciplinary; Psychology, Experimental" 
[5] "Astronomy & Astrophysics; Physics, Particles & Fields" 
[6] "Economics; Mathematics, Interdisciplinary Applications; Social Sciences, Mathematical Methods" 
[7] "Geriatrics & Gerontology" 
[8] "Gerontology" 
[9] "Management" 
[10] "Operations Research & Management Science" 
[11] "Computer Science, Artificial Intelligence; Computer Science, Information Systems; Engineering, Electrical & Electronic" 
[12] "Economics; Mathematics, Interdisciplinary Applications; Social Sciences, Mathematical Methods; Statistics & Probability" 

chciałbym zmienić te warunki i eliminacji duplikatów w celu uzyskania tego rezultat:

[1] "Science" 
[2] "Science" 
[3] "Arts & Humanities" 
[4] "Arts & Humanities; Social Sciences" 
[5] "Science" 
[6] "Social Sciences; Science" 
[7] "Science" 
[8] "Social Sciences" 
[9] "Social Sciences" 
[10] "Science" 
[11] "Science" 
[12] "Social Sciences; Science" 

Do tej pory mam tylko to:

stringedit <- function(A) 
{ 
    A <-gsub("Biology", "Science", A) 
    A <-gsub("Cell Biology", "Science", A) 
    A <-gsub("Art", "Arts & Humanities", A) 
    A <-gsub("Humanities, Multidisciplinary", "Arts & Humanities", A) 
    A <-gsub("Psychology, Experimental", "Social Sciences", A) 
    A <-gsub("Astronomy & Astrophysics", "Science", A) 
    A <-gsub("Physics, Particles & Fields", "Science", A) 
    A <-gsub("Economics", "Social Sciences", A) 
    A <-gsub("Mathematics", "Science", A) 
    A <-gsub("Mathematics, Applied", "Science", A) 
    A <-gsub("Mathematics, Interdisciplinary Applications", "Science", A) 
    A <-gsub("Social Sciences, Mathematical Methods", "Social Sciences", A) 
    A <-gsub("Geriatrics & Gerontology", "Science", A) 
    A <-gsub("Gerontology", "Social Sciences", A) 
    A <-gsub("Management", "Social Sciences", A) 
    A <-gsub("Operations Research & Management Science", "Science", A) 
    A <-gsub("Computer Science, Artificial Intelligence", "Science", A) 
    A <-gsub("Computer Science, Information Systems", "Science", A) 
    A <-gsub("Engineering, Electrical & Electronic", "Science", A) 
    A <-gsub("Statistics & Probability", "Science", A) 
} 
B <- lapply(A, stringedit) 

Ale to nie działa prawidłowo:

> B 
[[1]] 
[1] "Science" 
[2] "Cell Science" 
[3] "Arts & Humanities" 
[4] "Arts & Humanities; Social Sciences" 
[5] "Science; Science" 
[6] "Social Sciences; Science, Interdisciplinary Applications; Social Sciences" 
[7] "Science" 
[8] "Social Sciences" 
[9] "Social Sciences" 
[10] "Operations Research & Social Sciences Science" 
[11] "Computer Science, Arts & Humanitiesificial Intelligence; Science; Science" 
[12] "Social Sciences; Science, Interdisciplinary Applications; Social Sciences; Science" 

Jak mogę uzyskać poprawny wynik, o którym mowa powyżej?
Z góry dziękuję bardzo za uwagę!

+0

Za każdym razem, gdy kończy się wiele podobnych linii kodu, omijasz piękną [zasadę DRY] (http://en.wikipedia.org/wiki/Don%27t_repeat_yourself). Nadszedł czas na przeprojektowanie, najwyraźniej opakowanie zostało przekazane do pewnego rodzaju funkcji '* apply' lub innego pomocnika podobnego do pętli. – aL3xa

Odpowiedz

4

Zacznę od jednego przykładu. Masz ciąg "Cell Biology". Pierwsza substytucja, A <-gsub("Biology", "Science", A), zamienia ją w "Cell Science". Który następnie nie jest podstawiony.

Ponieważ nie używać wyrażeń regularnych, wolałbym użyć rodzaju hash zrobić podstawienia:

myhash <- c("Science", "Science", "Arts & Humanities", "Arts & Humanities", "Social Sciences", 
    "Science", "Science", "Social Sciences", "Science", "Science", "Science", "Social Sciences", 
    "Science", "Social Sciences", "Social Sciences", "Science", "Science", "Science", "Science", 
    "Science") 

names(myhash) <- c("Biology", "Cell Biology", "Art", "Humanities, Multidisciplinary", 
    "Psychology, Experimental", "Astronomy & Astrophysics", "Physics, Particles & Fields", "Economics", 
    "Mathematics", "Mathematics, Applied", "Mathematics, Interdisciplinary Applications", 
    "Social Sciences, Mathematical Methods", "Geriatrics & Gerontology", "Gerontology", "Management", 
    "Operations Research & Management Science", "Computer Science, Artificial Intelligence", 
    "Computer Science, Information Systems", "Engineering, Electrical & Electronic", 
    "Statistics & Probability") 

Teraz podany ciąg znaków takich jak „Biology”, można szybko sprawdzić swoją Kategoria:

myhash[ "Biology" ] 

nie jestem pewien, dlaczego chcesz używać listę zamiast wektorze łańcuchów, dlatego będę uprościć nieco sprawę:

A <- c("Biology","Cell Biology","Art", 
    "Humanities, Multidisciplinary; Psychology, Experimental", 
    "Astronomy & Astrophysics; Physics, Particles & Fields", 
    "Economics; Mathematics, Interdisciplinary Applications; Social Sciences, Mathematical Methods", 
    "Geriatrics & Gerontology","Gerontology","Management","Operations Research & Management Science", 
    "Computer Science, Artificial Intelligence; Computer Science, Information Systems; Engineering, Electrical & Electronic", 
    "Economics; Mathematics, Interdisciplinary Applications; Social Sciences, Mathematical Methods; Statistics & Probability") 

Wyszukiwanie nie będzie działać dla ciągów złożonych (zawierających ";"). Możesz je podzielić, jednak używając strsplit. Następnie można użyć numeru unique, aby uniknąć powtarzania terminów, i odłożyć je ponownie za pomocą funkcji paste.

stringedit <- function(x) { 
    # first, split into subterms 
    a.all <- unlist(strsplit(x, "; *")) ; 
    paste(unique(myhash[ a.all ]), collapse= "; ") 
} 

unlist(lapply(A, stringedit )) 

Oto wynik, zgodnie z życzeniem:

[1] "Science"       "Science"       "Arts & Humanities"     "Arts & Humanities; Social Sciences" 
[5] "Science"       "Social Sciences; Science"   "Science"       "Social Sciences"     
[9] "Social Sciences"     "Science"       "Science"       "Social Sciences; Science" 

Oczywiście, można zadzwonić *apply kilkakrotnie tak:

a.spl <- sapply(A, strsplit, "; *") 
a.spl <- sapply(a.spl, function(x) myhash[ x ]) 
unlist(sapply(a.spl, collapse, "; ") 

To nie jest mniej lub bardziej skuteczne niż poprzedni kod.

Tak, można osiągnąć to samo za pomocą wyrażeń regularnych, ale po pierwsze, wymagałoby to rozdzielenia łańcuchów, a następnie użycia wyrażenia regularnego, takiego jak ^Biology$, aby upewnić się, że pasują one do "Biologii", ale nie do "Biologii komórki" itp. chcesz wybrać konstrukcje typu ". * Biologia". W końcu i tak musiałbyś pozbyć się duplikatów, i wszystko, co by to było, moim zdaniem (i) mniej gadatliwy (= bardziej podatny na błędy) i (ii) nie warte wysiłku.

+0

IMO, zły pomysł. Używasz 'strsplit' -owania łańcucha w każdej iteracji pętli. Powinieneś zrobić to tylko raz. – aL3xa

+0

Jestem tylko 'strsplit'-ing' length (A) 'number of times; nie różni się to pod względem liczby podziałów od 'lapply (A, strsplit, ';") '. – January

+0

Dziękuję bardzo za rozwiązanie, @ styczeń! – user1496104

2

A co powiesz na używanie switch?

science.category <- function(science){ 
    switch(science, 
      "Biology" =, 
      "Cell Biology" =, 
      "Astronomy & Astrophysics" =, 
      "Physics, Particles & Fields" =, 
      "Mathematics" =, 
      "Mathematics, Applied" =, 
      "Mathematics, Interdisciplinary Applications" =, 
      "Geriatrics & Gerontology" =, 
      "Operations Research & Management Science" =, 
      "Computer Science, Artificial Intelligence" =, 
      "Computer Science, Information Systems" =, 
      "Engineering, Electrical & Electronic" =, 
      "Statistics & Probability" = "Science", 
      "Art" =, 
      "Humanities, Multidisciplinary" = "Arts & Humanities", 
      "Psychology, Experimental" =, 
      "Economics" =, 
      "Social Sciences, Mathematical Methods" =, 
      "Gerontology" =, 
      "Management" = "Social Sciences", 
      NA 
      ) 
} 

a <- unlist(lapply(A, strsplit, split = " *; *"), recursive = FALSE) 
a1 <- lapply(a, function(x) unique(sapply(x, science.category))) 
sapply(a1, paste, collapse = "; ") 

Oczywiście, to będzie działać tak długo, jak masz odpowiednie sznurki popchnął jako switch argumentów. Jedna niezgodność, a skończysz z NA. W przypadku niektórych zaawansowanych zastosowań powinieneś napisać własne opakowanie, aby korzystać z rodziny funkcji grep lub nawet agrep (posługuj się ostrożnie).

+1

Tęsknisz za wezwaniem do "kategorii nauki" między wywołaniami 'strsplit' i' sapply'. – January

+0

Hahahah, świetnie! =) Dzięki za spostrzeżenie! =) – aL3xa

+0

@ styczeń, naprawiono i thnx dla podpowiedzi. – aL3xa

5

Najłatwiej było wyszukać kolumnę z dwiema kolumnami: data.frame, z jedną kolumną dla nazwy kursu i jedną kolumną dla kategorii. Oto przykład:

course.categories <- data.frame(
    Course = 
    c("Art", "Humanities, Multidisciplinary", "Biology", "Cell Biology", 
    "Astronomy & Astrophysics", "Physics, Particles & Fields", "Mathematics", 
    "Mathematics, Applied", "Mathematics, Interdisciplinary Applications", 
    "Geriatrics & Gerontology", "Operations Research & Management Science", 
    "Computer Science, Artificial Intelligence", 
    "Computer Science, Information Systems", 
    "Engineering, Electrical & Electronic", "Statistics & Probability", 
    "Psychology, Experimental", "Economics", 
    "Social Sciences, Mathematical Methods", 
    "Gerontology", "Management"), 
    Category = 
    c("Arts & Humanities", "Arts & Humanities", "Science", "Science", 
    "Science", "Science", "Science", "Science", "Science", "Science", 
    "Science", "Science", "Science", "Science", "Science", "Social Sciences", 
    "Social Sciences", "Social Sciences", "Social Sciences", "Social Sciences")) 

Następnie zakładając A postaci listy, jak w Twoje pytanie:

sapply(strsplit(unlist(A), "; "), 
     function(x) 
     paste(unique(course.categories[match(x, course.categories[["Course"]]), 
             "Category"]), 
       collapse = "; ")) 
# [1] "Science"       "Science"       
# [3] "Arts & Humanities"     "Arts & Humanities; Social Sciences" 
# [5] "Science"       "Social Sciences; Science"   
# [7] "Science"       "Social Sciences"     
# [9] "Social Sciences"     "Science"       
# [11] "Science"       "Social Sciences; Science" 

match odpowiada wartości od A z nazwami przedmiotów w course.categories zbiorze i mówi, które wiersze meczu występuje w; służy to do wyodrębnienia kategorii, do której należy kurs. Następnie, unique upewnia się, że mamy po jednej z każdej kategorii. paste kładzie rzeczy razem.

+0

Dziękuję bardzo za sugestię, @mrdwab! – user1496104

Powiązane problemy