Pythonで最小値を求める

Pythonで最小値を求めるスクリプト。想定しているデータはこんな感じ。

0       2.87604 2.9828  3.19203 3.6073  3.90156 4.23807 4.24807 3.86984 3.51134
1       2.80487 2.90396 3.15443 3.5649  3.83633 4.19816 4.25518 3.88051 3.54163
2       2.78178 2.87611 3.13413 3.54351 3.8365  4.17321 4.24449 3.87114 3.53455
3       2.91111 2.99814 3.20955 3.60764 3.92462 4.26296 4.32612 3.93163 3.57703
4       2.92997 3.01939 3.26342 3.65234 3.94976 4.28576 4.40977 4.04215 3.69586
5       2.89252 2.91788 3.16297 3.56701 3.91119 4.26494 4.44967 4.0536  3.70644
6       2.79122 2.89977 3.1971  3.58737 3.87525 4.19734 4.366   3.97887 3.61761
7       2.94522 3.01401 3.21435 3.58788 3.8866  4.23736 4.48957 4.07393 3.73314
8       2.91237 2.9506  3.19116 3.58087 3.84278 4.156   4.53332 4.1122  3.74732
9       2.90657 3.00162 3.19358 3.54266 3.8198  4.15962 4.54799 4.14353 3.76158
10      2.86084 2.9319  3.17161 3.53902 3.7848  4.10889 4.50205 4.08645 3.70702

例えばある分子同士の距離の時間変化を取得したいときに、一方の分子が巨大だと重心同士の距離を計算しただけではうまく数値化できない。そういう時は、たとえばタンパク質ならアミノ酸単位で切り分けて、それぞれのアミノ酸と小分子との重心の距離を測ると、上のように幾つもの距離の時間変化が得られて、それぞれの列の最小値をとれば2分子の距離を近似できるというわけ。
説明しにくくてあんまりいい例じゃないなぁ…。

とにかく、Pythonを使って各行の2カラム目、横に並んでいる数値9個の中の最小値を出力することにする。

最初書いたスクリプトがこれ。三項演算子を使ったり自作関数にしたりしてる。正直な性格がにじみ出てますな。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys

def minimum(v1, v2):
  return v1 if (v1 < v2) else v2

if __name__ == '__main__':
  argvs = sys.argv
  argc = len(argvs)

  if argc <= 1:
    print "pytyon minimum.py [filename]"
    exit()
  f = open(argvs[1], 'r')
  for line in f:
    if not(line[0] == '@' or line[0] == '#'):
      col = line.split()
      mini=col[1]
      for i in range(2, len(col)):
        mini = minimum(mini, col[i])
      print "%-8d %9.5f" % (float(col[0]), float(mini))
      #print str(float(col[0]))+" "+mini
  f.close()

しかし、これを書いた後に重大な事実が判明。

Pythonには配列中の最小値をとるminという組み込み関数があるというではないか。(←これほどまでに初歩的なことになぜ気付かなかったのか…)

ということで、気を取り直して修正。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys

if __name__ == '__main__':
  argvs = sys.argv
  argc = len(argvs)

  if argc <= 1:
    print "pytyon minimum.py [filename]"
    exit()
  f = open(argvs[1], 'r')
  for line in f:
    if not(line[0] == '@' or line[0] == '#'):
      col = line.split()
      print "%-8d %9.5f" % (float(col[0]), float(min(col[1:])))
  f.close()

使い方は、

python minimum.py [input_filename] > [output_filename]

という感じで。出力はこうなります。

0          2.87604
1          2.80487
2          2.78178
3          2.91111
4          2.92997
5          2.89252
6          2.79122
7          2.94522
8          2.91237
9          2.90657
10         2.86084

ちなみに、このminという関数、PHPでもJavascriptでも似たようなものがあります。(それなのになぜ気付かなかったのか…)

// PHP
echo min(0.2, -0.1, 3, 100) // -0.1
window.console.log(Math.min.apply(null, [0.2, -0.1, 3, 100]));

頑張って作ったのに既にいい方法が隣にあるってわかった時に悲しくなるってのはままありますよね。(このプログラム作るのはそれほど頑張ったわけでもないけど)これもIT社会になって情報が瞬時に共有できるようになってからより身近になってきた話であって、昔、砂場に山作って堅牢なトンネルを掘る技術を磨いていた幼稚園生の時とかに、世の中の建築技術とか構造力学とかを知っていたら自分のダメさにたぶん絶望していたと思う。小さいことだけど、こうやって個人の自尊心が養われていったのを考えれば、グローバル化は少しずつこれを壊して言っているような気もするのです。

min関数を知らなかった恥ずかしさを、客観的に物事を見れる冷静なヤツを装うことでごまかそうとしてみましたが、書いているうちにどうでもよくなってきたのでこれくらいにしておきます。