Pythonは基本的にループ内を毎回コンパイルして実行するのでデータをループして処理するのは時間がかかるので避けねばなりません。
そんなわけでPythonの機械学習モジュールのほとんどNumpyという配列全体への操作を1オペレーションで行える多次元配列拡張モジュールを使ってます。
以下弊社でよく使っている言語で何パターンか配列の処理速度を測ってみました。
測り方は1.2以降は1.1と同じように測りました。
データ数がすくないので5回の平均をとってます。
php 5.4.16 (OutofMemoryになったのでphp.iniでmemory_limitを512Mに変更)
perl 5.16.3
python 2.7.5
配列の要素数は100万くらい(もっと多いほうがいいデータがとれますがうちの検証環境がしょぼいのでこのくらいに)
my ($e, $m) = gettimeofday();
my $start = $e + $m / 1000000;
for (my $i = 0; $i < 1000000; $i++) {
$ary[$i] = 1;
}
($e, $m) = gettimeofday();
print($e + $m / 1000000 - $start);
0.130244
$ary = array();
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
$ary[$i] = 1;
}
print_r(microtime(true) - $start);
0.221422
s = datetime.datetime.today()
start = float(s.minute) * 60 + float(s.second) + float(s.microsecond) / 1000000
ary = []
for i in range(1000000):
ary.append(i)
e = datetime.datetime.today()
print(float(e.minute) * 60 + float(e.second) + float(e.microsecond) / 1000000 - start)
0.161213
s = datetime.datetime.today()
start = float(s.minute) * 60 + float(s.second) + float(s.microsecond) / 1000000
ary = numpy.array([])
for i in range(1000000):
ary = numpy.append(i)
e = datetime.datetime.today()
print(float(e.minute) * 60 + float(e.second) + float(e.microsecond) / 1000000 - start)
10分待って終わらないので中断
s = datetime.datetime.today()
start = float(s.minute) * 60 + float(s.second) + float(s.microsecond) / 1000000
ary = numpy.ones((1000000))
e = datetime.datetime.today()
print(float(e.minute) * 60 + float(e.second) + float(e.microsecond) / 1000000 - start)
0.002626
my $num = 0;
for (my $i = 0; $i < 1000000; $i++) {
$num += $ary[$i];
}
0.093396
my $num = 0;
foreach my $i (@ary) {
$num += $ary[$i];
}
0.078159
for ($i = 0; $i < 1000000; $i++) {
$num += $ary[$i];
}
0.065996
foreach ($ary as $val) {
$num += $val;
}
0.052462
for i v in range(len(ary)):
num += i
0.122088
for i v in range(len(ary)):
num += i
0.14291
num = np.sum(ary)
0.001414
100000*4*4の配列の測定
my @ary = ();
for (my $i = 0; $i < 100000; $i++) {
$ary[$i] = ();
for (my $j = 0; $j < 4; $j++) {
$ary[$i][$j] = ();
for (my $k = 0; $k < 4; $k++) {
$ary[$i][$j][$k] = 1;
}
}
}
0.587198
$ary = array();
for ($i = 0; $i < 100000; $i++) {
$ary[$i] = array();
for ($j = 0; $j < 4; $j++) {
$ary[$i][$j] = array();
for ($k = 0; $k < 4; $k++) {
$ary[$i][$j][$k] = 1;
}
}
}
0.676906
ary = [[[1] * 4 for i in range(4)] for j in range(100000)]
0.446916
ary = numpy.ones((10000,4,4))
0.000753
my $num = 0;
for (my $i = 0; $i < 100000; $i++) {
for (my $j = 0; $j < 4; $j++) {
for (my $k = 0; $k < 4; $k++) {
$num += $ary[$i][$j][$k];
}
}
}
0.363232
my $num = 0;
foreach my $i (@ary) {
foreach my $j (@$i) {
foreach my $k (@$j) {
$num += $k;
}
}
}
0.244424
$num = 0;
for ($i = 0; $i < 100000; $i++) {
for ($j = 0; $j < 4; $j++) {
for ($k = 0; $k < 4; $k++) {
$num += $ary[$i][$j][$k];
}
}
}
0.303648
$num = 0;
foreach ($ary as $v1) {
foreach ($v1 as $v2) {
foreach ($v2 as $val) {
$num += $val;
}
}
}
0.401962
num = 0
for i, v in enumerate(ary):
for j, v2 in enumerate(v):
for k, v3 in enumerate(v2):
num += v3
0.454874
num = np.sum(ary)
0.0003
言語 | リスト | 多次元配列 | |||
---|---|---|---|---|---|
初期化 | 計算 | 初期化 | 計算 | ||
perl | for | 0.130244 | 0.093396 | 0.587198 | 0.363232 |
perl | foreach | - | 0.078159 | - | 0.244424 |
php | for | 0.221422 | 0.065996 | 0.676906 | 0.303648 |
php | foreach | - | 0.052462 | - | 0.401962 |
python | for | 0.161213 | 0.122088 | 0.446916 | 0.454874 |
python numpy | for | 中止 | 0.14291 | - | - |
python numpy | method | 0.002626 | 0.001414 | 0.000753 | 0.0003 |
多少恣意的ではありますがnumpyのすばらしさを分かっていただけたでしょうか。
機械学習などでnumpyを使うときはsum以外にも各種メソッドがありますのでそれを使うようにしましょう。