MathematicaのClusteringComponentsの困ったところ

Mathematica 9.0, 10.0, 10.1, 10.2, 10.3, 10.4.1, 11.2, 11.3 for Microsoft Windows (64-bit)と10.0.0 for Linux ARM (32-bit)でのことです。

Mathematicaには、階層的クラスタリングができる関数が3つ用意されています。FindClustersAgglomerateClusteringComponentsです。

FindClustersにはバグがありました。(FindClustersのバグは11で解決)

Agglomerateにはバグがあります。

バグではありませんが、ClusteringComponentsにも困ったところがあります。データをn個のクラスタに分けたいと思ってClusteringComponents[array,n]としても、できるクラスタがnより少ないことがあるのです。マニュアルには「最高でn個のクラスタを求める」とあるので、nより少ないのはバグでは無いのですが、ちょうどn個のクラスタを作りたいときに使えないのは困ります。

次のコードで再現できます。

data = Import["https://gist.github.com/taroyabuki/4996086/raw/be3b2d537a51b803790fa1149cc714663a8b6ee9/clustering_test_data2.csv"];

Length[Union[ClusteringComponents[data, 13, 1, DistanceFunction -> EuclideanDistance, Method -> "Optimize"]]]
(* 12 *)

13個のクラスタを作りたかったのですが、できたクラスタは12個でした。

データをシャッフルしてからならうまくいきます。

Length[Union[ClusteringComponents[RandomSample@data, 13, 1, DistanceFunction -> EuclideanDistance, Method -> "Optimize"]]]
(* 13 *)

というわけで、階層的クラスタリングをしたいときはRを使うのがよさそうです(参考)。

フリーソフトウェアで風景から歩行者を消す方法(FFmpeg, ImageMagick)

先日「風景から歩行者を消す手軽な方法」をMathematicaで実装したのですが、「なんでMathematica? 持ってないし。高いじゃん」という意見があったので、フリーソフトウェアを使う方法を紹介しましょう。「風景から歩行者が消えていく様子」が要らないならこれで十分かも知れません。(Raspberry PiのMathematicaなら無料なのですが、非力なのでこの話には使いにくいでしょう。)

Ubuntuで試します。(WindowsでもFFmpegとImageMagickを入れればできるかもしれません。)

sudo apt-get install libav-tools imagemagick

ffmpegで動画を画像に分解し、convertでまとめます。(Ubuntu 14.04ではffmpegavconvに置き換えてください。)

ffmpeg -i movie.mov -f image2 %d.png
convert -evaluate-sequence mean *.png mean.jpg

meanmedianに置き換えれば平均ではなく中央値を使うようになりますが、処理時間がかなり増えます。

風景から歩行者が消えていく様子

先日紹介した「風景から歩行者を消す手軽な方法」は、動画の画素ごとに時間について平均をとると動いているものを消せるという話でした。

この方法について、(1)平均ではなく中央値や最頻値を使った方がいいのではないか、(2)シャッターを開きっぱなしにするのと同じではないかと言われたので、お答えしようと思います。(ネタを引きずるのはよくないのですが。)

(1)については、やっていることの意味からすればその通りです。しかし、中央値や最頻値は平均に比べて計算負荷が高いので(前記事の追記も参照)、動画という重いデータを扱う際には、そこにこだわるべきではないと思います。簡単なものをまず試し、できたらそれでよしとするわけです。例えば、ウェブカメラの画像を取得するCurrentImage[]を使って、先の話のリアルタイム版を作れるのですが、平均でやるなら次のように簡単です(Mathematica)。

t = 1;
accumu = ImageData[CurrentImage[]];
Dynamic[Refresh[Image[accumu/t], TrackedSymbols -> {t}]]
(*ここに動画が表示される*)
While[True,
  accumu += ImageData[CurrentImage[]];
  t++;
  Pause[0.1]];

いいウェブカメラがあれば、下のような動画が見られるはずです。(実時間だと速くてよくわからないので、最初の5秒を30秒に引き延ばしたのが冒頭の動画です。)

これを中央値や最頻値でやろうとすると、すぐにメモリがなくなるでしょう。最頻値の場合は数値の揺らぎの程度(あるいは数値を丸める必要の有無)も確認しなければなりません。

(2)の方法は知らなかったのですが、上のような動画を作るのはちょっと面倒なのではないでしょうか。

風景から歩行者を消す手軽な方法

固定したカメラで撮った動画で、画素ごとに時間について平均を取れば、(適当な速度で)動くものを消せます。Mathematicaだとこんな感じです。(参照:フリーソフトウェアを使う方法

Export["result.jpg",
 Image[Mean[Map[ImageData,
    Import["movie.mov", "ImageList"]]]]]

おまけ:フレームの平均を計算していく過程(最初の5秒を30秒で)
詳細:風景から歩行者が消えていく様子(リアルタイム版)

追記:画質的には平均ではなく中央値や最頻値を使った方がいいかもしれませんが、「手軽」ではなくなります。「平均でもできるんだ」という「手軽」さの実例だと理解していただければと思います。

中央値:MeanMedianに置き換えるだけで試せますが、計算時間・消費メモリともに増大します。平均なら約90秒で終わるこの動画(1280x720x372フレーム)の処理に約450秒かかります。消費メモリは2倍くらいになるようです(Core i7 4700MQ、メモリ16GB、Windows 7 64bit、Mathematica 9.0.1)。

最頻値:中央値と同様、計算負荷が高くなります。数値の揺らぎも心配です。Mathematicaの最頻値(Commonest[])は戻り値がリストなので、コードの書き換えも面倒です。

カメラからの入力を「手軽」にリアルタイム処理する場合にも、やはり平均を使うのがいいでしょう。

縦と横にしか動けない世界で(1994年東京大学入学試験理系数学第6問)

1994年の東京大学の入学試験、理系数学第6問は次のようなものでした。

平面上の2点P, Qに対し、PとQをx軸またはy軸に平行な線分からなる折れ線で結ぶときの経路の長さの最小値をd(P, Q)で表す。

(1) 原点O(0, 0)と点A(1, 1)に対し、
d(O, P)=d(P, A)を満たす点P(x, y)の範囲をxy平面上に図示せよ。

(2) 実数a>=0に対し、点Q(a, a^2+1)を考える。
次の条件(*)を満足する点P(x, y)の範囲をxy平面上に図示せよ。
(*) 原点O(0, 0)に対し、d(O, P)=d(P, Q)となるようなa>=0が存在する。

この問題は、d(O, P)=Abs[x]+Abs[y]であることがわかれば解けます。d(O, P)=Sqrt[x^2+y^2]ではありません。

Mathematicaで試します。

(*1*)
d[p_, q_] := Total[Abs[p - q]]
expr = d[{0, 0}, {x, y}] == d[{x, y}, {1, 1}];
cond = Reduce[expr, {x, y}, Reals];
reg = ImplicitRegion[cond, {x, y}];
RegionPlot[reg, PlotRange -> {{-2, 2}, {-2, 2}}]

(*2*)
expr = Exists[a, a >= 0,
   d[{0, 0}, {x, y}] == d[{x, y}, {a, a^2 + 1}]];
cond = Reduce[expr, {x, y}, Reals];
reg = ImplicitRegion[cond, {x, y}];
RegionPlot[reg, PlotRange -> {{-2, 2}, {-2, 2}}]

描画領域の境界にも実線が引かれている、という問題がありますが、とりあえずはこれでいいでしょう。

Mathematica 10.3.1と11.2, 11.3には,直線部分が描かれないというバグがあります(紛らわしいことに10.4, 11.0.1は大丈夫)。11.2以降なら,RegionImageを使うといいかもしれません。

RegionImage[reg, PlotRange -> {{-2, 2}, {-2, 2}}]

関連:数学まちがい大全集