2017-04-24 3 views
2

いくつかの論理カラムを含むデータセットがあり、「TRUE」の値を対応するカラム名に置き換えます。私は同様の質問hereを尋ね、他のS/Oユーザーからの示唆の助けを借りて適切なソリューションを特定することができました。しかし、このソリューションでは、data.table構文を使用せず、参照で置き換える代わりにデータセット全体をコピーするため、時間がかかります。R論理カラムの正の値をdata.table構文を使用してカラム名に置き換えます。

data.tableの構文を使用してこれを行う最も適切な方法は何ですか?

私はこれを試みた:

# Load library  
library(data.table) 

# Create dummy data.table: 
mydt <- data.table(id = c(1,2,3,4,5), 
        ptname = c("jack", "jill", "jo", "frankie", "claire"), 
        sex = c("m", "f", "f", "m", "f"), apple = c(T,F,F,T,T), 
        orange = c(F,T,F,T,F), 
        pear = c(T,T,T,T,F)) 

# View dummy data: 
> mydt 
    id ptname sex apple orange pear 
1: 1 jack m TRUE FALSE TRUE 
2: 2 jill f FALSE TRUE TRUE 
3: 3  jo f FALSE FALSE TRUE 
4: 4 frankie m TRUE TRUE TRUE 
5: 5 claire f TRUE FALSE FALSE 

# Function to recode values in a data.table: 
recode.multi <- function(datacol, oldval, newval) { 
    trans <- setNames(newval, oldval) 
    trans[ match(datacol, names(trans)) ] 
} 

# Get a list of all the logical columns in the data set: 
logicalcols <- names(which(mydt[, sapply(mydt, is.logical)] == TRUE)) 

# Apply the function to convert 'TRUE' to the relevant column names: 
mydt[, (logicalcols) := lapply(.SD, recode.multi, 
           oldval = c(FALSE, TRUE), 
           newval = c("FALSE", names(.SD))), .SDcols = logicalcols] 

# View the result: 
> mydt 
    id ptname sex apple orange pear 
1: 1 jack m apple FALSE apple 
2: 2 jill f FALSE apple apple 
3: 3  jo f FALSE FALSE apple 
4: 4 frankie m apple apple apple 
5: 5 claire f apple FALSE FALSE 

これは置換値に対する各カラム名を反復としての代わりに補正されていない、それだけで最初のもの(ここでは「りんご」)をリサイクル。

私は古いものと新しい値の順序を逆にあればまた、機能が第2の値のための私の文字列置換を無視し、すべての場合に代替品として最初の2列名を使用しています。

# Apply the function with order of old and new values reversed: 
mydt[, (logicalcols) := lapply(.SD, recode.multi, 
           oldval = c(TRUE, FALSE), 
           newval = c(names(.SD), "FALSE")), .SDcols = logicalcols] 

# View the result: 
> mydt 
    id ptname sex apple orange pear 
1: 1 jack m apple orange apple 
2: 2 jill f orange apple apple 
3: 3  jo f orange orange apple 
4: 4 frankie m apple apple apple 
5: 5 claire f apple orange orange 

私は」私はおそらく何かシンプルなものがありませんが、なぜ関数が列名を反復しないのか(そしてこれを行うためにそれを編集する方法)を知っていますか?次のように

私の予想される出力は次のようになります。

> mydt 
    id ptname sex apple orange pear 
1: 1 jack m apple FALSE pear 
2: 2 jill f FALSE orange pear 
3: 3  jo f FALSE FALSE pear 
4: 4 frankie m apple orange pear 
5: 5 claire f apple FALSE FALSE 

これははるかに高く評価されるだろう達成するための簡潔なdata.table構文の代わりに他の提案。

+2

文字を使用する代わりに、論理的な、私は推測する任意の後の解析に痛みを伴うだろう。あなたの方法がうまくいかない理由について、 'lapply'は一度に一つのことを繰り返します(.SDここ)。 .SDと名前(.SD)を反復処理する必要がある場合は、Mapを試してみてください。 – Frank

+0

ありがとう - 'マップ'の構文例が見つかりませんでしたが、mapptのmapptのラッパーです - mapply(recode.multi、 datacol = .SD、 oldval = c(TRUE、FALSE)、 newval = c(名前(.SD)、 "FALSE")、 SIMPLIFY = FALSE)、。SDcols = logicalcols] 'は、FALSEの値がNAに変換されていることを除いて、ほとんど私をそこに置きます。 –

答えて

2

は、我々はmelt/dcastアプローチ

dcast(melt(mydt, id.var = c("id", "ptname", "sex"))[, 
    value1 := as.character(value)][(value), value1 := variable], 
      id + ptname + sex~variable, value.var = "value1") 
# id ptname sex apple orange pear 
#1: 1 jack m apple FALSE pear 
#2: 2 jill f FALSE orange pear 
#3: 3  jo f FALSE FALSE pear 
#4: 4 frankie m apple orange pear 
#5: 5 claire f apple FALSE FALSE 

を使用するか、別のオプションは、


nm1 <- which(unlist(mydt[, lapply(.SD, class)])=="logical") 
for(j in nm1){ 
    i1 <- which(mydt[[j]]) 
    set(mydt, i=NULL, j=j, value = as.character(mydt[[j]])) 
    set(mydt, i = i1, j=j, value = names(mydt)[j]) 
} 

mydt 
# id ptname sex apple orange pear 
#1: 1 jack m apple FALSE pear 
#2: 2 jill f FALSE orange pear 
#3: 3  jo f FALSE FALSE pear 
#4: 4 frankie m apple orange pear 
#5: 5 claire f apple FALSE FALSE 
やコメントで述べた別のオプションが

で、より効率的である setであります
mydt[, (nm1) := Map(function(x,y) replace(x, x, y), .SD, names(mydt)[nm1]), .SDcols = nm1] 
mydt 
# id ptname sex apple orange pear 
#1: 1 jack m apple FALSE pear 
#2: 2 jill f FALSE orange pear 
#3: 3  jo f FALSE FALSE pear 
#4: 4 frankie m apple orange pear 
#5: 5 claire f apple FALSE FALSE 

UPDATE:18573行と650列からなるデータセットで、オプション2と3を比較します(そのうちの1つは非論理列の数のため不可能です)。そのうちの252列は、次のタイミングで論理実行されます。

# Option 2: 
    nm1 <- which(unlist(mydt[, lapply(.SD, is.logical)])) 
    system.time( 
    for(j in nm1){ 
    i1 <- which(mydt[[j]]) 
    set(mydt, i=NULL, j=j, value = as.character(mydt[[j]])) 
    set(mydt, i = i1, j=j, value = names(mydt)[j]) 
    } 
    ) 
# user system elapsed 
# 0.61 0.00 0.61 

# Option 3: 
system.time( 
    mydt[, (nm1) := Map(function(x,y) replace(x, x, y), .SD, names(mydt)[nm1]), .SDcols = nm1] 

    ) 
#user system elapsed 
#0.65 0.00 0.66 

の両方がdata.table構文を使用していない独創的なアプローチよりもかなり速いです:

# Original approach: 
logitrue <- which(mydt == TRUE, arr.ind = T) 
system.time(
    mydt[logitrue, ] <- colnames(mydt)[logitrue[,2]] 
) 
    # user system elapsed 
    # 1.22 0.03 4.22 
+0

ありがとうございますが、変更する列がデータセットのどこにあるのかわからない場合は適用可能ですが(ただし、すべての論理列のリストを作成して変更する列を特定できます。これを含める)。 .SDをmelt/dcastで使用することは可能ですか?また、上記のrecode.multi関数では、ロジックから文字への変換はすでに処理されていますが、これを使用する方が高速ですか? –

+0

@AmyM文字を値に再コーディングする前に論理を文字に変更する必要があります – akrun

+0

@AmyM指定する列名には何らかのパターンや何かがあるはずです。パターンがない場合は、変更する列をどのように知っていますか? – akrun

関連する問題