2011-07-19 8 views
2

非常にユニークでない値のベクトルがあります。リストを値を共有しないリストのサブセットに分割するR

私はこのベクトルを4つのほぼ同じ長さのベクトルに分割したいと思います.2つのベクトルに同じ値を入れることはできませんが、4つのベクトルのそれぞれに1つ以上の異なる値を含めることができます。

例:

List <- c(1,1,1,2,3,3,5,5,5,5,9,11,11) 

LIST1 = 1,1,1 LIST2 = 2,3,3 LIST3 = 5,5,5,5 list4 = 9,11,11

Rでこれを実装する最良の方法は何ですか?

+0

リストに基づいてリストを分割しますか?シーケンス?もしそうなら、 'rle()'を試してください。どのサブリストに入るかを判断する基準は何ですか(サブリストに複数の値がある場合など)。 –

+0

サブリストには値が8つあり、サブリストが4つある可能性があるため、複数の値を持つことができます。各値は1つのサブリストにのみ属していなければなりません。 –

+0

あなたの目的について少し話していただけますか?つまり、あなたが4つに壊れた後にベクターで何をするつもりですか?彼らはカテゴリ変数か連続変数ですか? –

答えて

1

ここでは、あなたが望むような音に近い非常に平凡なアルゴリズムがあります。それが改善される可能性がで

n.groups <- 4 
L <- c(1,1,1,2,3,3,5,5,5,5,9,11,11) 
N <- length(L) 

L <- sort(L) 
L.rle <- rle(L) 

ave.grp.length <- N/n.groups 

lgths <- L.rle$lengths 
vals <- L.rle$values 

res <- list(one=c(),two=c(),three=c(),four=c()) 
l <- 1 
for(i in seq(length(vals))) { 
    if(sum(res[[l]])>=ave.grp.length & l<n.groups) { 
    l <- l+1 
    } 
    res[[l]] <- c(res[[l]], rep(vals[i],lgths[i])) 
} 

方法:

  • あなたはあなたのリストが非常に大きいと言うので、あなたは凝縮形であなたの出力を好むかもしれません。凝縮したデータを複製するのは非効率的なので、計算時間を大幅に節約できます。
  • 現在、順番に動作しています。これは計算が簡単で高速です。できるだけ類似した大きさになるようにグループを強くしたいのであれば、他のアルゴリズムで混乱させることもできますし、最後にやり直すために2番目のパスを追加することもできます。
  • それのループベース、めったにR.で物事を行うための最善の方法ではありません
2

EDIT:元の質問の後のコメントに基づいて

、あなたは、単に行うことができます。

my.sample <- function(x,n){ 

    samples <- rle(List)$lengths 
    ng <- length(samples) 
    groups <- cut(1:ng,n,labels=FALSE) 
    reps <- tapply(samples,groups,sum) 
    rep(1:n,reps) 

} 
> my.sample(List,4) 
[1] 1 1 1 1 2 2 3 3 3 3 4 4 4 

ベクトルを取得するにはsplit()で使用できます。


c(1,1,1,1,1,1,1,1,1,2,2,3,3,4,4)のようなベクトルを持つことを開始すると問題が発生します。

  • は、n個のグループにそれらを組み合わせたユニークな値のベクトルのリストでベクトルを分割:あなたがシフトする順序を気にしない場合は、次のロジックに基づいて、そのための機能を構築することができます
  • グループを超えて、それらの長さがすべて同じかそれより短いかどうかを確認します。そうでない場合は、値の大きいものから小さいものに切り替えます。
  • 差が全体の長さのモジュラスおよびグループの数よりも少ない、またはあなたは、アルゴリズムを実行するまで続行10倍(一部の極端な場合にあなたがループしながら、無限に終わる可能性)
を言います

これは、このようなとして適用することができ、以下の機能

my.sample <- function(x,n){ 
    # these are the unique values from which to sample 
    samples <- split(x,x) 
    ns <- length(samples) 

    groups <- list() 
    # make sure that sample() returns n groups 
    while(length(groups)!=n){ 
    groups <- split(samples,sample(1:n,ns,replace =TRUE)) 
    } 

    count <- 0 
    lgroups <- c(1,ns) 

    while(diff(range(lgroups)) > ns%%n & count < 10){ 

    lgroups <- sapply(groups,function(i)length(unlist(i))) # length of groups 
    ngroups <- sapply(groups,length) # number of unique values 
    id <- which(ngroups > 1) # which groups have more than one unique value 

    #switch one value from the largest to the smallest group 
    gmin <- which.min(lgroups) 
    gmax <- id[which.max(lgroups[id])] 
    gsw <- sample(1:length(groups[gmax]),1) 
    groups[[gmin]] <- c(groups[[gmin]],groups[[gmax]][gsw]) 
    groups[[gmax]] <- groups[[gmax]][-gsw] 
    count <- count+1 
    } 
    # create the output 
    lapply(groups,unlist,use.names=FALSE) 

} 

を与える:

> my.sample(List,4) 
$`1` 
[1] 5 5 5 5 

$`2` 
[1] 11 11 2 

$`3` 
[1] 3 3 9 

$`4` 
[1] 1 1 1 

それはまだあなた自身のニーズに微調整されることができ、これはRのようなやり方です。

1

これはrleを使用する点でgsk3の解法に似ていますが、代わりに目的の分位数に最も近い分裂を見つけようとします。 (これは、off-by-oneエラーに苦しむことがあり、私は分位とかなり正確rleからの結果を比較していないよと思う。)

mysplit <- function(List, n) { 
    q <- length(List)*(1:(n-1))/n 
    d <- cumsum(rle(List)$lengths) 
    x <- d[apply(abs(outer(q, d, `-`)),1,which.min)] 
    x <- c(0,x,length(List)) 
    lapply(1:n, function(i) List[(x[i]+1):x[i+1]]) 
} 

の出力で:

> List <- c(1,1,1,2,3,3,5,5,5,5,9,11,11) 
> mysplit(List, 4) 
[[1]] 
[1] 1 1 1 

[[2]] 
[1] 2 3 3 

[[3]] 
[1] 5 5 5 5 

[[4]] 
[1] 9 11 11 

にも注意してくださいグループが正の長さを持つように一意の識別子が十分にある場合にのみ機能します。特にJorisの例では機能しません。

等しい長さが重要でない場合は、より簡単な方法です。 4つのグループを一度に1つの固有の値で順番に満たします。

mysplit2 <- function(List, n) { 
    spl <- split(List, List) 
    lapply(0:(n-1), function(x) unname(unlist(spl[(seq_along(spl)-1) %% n == x]))) 
} 

おそらく遅いですが、かなり簡単です。

1

グループを「完全」にかなり近づけようとする試みでは、値を最も反復回数の少ないものとペアにすることによって試みます。梱包の面では最適ですが、かなり速いです。 data.frame全体をバッチに簡単に分割できるように、ベクターを返します。

bucket = function(x, n) { 
    x = factor(x) 
    l = table(x) 
    g = as.list(names(l[l >= n])) 
    l = sort(rev(l[l < n])) 
    while (length(l)) { 
    big = names(which(cumsum(rev(l)) <= n)) 
    left = n - sum(l[big]) 
    l = l[seq_len(length(l) - length(big))] 
    small = names(which(cumsum(l) <= left)) 
    l = l[seq_len(length(l) - length(small)) + length(small)] 
    g = c(g, list(c(small, big))) 
    } 
    unname(setNames(rep(seq_along(g), sapply(g, length)), unlist(g))[levels(x)][x]) 
} 

x = c(1,1,1,1,1,1,1,2,3,3,5,5,5,5,9,11,11) 
n = 4 

split(x, bucket(x, 4)) 
関連する問題