2017-09-06 2 views
2

Tibbleを関数呼び出しのパラメータリストに変換しようとしています。私がこれをやっている理由は、さまざまな列を持つ複数の固定幅ファイルを読み込むための単純なファイル指定Tibbleを作成したいからです。このようにして、プルとセレクトを使用してファイル内のカラムを指定するだけで、ファイルを自動的にロードして解析することができます。しかし、私は列の形式を指定するcolsオブジェクトを使用して問題に挑戦しています。Tibbleをパラメータリストに変換

> (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のオブジェクトで終わるしたい:

> (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) 
) 

私が読んだ他の質問から、この例では

は、私はフォーマットのTibbleを持っていると仮定することができます私はdo.callでこれができることを知っています。しかし、列IDと型を自動的に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が何をするのか理解していると思います。他のパラメータを引数として呼び出す関数です。下の答えに対する私のコメントによると、ここで私を逃れることは、自動化された方法で名前付きリストを作成する方法です。私はフィールド=タイプのパラメータをすべて手作業で入力する必要はありません、私は2つのカラムにそれらを持っています、私はちょうど私のために名前付きリストを作成したい。 – 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はこれを達成するために2つの便利な機能(それぞれparseeval)を提供します。しかし、2つの簡単な機能の存在があなたを欺くことは許さないでください。それは信じられないほど複雑な操作です。 Rは基本的に、コード断片に対して完全なパーサーとインタプリタを実行する必要があります。コードがあなたが期待しているものでないなら、それはさらに毛がいっぱいになります。たとえば、テキストにの代わりにコードunlink('/', recursive = TRUE)が含まれている可能性があります。 Rはあなたのハードドライブを喜んで消去します。

これは、parse/evalが複雑で一般的に避けられる理由のうち、の1つです。です。その他の理由としては、コードに解析エラーがあるとどうなりますか(実際にはコードには閉じ括弧がありません...)?

しかし、ここに行きます。今、私たちは一緒にすべてのピースを持っていることを、私たちは、比較的容易にそれらを結合することができます

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

私はこのソリューションが好きで、うまくいきます!私がチベットを使用していた主な理由は、最終的に50〜60列を持ち、ソースファイルのそのリストを維持することが迷惑になる可能性があるからです。そのため、CSV経由で読み込みを行うことを望んでいました。私が必要とする2つの列を取り込み、リストにする簡単な方法はありますか?私はRには新しく、自動化された方法で名前付きリストを作成する方法が私を逃していると思います。 – RandomString

関連する問題