web-dev-qa-db-ja.com

リストから一意の値を見つける

値のリストがあるとします

x <- list(a=c(1,2,3), b = c(2,3,4), c=c(4,5,6))

すべてのリスト要素を組み合わせて一意の値を見つけたいです。これまでのところ、次のコードはトリックを行いました

unique(unlist(x))

誰もがより効率的な方法を知っていますか?私はたくさんの価値がある膨大なリストを持っているので、どんな高速化でも感謝します。

27
Roman Luštrik

Marekによって提案されたこのソリューションは、元のQに対する最良の回答です。他のアプローチと、Marekが最も有用である理由については、以下を参照してください。

_> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6
_

討論

より高速な解決策は、最初にxのコンポーネントでunique()を計算し、次にそれらの結果で最後のunique()を実行することです。これは、以下の両方の例のように、リストのコンポーネントに同じ数の一意の値がある場合にのみ機能します。例えば。:

最初にあなたのバージョン、次に私の二重のユニークなアプローチ:

_> unique(unlist(x))
[1] 1 2 3 4 5 6
> unique.default(sapply(x, unique))
[1] 1 2 3 4 5 6
_

matrixには1つのマージンを固定するuniqueメソッドがあるため、_unique.default_を呼び出す必要があります。行列はベクトルとして扱うことができるため、これは問題ありません。

マレックは、この回答に対するコメントで、unlistアプローチの遅い速度は、リスト上のnamesに起因する可能性があると指摘しています。 Marekの解決策は、unlistに_use.names_引数を使用することです。これを使用すると、上記の二重の固有バージョンよりも高速な解決策が得られます。 Romanの投稿の単純なxについては、

_> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6
_

Marekのソリューションは、コンポーネント間で一意の要素の数が異なる場合でも機能します。

次に、3つの方法すべてのタイミングを含むより大きな例を示します。

_## Create a large list (1000 components of length 100 each)
DF <- as.list(data.frame(matrix(sample(1:10, 1000*1000, replace = TRUE), 
                                ncol = 1000)))
_

DFを使用した2つのアプローチの結果は次のとおりです。

_> ## Do the three approaches give the same result:
> all.equal(unique.default(sapply(DF, unique)), unique(unlist(DF)))
[1] TRUE
> all.equal(unique(unlist(DF, use.names = FALSE)), unique(unlist(DF)))
[1] TRUE
> ## Timing Roman's original:
> system.time(replicate(10, unique(unlist(DF))))
   user  system elapsed 
  12.884   0.077  12.966
> ## Timing double unique version:
> system.time(replicate(10, unique.default(sapply(DF, unique))))
   user  system elapsed 
  0.648   0.000   0.653
> ## timing of Marek's solution:
> system.time(replicate(10, unique(unlist(DF, use.names = FALSE))))
   user  system elapsed 
  0.510   0.000   0.512
_

これは、二重のuniqueunique()を個々のコンポーネントに適用してからunique()に固有の値の小さいセットを適用するよりもはるかに速いことを示していますが、この高速化は純粋にリストnamesDFが原因です。 unlistnamesを使用しないように指定すると、この問題のMarekの解は、二重のuniqueよりもわずかに速くなります。マレックのソリューションは適切なツールを適切に使用しており、回避策よりも高速であるため、推奨されるソリューションです。

ダブルuniqueアプローチの大きな落とし穴は、ここの2つの例のように、ifのみが機能することです。入力リスト(DFまたはx)には、同じ数の一意の値があります。そのような場合、sapplyは結果を行列に整理し、_unique.default_を適用できるようにします。入力リストのコンポーネントの一意の値の数が異なる場合、二重の一意のソリューションは失敗します。

41
Gavin Simpson