2016-04-14 11 views
1

これは明白であるべきですが、私はまだlapplyとその親戚の周りに私の心を持っていないし、私はこれではっきりと簡単な答えを見つけていませんまたはGoogle。 noobnessのための謝罪とだから、ここに行く:カラム名tolower()再帰的に(データフレームのリスト内で)

私は、複数の埋め込みでリストを持って、このようなビット(hereから再現性の一例を捕物):

lst <- structure(list(Df1 = structure(list(Df1 = structure(list(Date = structure(c(14611, 14612), class = "Date"), Ta_200 = c(10.0067787761421, 5.9095282339839)), .Names = c("Date", "Ta_200"), row.names = c(NA, -2L), class = "data.frame"), Df2 = structure(list(Date = structure(c(14611, 14612), class = "Date"), rH_200 = c(64.9115310510325, 90.8615907551521)), .Names = c("Date", "rH_200"), row.names = c(NA, -2L), class = "data.frame")), .Names = c("Df1", "Df2")), Df2 = structure(list(Df1 = structure(list(Date = structure(c(14642, 14643), class = "Date"), Ta_200 = c(9.91976687351846, 8.79129183854663)), .Names = c("Date", "Ta_200"), row.names = c(NA, -2L), class = "data.frame"), Df2 = structure(list(Date = structure(c(14642, 14643), class = "Date"), rH_200 = c(76.9297879127307, 75.8021788747459)), .Names = c("Date", "rH_200"), row.names = c(NA, -2L), class = "data.frame")), .Names = c("Df1", "Df2"))), .Names = c("Df1", "Df2")) 

目標:すべてですべての列名を作ります小文字の場合はtolower()を使用し、2〜3レベルの深さの再帰リストの場合(ここのように)私はリストの要素をループすることができますが、ループを回避してapplyファミリとdplyrファミリからのものを使用するために、どこにでもある推奨事項に従おうとしています。

、私はこのようなダウンセカンドレベルのためlapplyを使用することができます。

lapply(lst, function(x) { names(x) <- tolower(names(x)) }) 

しかし:(1)私は、再帰的に第一及び第二(及び第3)レベルのためにこれを行う方法を理解しておらず、 (2)リスト項目に実際に新しい小文字の名前を書く方法がありません(上記の行は、それを返すだけです)。

+2

'setNames'は役に立ちます:' lapply(lst、function(x){setNames(x、tolower(names(x)))}) 'これは一度に1レベルだけです。 – alistaire

答えて

3

あなたは 小文字...

all_to_lower <- function(x) { 
    ## Update the name at the desired level, when present. 
    if (! is.null(names(x))) 
     names(x) <- tolower(names(x)) 
    ## Decide if an iterative step should be used. 
    if (is.list(x) & ! is.data.frame(x)) 
     x <- lapply(
      X = x, 
      FUN = all_to_lower) 
    ## Return to workflow. 
    x 
} 

all_to_lower(lst) 
$df1 
$df1$df1 
     date ta_200 
1 2010-01-02 10.006779 
2 2010-01-03 5.909528 

$df1$df2 
     date rh_200 
1 2010-01-02 64.91153 
2 2010-01-03 90.86159 


$df2 
$df2$df1 
     date ta_200 
1 2010-02-02 9.919767 
2 2010-02-03 8.791292 

$df2$df2 
     date rh_200 
1 2010-02-02 76.92979 
2 2010-02-03 75.80218 

編集に戻されるすべてのレベルですべての名前に対して異議がない ことを考えると、トリックを行います自分自身を再帰的に呼び出す関数:にですがもちろん、データフレームの名前だけが影響を受けるように関数を微調整することも可能です。単に(! is.null(names(x)))(! is.null(names(x)) & is.data.frame(x))に置き換えてください。

+0

ラブリー。私はこれが '再帰的適用 'のような'再帰的適用'ができることを意図しているが、それを働かせることができなかったのだと思う。あなたの解決策はエレガントで汎用性があり、自分のデータのために働く。 – strangeloop

+0

私は 'rapply 'もやってみましたが、なぜそれがうまくいかなかったのか少し混乱しました。しかし、@alistaireの答えにコメントされているように、 'rapply'は' data.frame'もまた 'list'であるため、ここで問題に遭遇し、それから私たちが望む以上に一歩歩きます。他のデータ型については、私たちが期待しているように 'rapply'も動作するはずです。 –

1

ここでは2つのレベルの問題の1つの解決方法を示します。それはあなたのdata.framesに複数のデータ型を持っている場合は有用である可能性がある文字ベクトル、のためにこのルーチンをチェックし

# double lapply with as.data.frame wrapping second lapply 
noCapsData <- lapply(lst, function(level2) lapply(level2, 
        function(dfnames) setNames(dfnames, tolower(names(dfnames))))) 

ビット密です。

+0

この例では、 'lst'で呼び出されたときに何か違うものを返します。 – alistaire

+0

@alistaire申し訳ありません。私はタイトルを読んで、データの内容を変更する何かを書きました。フレーム。しかし、体の中でOPは変数の名前について質問しています。私は変更を行います。 – lmo

+0

はい、申し訳ありませんが、質問とその回答を反映するタイトルを編集しました。 – strangeloop

0

lapplysetNamesは、リストの深さの階層数に応じてネストできます。すべてdata.framesは単一レベルにある場合、あなたはさまざまなレベルでdata.framesを持っている場合、あなたは繰り返し処理している項目があるかどうかを確認する必要があるかもしれません

lapply(lst, function(x){lapply(x, function(y){setNames(y, tolower(names(y)))})}) 

ようなもので逃げることができますdata.frames:

lapply(lst, function(x){if(is.data.frame(x)){ 
    setNames(x, tolower(names(x))) 
    } else { 
    lapply(x, function(y){if(is.data.frame(y)){ 
     setNames(y, tolower(names(y))) 
    }}) 
}}) 

リストが深くなったら、もう一度繰り返します。

lapplyの再帰バージョンが存在しますが、data.framesで正しく動作するようにするのは、data.framesがリストであるためです。

+0

確かに、私は最初に 'rapply'が私の必要とするものだと思っていましたが、それが真実かもしれませんが、私はそれを働かせることができませんでした。私は@ lars-arne-jordangerの再帰関数である最も一般的な解を受け入れました。 – strangeloop

関連する問題