2017-02-14 6 views
2

난 지저분한 문자열의 열을 포함하는 데이터 프레임이 있습니다. 각 지저분한 문자열에는 그 안에 어딘가에있는 단일 국가의 이름이 포함됩니다. 여기에 장난감 버전입니다 : (country.name)를 관련 국가 이름 국가 이름에 대한 정규식 등에서 특정 요소를 뽑아 오기 (regex)와 또 다른 한 다음 countrycode 패키지문자열에서 정규식으로 새 문자열

df <- data.frame(string = c("Russia is cool (2015) ", 
          "I like - China", 
          "Stuff happens in North Korea"), 
       stringsAsFactors = FALSE) 

덕분에, 나는 또한이 유용한 열을 포함하는 두 번째 데이터 세트를 . 우리는이 같은이 데이터 세트를로드 할 수

library(countrycode) 
data(countrycode_data) 

내가 df$string의 각 행에 국가 이름을 탐지하는 countrycode_data$regex에서 정규 표현식을 사용하는 코드를 작성하려합니다; 해당 정규 표현식을 적절한 국가 이름과 연관시킵니다 (countrycode_data$country.name). 마지막으로 해당 이름을 새 열의 관련 위치 인 df$country에 씁니다. 이 TBD 작업을 수행 한 후, df는 다음과 같이 보일 것이다 :

     string        country 
1  Russia is cool (2015)      Russian Federation 
2    I like - China         China 
3 Stuff happens in North Korea Korea, Democratic People's Republic of 

꽤이 작업을 수행하는 방법에 주위에 내 머리를 정리하고 수 없습니다. grepl, which, tolower%in%의 다양한 조합을 사용해 보았습니다. 그러나 방향이나 크기 (또는 둘 다)가 잘못되었습니다.

+0

... 편집 I 내가'country.name.en.regex'라고 불렀던 것을 발견했다고 생각하십니까? – rosscova

+0

'countrycode_data '의 관련 열은'regex'라고해야합니다. 적절한 이름을 갖는 연관된 컬럼은'country.name'입니다. – ulfelder

+0

다음과 같은 내용이 도움이 될 수 있습니다. http://stackoverflow.com/questions/21165256/r-merge-data-frames-allow-inexact-id-matching-eg-with-additional-characters – Bulat

답변

1

교차 결합 (블로우 업됩니다 데이터)와 가능한 솔루션입니다 : 아래 세 개의 텍스트 문자열에 무슨 일이 일어 나는지 case이지만 countrycode_data data.frame의 행에 걸쳐 반복적으로 반복됩니다. 실제 세계의 원래 데이터가 더 큰 순서가되는 반면 200 행만 있기 때문입니다. ,

for(i in seq_along(patt)) { 
    df$country[grepl(patt[i], df$string, ignore.case=TRUE, perl=TRUE)] <- name[i] 
} 

다른 사람들이 지적했듯이 : 그럼 우리가 루프가 새 열을 작성할 수 있습니다

patt <- countrycode_data$country.name.en.regex[!is.na(countrycode_data$country.name.en.regex)] 
name <- countrycode_data$country.name.en[!is.na(countrycode_data$country.name.en.regex)] 

: 때문에 긴 이름의

, 나는 두 국가 코드 데이터의 열을 추출 북한은 국가 코드 데이터에 지정된 정규 표현식과 일치하지 않습니다.

+1

우아하고 고마워요. (실제로, 나는 실제로 "북한"에 대해서도 원하는 결과를 얻는다.) – ulfelder

+1

예, 좋은 생각입니다. 나는 'stringi'를 사용하여 같은 생각을하고 있었는데, (sapply (countrycode_data $ country.name.en.regex, stringi :: stri_detect_regex, str = tolower (df $ string)), arr.ind = TRUE)' where'col'는'countrycode_data $ country.name.en' 내의 행 인덱스입니다) –

+0

@DavidArenburg 또한 좋은 대안입니다. 결국 하나의 루프를 어떤 식 으로든 만들어야합니다. stringi는 눈에 띄게 일치하는 정규식을 높일 수 있습니다 (물론 내 접근 방식에서도 채택 될 수 있습니다). –

1

여기에 해결책이 있지만 시스템에서 다르게 나타나므로 countrycode_data 프레임의 다른 열 이름을 참조하고 있습니다. 나는 또한 이상한 것이 아닌 약간의 *apply 호출을 의지했습니다. 나는 그 중 몇 가지를 벡터화 할 수있을 것이라고 확신합니다. 나는 어떻게 자신을 확신 할 수 없습니다.

matches <- sapply(df$string, function(x) { 

    # find matches by running all regex strings (maybe cound be vectorised?) 
    find.match <- lapply(countrycode_data$country.name.en.regex, grep, x = x, ignore.case = TRUE, perl = TRUE) 

    # note down which patterns came up with a match 
    matches <- which(sapply(find.match, length) > 0) 

    # now cull the matches list down to only those with a match 
    find.match <- find.match[ sapply(find.match, length) > 0 ] 

    # get rid of NA matches (not sure why these come up) 
    matches <- matches[ sapply(find.match, is.na) == FALSE ] 

    # now only return the value (reference to the match) if there is one (otherwise we get empty returns) 
    ifelse(length(matches) == 0, NA_integer_, matches) 
}) 

# now use the vector of references to match up country names 
df$country <- countrycode_data$country.name.en[ matches ] 

> df 
         string   country 
1  Russia is cool (2015) Russian Federation 
2    I like - China    China 
3 Stuff happens in North Korea    <NA> 

주 : 세 번째 문자열 "물건이 북한에서 일어나는"는 countrycode_data 세트 (128)를 행하기 위해 일치해야하지만 그렇지 않습니다. 그 이유는 정규식 (^(?=.*democrat|people|north|d.*p.*.r).*\bkorea|dprk|korea.*(d.*p.*r))이 "북쪽"이 문자열의 시작이어야한다고 지정하는 것 같습니다. 나는 정규 표현식으로 나 자신이 좋지 않다. 그러나 나는 이것이 ^이 지정하는 것이라고 믿는다.

다음
grepl("^(?=.*democrat|people|north|d.*p.*.r).*\\bkorea|dprk|korea.*(d.*p.*r)", 
     c("korea", "north korea", "aaa north korea"), 
     perl = TRUE, ignore.case = TRUE) 
# [1] FALSE TRUE FALSE 
0

나는이에 for 루프와 함께 갈 것

library(countrycode) 
data(countrycode_data) 

library(data.table) 
df <- data.table(string = c("Russia is cool (2015) ", 
          "I like - China", 
          "Stuff happens in North Korea"), 
       stringsAsFactors = FALSE) 

# adding dummy for full cross-join merge 
df$dummy <- 0L 
country.dt <- data.table(countrycode_data[, c("country.name.en", "country.name.en.regex")]) 
country.dt$dummy <- 0L 

# merging original data to countries to get all possible combinations 
res.dt <- merge(df, country.dt, by ="dummy", all = TRUE, allow.cartesian = TRUE) 

# there are cases with NA regex 
res.dt <- res.dt[!is.na(country.name.en.regex)] 

# find matches 
res.dt[, match := grepl(country.name.en.regex, string, perl = T, ignore.case = T), by = 1:nrow(res.dt)] 

# filter out matches 
res.dt <- res.dt[match == TRUE, .(string, country.name.en)] 
res.dt 

#     string country.name.en 
# 1: Russia is cool (2015) Russian Federation 
# 2:   I like - China    China 
+1

결국 행 조작으로 수행하는 경우 교차 결합이 필요한 이유는 무엇입니까? 단순한'sapply' IMO를 할 수 있을까요? –

+0

이 특별한 경우에 예상되는 일치 수가 적기 때문에 아주 좋은 해결책은 아닙니다. 하지만 비슷한 일을 할 때 유용 할 수 있습니다. – Bulat

2

이것은 countrycode 패키지의 목적과 정확히 동일하므로 직접 코드를 다시 코딩 할 이유가 없습니다. 그냥 이렇게 사용해라.

library(countrycode) 
df <- data.frame(string = c("Russia is cool (2015) ", "I like - China", 
          "Stuff happens in North Korea"), stringsAsFactors = FALSE) 

df$country.name <- countrycode(df$string, 'country.name', 'country.name') 

"물건이 북한에서 일어나는"특별히이 경우, 명확한 일치를 찾을 수 없습니다,하지만 실제로 북한과 한국에 대한 정규 표현식에 문제입니다 (나는 여기에 대한 문제를 열었다 https://github.com/vincentarelbundock/countrycode/issues/139). 그렇지 않으면, 당신이하고 싶은 것은 원칙적으로 작동해야합니다.

(그래서 country.name 지금 country.name.en입니다 countrycode의 새 버전이 그냥 크랑에 출시 된 v0.19 우리가 새로운 언어를 추가하기 때문에 열 이름이 조금 변경하고, regex 지금 country.name.en.regex입니다. 보조 노트는 특히 @ulfelder합니다)

1

나는 국가 코드 관리자입니다. @ cj-yetman이 정답을주었습니다. 귀하가 직면 한 구체적인 북한 문제는 Github의 countrycode 개발 버전에서 수정되었습니다. ?

당신은 국가 이름 또는 코드로 문장을 변환하는 직접 COUNTRYCODE를 사용할 수 있습니다, 신경 끄시 고,

> library(devtools) 
> install_github('vincentarelbundock/countrycode') 
> library(countrycode) 
> df <- data.frame(string = c("Russia is cool (2015) ", 
+        "I like - China", 
+        "Stuff happens in North Korea"), 
+     stringsAsFactors = FALSE) 
> df$iso3c = countrycode(df$string, 'country.name', 'country.name') 
> df 
         string         iso3c 
1  Russia is cool (2015)      Russian Federation 
2    I like - China         China 
3 Stuff happens in North Korea Democratic People's Republic of Korea 
나는`countrycode_data` 데이터 프레임의`regex` 열을 확인할 수 없습니다
+1

고마워요, 빈센트! 한 가지 방법으로,'countrycode'를 얻기 전에 좀 더 일반적인 대답을 얻었 기 때문에 기쁘다. 문제를 해결하는 패키지가없는 상황에서 다시 한번 나에게 올 수 있기 때문이다. – ulfelder

+0

거기에 'countrycode'를 사용하여 하나의 문자열에 여러 국가 이름을 붙잡는 효율적인 방법이 있습니까? 예를 들어, "수단 및 남부 수단 사무 총장 보고서"라는 문자열이 있고 "수단, 남부 수단"과 같은 문자열을 반환하고 싶다면 어떻게해야합니까? 나는 붕괴하는 법을 안다. 그것은 나를 괴롭히는 하나 이상의 경기를 반환합니다. – ulfelder

+1

국가 코드가 붙어 있지 않은 상태이지만 내부 코드를 보면 패키지가 이미 여러 일치 항목을 추적합니다. 같은 코드를 사용하여''destination_list''를 잡을 수 있습니다. 여기를 참조하십시오 : https://github.com/vincentarelbundock/countrycode/blob/master/R/countrycode.R#L123 – Vincent