2017-09-06 9 views
2

Tibble을 함수 호출을위한 매개 변수 목록으로 변환하려고합니다. 내가이 일을하는 이유는 여러 열로 여러 개의 고정 너비 파일을 읽는 간단한 파일 사양 Tibble을 만들고 싶기 때문입니다. 이 방법은 pull과 select를 사용하여 파일에있는 열만 지정하면 파일을 자동으로로드하고 파싱 할 수 있습니다. 그러나 cols 개체를 사용하여 열 형식을 지정하는 데 문제가 있습니다. 다른 질문에서Tibble을 매개 변수 목록으로 변환

> (cols(Title = col_character(), Date = col_date(), ATTR=col_factor(levels=c(123456,654321)))) 
cols(
    Title = col_character(), 
    Date = col_date(format = ""), 
    ATTR = col_factor(levels = c(123456, 654321), ordered = FALSE) 
) 

내가 읽고 :

> (filespec <- tibble(ID = c("Title", "Date", "ATTR"), Length = c(23, 8, 6), Type = c("col_character()", "col_date()", "col_factor(levels=c(123456,654321)"))) 
# A tibble: 3 x 3 
    ID Length        Type 
    <chr> <dbl>        <chr> 
1 Title  23     col_character() 
2 Date  8       col_date() 
3 ATTR  6 col_factor(levels=c(123456,654321) 

내가 형식의 COLS 객체와 끝까지하려는 :이 예를 들어

내가 형식의 Tibble가 있다고 가정 할 수 있습니다 do.call로이 작업을 수행 할 수 있다는 것을 알고 있습니다. 그러나 컬럼 ID와 Type을 자동화 된 방식으로 cols 객체로 변환하는 방법을 알 수는 없습니다. 여기 는
> do.call(cols, select(filespec,ID, Type)) 
Error in switch(x, `_` = , `-` = col_skip(), `?` = col_guess(), c = col_character(), : 
    EXPR must be a length 1 vector 
는 내가 매핑을 매개 변수 행을 수행하는 다른 기능을 포장 할 수있는 선택의 요구를 가정하고

, 어떻게이

을 수행 ... 내가 뭘하려의 예입니다?

+1

당신은'do.call'을 사용하여이 일을 할 수도 있지만, 여러분의 코드는 원격지에서 여러분이 원하는대로 행동하지 않습니다 - 먼저 do.call이 실제로 무엇을하는지 먼저 이해해야합니다 그것을 사용할 수 있습니다. –

+0

저는 R에 익숙하지 않습니다. 그래서 이것은 모든 학습 경험입니다. 나는 do.call이하는 일을 이해하고 있다고 생각합니다. 다른 매개 변수를 인수로 사용하여 함수를 호출합니다. 아래 답변에 대한 내 의견에 따라 나는 여기에서 나를 도피하는 것이 자동화 된 방식으로 명명 된 목록을 만드는 방법이라고 생각합니다. 필자는 모든 field = type 매개 변수를 직접 손으로 입력하지 않아도되고, 두 개의 열이 있는데, R이 나를 위해 명명 된 목록을 만들길 원합니다. – RandomString

+0

예, 실제로 문제 설명에 집중하고 있습니다. 당신의 질문에서 당신이 이걸 이해 한 것처럼 보이지 않았습니다. 그러나 문제의이 부분은 실제로'setNames'를 사용하여 쉽게 해결할 수 있습니다. 또 다른 큰 문제는 매개 변수가 코드가 아니라 문자열이라는 것입니다. 따라서 먼저 평가할 필요가 있으며 가능한 경우 (구문 분석/평가를 통해) 가능하지만 지저분하고 어쩌면 좋은 아이디어로 시작하지 않을 수도 있습니다 (경우에 따라 다를 수 있음). 조란의 접근 방식이 우수합니다. –

답변

0

TL; DR을 : 여러 가지가 있습니다 이것이 보이는 것보다 더 복잡하게 만듭니다. 그러나 실현 가능하며, 최종적으로 제공되는 결과 코드는 개별적인 부분이 이해되면 복잡하지 않습니다.

의견에서 설명한대로 나는 기본적으로 조란의 접근 방식을 선호합니다. 사실 코드 문자열을 문자열에 저장하면 언제든지 경고음을 울려 야합니다. stringly typed code (반점이 있고 strongly typed code과 매우 반대입니다)으로 알려진 반 패턴입니다. 불행히도 R은 문자열 형 코드로 가득차 있습니다.

그 말은입니다. 유스 케이스 (파일 기반 구성) 그 자체가 좋은 아이디어입니다. 정보를 R 코드 조각과 다른 형식으로 저장하는 것이 좋습니다. 그러나, 잘 작동합니다. 그래서 코드이 작동하지 않는 이유를 알아 보겠습니다.

첫 번째 문제는 다음과 같습니다. do.call으로 바꿉니다. Tibbles는 열 목록이므로 do.call에서 허용됩니다. 그러나 내부적으로 귀하의 전화는 다음과 같은 형식으로 변환됩니다.

cols(
    ID = c("Title", "Date", "ATTR"), 
    Type = c("col_character()", "col_date()", "col_factor(levels=c(123456,654321))") 
) 

-하지만 이것은 우리가 원하는 코드가 아닙니다!

우리는 여기서 두 가지 문제를 해결해야합니다

  1. 우리는 인수로 인수로 이름하고 ID 열을 Type 열을 사용해야합니다.우리는 이름으로 ID 그리고 Type을 값으로 갖는 새로운 목록을 만들어서 이것을 할 수 있습니다 : setNames(Type, ID).
  2. cols은 문자열 인수를 어떻게 처리해야할지 알지 못합니다. 열 지정 - Collector 유형의 개체가 필요합니다.

    다른 말로 표현하면 "col_date()" 또는 col_date()을 작성하는 것과 큰 차이가 있습니다. 우리는 R 코드와 Type 열을 구문 분석 태어나 셨, 우리는 결과 분석 식을 평가해야합니다

는이 문제를 해결하려면, 우리는 매우 복잡한 일을 할 필요가있다. R은 이것을 수행하기 위해 편리한 두 가지 기능 (각각 parseeval)을 제공합니다. 하지만 두 가지 쉬운 기능이 존재한다는 사실을 속여서는 안됩니다. 매우 복잡한 작업입니다. R은 본질적으로 코드 조각에 대해 전체 구문 분석기와 해석기를 실행해야합니다. 코드가 예상 한 것과 다르다면 더 털이 나옵니다. 예를 들어, 텍스트는 대신 unlink('/', recursive = TRUE) 코드를 포함 할 수 있습니다. 그러면 R이 행복하게 하드 드라이브를 지울 것입니다.

parse/ eval가 복잡하고 일반적으로 피할 이유 중입니다. 다른 이유는 다음과 같습니다. 코드에 구문 분석 오류가 있으면 어떻게됩니까? (실제로 코드에 누락 된 닫는 괄호가 포함되어 있습니다 ...)?

하지만 여기 있습니다. 이제 우리가 함께 모든 조각을 가지고, 우리는 상대적으로 쉽게 가입 할 수 있습니다 :

filespec %>% 
    mutate(Parsed = lapply(Type, function (x) parse(text = x, encoding = 'UTF-8'))) %>% 
    mutate(ColSpec = lapply(Parsed, eval)) %>% 
    with(setNames(ColSpec, ID)) %>% 
    do.call(cols, .) 

은 무엇을보고 제대로 작동하고 있다고 자신을 설득하는 부분으로이 코드 조각을 실행합니다.

+1

setNames/with 부분은 내가 필요한 것입니다. 나는 eval 문제에 대해 알았지 만, 나중에 그것을 고치려고했는데, 대부분은 유형 문자열 -> S3 객체에서 간단한 매핑으로 해결할 것입니다. – RandomString

1

내가 다른이에게 조금 접근, 간단한 목록에서 파일 사양을 저장할 수 있습니다 :

library(purrr) 
library(readr) 
filespec <- list(Title = list(Length = 23, 
           Type = col_character()), 
       Date = list(Length = 8, 
          Type = col_date()), 
       ATTR = list(Length = 6, 
          Type = col_factor(levels = 123456,654321))) 

a <- at_depth(.x = filespec,.depth = 1,.f = "Type") 
> invoke(.f = cols,.x = a) 

cols(
    Title = col_character(), 
    Date = col_date(format = ""), 
    ATTR = col_factor(levels = 123456, ordered = 654321, include_na = FALSE) 
) 

또는

> invoke(.f = cols,.x = a[c('Title','ATTR')]) 
cols(
    Title = col_character(), 
    ATTR = col_factor(levels = 123456, ordered = 654321, include_na = FALSE) 
) 
+0

나는이 해결책이 마음에 든다! 나가 tibble를 사용하고 있던 1 차적인 이유는 결국 50-60의 란이 있을지도 모르고 원본 파일에있는 그 명부를 유지하는 것이 성가시다 수 있었기 때문에, 나는 csv를 통해 안으로 읽는에서 그것을하는 것을 희망하고 있었다. 내가 필요로하는 두 개의 칼럼을 받아들이고 목록으로 변환하는 쉬운 방법이 있습니까? 나는 R에 익숙하지 않고 자동화 된 방식으로 명명 된 목록을 만드는 방법이 나를 벗어나고 있다고 생각합니다. – RandomString