2016-05-20 5 views
4

かなりの数の列を持つdata.tableがあります。私はそれらをループし、いくつかの条件を使用して新しい列を作成する必要があります。現在、私は各列ごとに別々の行を書いています。例を挙げて説明しましょう。私たちのようにサンプルデータを見てみましょう -data.tableをループして新しい列を作成する条件があります

合計1から列ごとに
set.seed(71) 

DT <- data.table(town = rep(c('A','B'), each=10), 
       tc = rep(c('C','D'), 10), 
       one = rnorm(20,1,1), 
       two = rnorm(20,2,1), 
       three = rnorm(20,3,1), 
       four = rnorm(20,4,1), 
       five = rnorm(20,5,2), 
       six = rnorm(20,6,2), 
       seven = rnorm(20,7,2), 
       total = rnorm(20,28,3)) 

、私は4つの新しい列を作成する必要がある、つまり意味し、SD、UPLIMIT、2シグマ外れ値の計算のためのLowLimitの。私がすることでこれをやっている -

DTnew <- DT[, as.list(unlist(lapply(.SD, function(x) list(mean = mean(x), sd = sd(x), uplimit = mean(x)+1.96*sd(x), lowlimit = mean(x)-1.96*sd(x))))), by = .(town,tc)] 

私は、外れ値を思い付くために私DT

DTmerge <- merge(DT, DTnew, by= c('town','tc')) 

と合併しています。このDTnewのdata.tableを、私は、各変数のコードの別個のセットを書いています -

DTAoutlier <- DTmerge[ ,one.Aoutlier := ifelse (one >= one.lowlimit & one <= one.uplimit,0,1)] 
DTAoutlier <- DTmerge[ ,two.Aoutlier := ifelse (two >= two.lowlimit & two <= two.uplimit,0,1)] 
DTAoutlier <- DTmerge[ ,three.Aoutlier := ifelse (three >= three.lowlimit & three <= three.uplimit,0,1)] 

は、いくつかのいずれかの助けには、このコードを簡素化することができますので、

  1. 私は外れ値のコードを別々に書く必要はありません。この例では8つの変数しかありませんが、100の変数があれば、100行のコードを書くことになりますか? forループを使ってこれを行うことはできますか?どうやって?

  2. 一般的にdata.tableの場合、元の列を保持する新しい列を追加するにはどうすればよいですか。例えば、以下の例では、3列目から10列目のログを取っています。新しいDTlogを作成しないと、DTの元の列が上書きされます。どのように私は元の列をDTに保持し、DTで新しい列を持つことができます。

    DTlog <- DT[,(lapply(.SD,log)),by = .(town,tc),.SDcols=3:10]

一部の専門家のアドバイスをお楽しみください。

+1

私はあなたが特に 'data.table'解決策を探している知っているが、あなたが探していることは本質的であることに注意することは、'役に立つかもしれませんdata.table'は 'dplyr'の' mutate_each'に相当します – shreyasgm

+0

@shreyasgm回答を投稿する – eddi

+0

@Prasadこれは何をしているのですか?あなたはなぜ同じグループに同じ4つの数字を繰り返し書いていますか? – eddi

答えて

4

:=を使用してください。グループ化変数ではない列名( 'nm')をサブセット化します。 outer( 'nm1')を使用して新しい列に割り当てる名前のvectorを作成します。次に、OPコード「unlist」を使用して、出力を「nm1」に割り当て(:=)、新しい列を作成します。

nm <- names(DT)[-(1:2)] 

nm1 <- c(t(outer(c("Mean", "SD", "uplimit", "lowlimit"), nm, paste, sep="_"))) 

DT[, (nm1):= unlist(lapply(.SD, function(x) { Mean = mean(x) 
            SD = sd(x) 
        uplimit = Mean + 1.96*SD 
        lowlimit = Mean - 1.96*SD 
      list(Mean, SD, uplimit, lowlimit) }), recursive=FALSE) , 
        .(town, tc)] 

質問の第2の部分は、列の論理比較を行うことです。 1つのオプションは、最初の列である 'lowlimit'と 'uplimit'列を別々にサブセット化し、比較を行う(これらは同じ次元であるため)、+でバイナリに強制変換できる論理出力を得ることです。次に、それを元のデータセットに割り当てて外れ値の列を作成します。

m1 <- +(DT[, nm, with = FALSE] >= DT[, paste("lowlimit", nm, sep="_"), 
      with = FALSE] & DT[, nm, with = FALSE] <= DT[, 
      paste("uplimit", nm, sep="_"), with = FALSE]) 
DT[,paste(nm, "Aoutlier", sep=".") := as.data.frame(m1)] 

代わりに、データを比較します。テーブルは、我々はまた、(より効率的である)setforループ

nm2 <- paste(nm, "Aoutlier", sep=".") 
DT[, (nm2) := NA_integer_] 
for(j in nm){ 
set(DT, i = NULL, j = paste(j, "Aoutlier", sep="."), 
    value = as.integer(DT[[j]] >= DT[[paste("lowlimit", j, sep="_")]] & 
      DT[[j]] <= DT[[paste("uplimit", j, sep="_")]])) 
} 

を使用することができ、列も:=

DT[,paste(nm, "log", sep=".") := lapply(.SD,log),by = .(town,tc),.SDcols=nm] 
+0

ありがとうございますAkrun !!また、コードの一部を説明してください。実際に何をしているのですか?なぜ 'with = FALSE'を使用していますか?その後、forループで、設定された部分について詳しく説明してください。なぜ私は 'i = NULL'と言っているのですか?また、DT [[j]]という2つの角括弧を付ける必要があるのはなぜですか?申し訳ありませんが、いくつかの基本的な質問をしているかもしれませんが、明確にすることができればすばらしいでしょう。また、あなたはdata.tablesとそのような操作の例についてもっと理解する良い情報源を指摘できますか? – user1412

+1

@Prasad '+'は、論理行列を2進行列に変換するうえでのヒントです。 'as.integer'や' as.numeric'と同じように動作しますが、構造体も保持します。 '?data.table'を読んだら、列をサブセッティングするための' with = FALSE'について言及しています。列のすべての行が変更されるため、行の条件は設定されません。行に何らかの値がある行の値を変更するなどの特定の条件があった場合は、それを 'i'で指定することができます。あなたは、ビネットを見て、data.tableの詳細を読むことができます。 – akrun

3

あなたのデータは、おそらく長い間であるべきで作成することができる「ログ」形式:

m = melt(DT, id=c("town","tc")) 

それからちょうど

一度テストを書きます
m[, 
    is_outlier := +(abs(value-mean(value)) > 1.96*sd(value)) 
, by=.(town, tc, variable)] 

私が(外れ値の与えられた定義によれば)、このデータには外れ値を見ない:それは

  • melt仕組み

    m[, .N, by=is_outlier] # this is a handy alternative to table() 
    
    # is_outlier N 
    # 1:   0 160 
    

    は、すべての残りid列とスタックを保持します〜

    • variable(列名)
    • value(列の内容)
  • +xあなたが実際にも、ワイドフォーマットでデータを好きなら1/0

にTRUE/FALSEを強制する、as.integer(x)と同じことを行います:

vjs = setdiff(names(DT), c("town","tc")) 
DT[, 
    paste0(vjs,".out") := lapply(.SD, function(x) +(abs(x-mean(x)) > 1.96*sd(x))) 
, by=.(town, tc), .SDcols=vjs] 
+0

こんにちはフランク、テストコードで非常に明確ではありません。どうして '+(abs(value-mean(value))'と書かれているのですか? – user1412

+0

@Prasad申し訳ありませんが、それらを説明するのを忘れましたが、今編集しました。他に何か不明な点がある場合は教えてください – Frank

0

完全性については、dplyrmutate_eachは、このような問題に取り組むのに便利な方法を提供します:

library(dplyr) 

result <- DT %>% 
    group_by(town,tc) %>% 
    mutate_each(funs(mean,sd, 
        uplimit = (mean(.) + 1.96*sd(.)), 
        lowlimit = (mean(.) - 1.96*sd(.)), 
        Aoutlier = as.integer(. >= mean(.) - 1.96*sd(.) & 
               . <= mean(.) - 1.96*sd(.))), 
       -town,-tc) 
関連する問題