当サイトはアフィリエイトプログラムによる収益を得ています〈景品表示法に基づく表記です)

astropy

【astropy.units】Pythonで単位付きの数値を計算・単位換算

自然現象を扱う理科系の計算では単位は必須。ただ、単位を考えながらPythonコードを考えるのがかなり面倒。

当然ながら単位換算を間違えると最終的な結果がおかしくなるし、どこで計算ミスしたのかを見つけるために処理を追っていく必要がある。

今回はastropyの単位付与ライブラリastropy.unitsを使って、数値に単位を付与して計算・単位換算する方法を紹介する。

これまで単位換算で計算ミスしていた人・単位換算をもっと楽にしたい人は読み進めてほしい。

Python環境は以下。

  • Python 3.10.8
  • astropy 5.2.2

参考になるサイト

astropy公式

本記事のコード全文

下準備のimport

from astropy import units as u

まずは下準備のimportから。今回はastropy.unitsしか使用しないのでastropy.unitsimport

astropy公式as uで短縮使用しているが、他のサイトでは短縮していない場合もあるので注意。

数値計算の単位換算が面倒

数値計算で単位換算を考えるのは面倒だし何よりも手間だ。1つひとつの計算でちゃんと合っているのか確認しつつ最終的な結果を求める必要がある。

M(メガ、10^6)やG(ギガ、10^9)なら普段から目にする機会が多いから計算しやすいが、h(ヘクト、$10^2$)といった普段使わない接頭辞だと計算間違いが起きやすい。

SI接頭語(補助単位)はまだ簡単

from astropy import units as u

# 1kmをm単位に換算

one_kilo_meter = 1  # 1km
# m単位になるように計算
one_meter = one_kilo_meter * 10**3
print(one_meter)
# 1000

k(キロ)やM(メガ)といったSI接頭語はまだシンプルで計算しやすくミスも少ない。

例えば上の例だと1kmを1mに換算しているが、この時はk(キロ)を1,000に換算したらいいので、1,000倍してあげればいい。

また、以下の例では距離distanceと時間secondから速さvelocityを計算し、その結果をkm/s単位に換算している。

from astropy import units as u

# 距離と時間から速さを計算

distance = 10  # 10m
second = 2  # 2秒

# m/s単位で速さを計算
velocity = distance / second
print(velocity)
# 5.0

# 速さをkm単位に換算
kilo_velocity = velocity / (10**3)
print(kilo_velocity)
# 0.005

これらのレベルだと10の何乗したいいのか、という問題だけなので面倒ではあるがそこまで面倒でもない。

単位換算は複雑で面倒

from astropy import units as u

# 1mをインチに換算

one_meter = 1  # 1m
# 1インチは25.4mm
one_inch = one_meter / (25.4 * 10**(-3))
print(one_inch)
# 39.37007874015748

しかし、メートルとインチのように、同じ「距離」という単位だが単位自体が変わってしまう場合は面倒。

それぞれの単位の定義を確認して計算式に盛り込む必要がある。例えば1インチは25.4mmなので、1mをインチに換算する際には25.4 * 0.001mで割らなければいけない。

さすがにこれは面倒だし計算ミスも多発する。

astropy.unitsで単位付きの数値を作成

from astropy import units as u

print(u.m)
# m
print(type(u.m))
# <class 'astropy.units.core.IrreducibleUnit'>

print(u.km)
# km
print(type(u.km))
# <class 'astropy.units.core.PrefixUnit'>

そこで使えるのがastropy.unitsだ。astropyは天文学系のライブラリだが、その中のunitsを使うことで数値に単位を付与することができる。

単位は一般的なものであれば上のようにu.mu.kmといったそのままの記法で記述できる。

単位名を掛け算するだけで単位をつけられる

from astropy import units as u

# astropy.unitsで数値に単位を付与する

# astropy.unitsで1という数値にkmの単位をつける
one_kilo_meter = 1 * u.km
print(one_kilo_meter)
# 1.0 km
print(type(one_kilo_meter))
# <class 'astropy.units.quantity.Quantity'>

使い方は簡単で、数値の後ろにastropy.unitsの単位を掛け算してあげるだけ。上の例だと数値1kmを表すu.kmを掛け算した。これで1kmを作成できる。

あとは後述する計算や単位換算をするだけだ。単位同士の換算は自動で行ってくれるので、人為的なミスが格段に減る。

astropy.unitsに帝国単位は含まれない

inch = 1 * u.inch
# AttributeError: module 'astropy.units' has no attribute 'inch'.

なお、astropy.unitsは元々、天文学系のライブラリastropyをベースにしているので、天文学であまり使われない単位はサポートしていない時がある。

例えば帝国単位である長さの単位「inch(インチ)」はastropy.unitsではサポートしていない。

このような単位を使用する場合は次のu.imperialを使う。

帝国単位にはu.imperialを使う

from astropy import units as u

# インチを計算
one_inch = 1 * u.imperial.inch
print(one_inch)
# inch
print(type(one_inch))
# <class 'astropy.units.quantity.Quantity'>

帝国単位であるインチをastropyで使用するにはu.imperial.inchを使う。あとは通常のastropy.unitsと同じように数値をかけるだけだ。

ちょっとした使い分けは必要だが、一度定義してしまえばのちの計算では自動で単位換算してくれるから使わない手はない。

astropy.unitsの単位付きの数値で計算

astropy.unitsで単位を付与した数値を定義したら、あとはこれらを使って普段通りに計算するだけだ。

計算は単に掛け算などをするだけ

from astropy import units as u

# 距離と時間から速さを計算

distance = 10 * u.m  # 10m
second = 2 * u.s  # 2秒

# m/s単位で速さを計算
velocity = distance / second
print(velocity)
# 5.0 m / s

例えば距離と時間から速さを求める場合は、距離と時間それぞれに単位を付与して速さを計算するだけだ。

自動で速さの単位m / sが付与される。間違えてs / mになったらこの時点で気づくことができる。

数値と単位を分けて取得

from astropy import units as u

# 数値と単位を分けて取得

distance = 10 * u.m  # 10m
second = 2 * u.s  # 2秒

# m/s単位で速さを計算
velocity = distance / second
print(velocity)
# 5.0 m / s
print(type(velocity))
# <class 'astropy.units.quantity.Quantity'>

# 値だけ取り出し
value = velocity.value
print(value)
# 5.0
print(type(value))
# <class 'numpy.float64'>

# 単位だけ取り出し
unit = velocity.unit
print(unit)
# m / s
print(type(unit))
# <class 'astropy.units.core.CompositeUnit'>

ただし、astropy.unitsの単位を付与した値の型はastropy.units.quantity.Quantityなので、このままだと他のライブラリでの計算などでエラーになるかもしれない。

得られた値に.valueを使うことでnumpy.float64形式で、.unitastropyの単位の型で値を分離することができる。

.valueで値だけ取り出してから他のライブラリで使用して欲しい。

単位付きの数値を文字列に変換することも可能

from astropy import units as u

# 単位付きの数値を文字列に変換

distance = 10 * u.m  # 10m
second = 2 * u.s  # 2秒
velocity = distance / second

# 文字列に変換
string = velocity.to_string()
print(string)
# 5.0 m / s
print(type(string))
# <class 'str'>

また、計算結果を文字列として出力することも可能だ。.to_string()を使うことで文字列の状態で取得できる。

単位付きの文字列措定ファイル保存する際などは使用してほしい。

astropy.unitsで別の単位に単位換算する

数値に単位を付与して計算することができたが、ここでは単位付きの数値を他の単位に変換する方法を紹介する。

1つの単位を別の単位に単位換算する

from astropy import units as u

# 1kmをm単位に換算

one_kilo_meter = 1 * u.km  # 1km
# .toでm単位になるように計算
one_meter = one_kilo_meter.to(u.m)
print(one_meter)
# 1000.0 m

# 文字列でも単位換算の指定が可能
print(one_kilo_meter.to('m'))
# 1000.0 m

別の単位に変換する際には.to()を使う。引数に換算後の単位を入れることで単位換算することが可能だ。

上の例では1kmを1mに単位換算するために.to(u.m)をした。なお、引数は文字列でも指定が可能。mの場合はそのまま’m’で指定できる。

複数の単位の組み合わせを単位換算する

from astropy import units as u

# 複数の単位の組み合わせで単位換算

distance = 10 * u.m  # 10m
second = 2 * u.s  # 2秒
velocity = distance / second
print(velocity)
# 5.0 m / s

# m/2の単位をkm/2に変換
kilo_velocity = velocity.to(u.km / u.s)
print(kilo_velocity)
# 0.005 km / s

# 文字列での指定も可能
kilo_velocity = velocity.to('km / s')
print(kilo_velocity)
# 0.005 km / s

# 同時に複数の単位の換算も可能
kilo_micro_velocity = velocity.to('km / us')
print(kilo_micro_velocity)
# 5e-09 km / us

複数の単位が混ざった値でも同様に単位換算できる。上の例だと速さの単位m/skm/skm/μsにそれぞれ換算した。

マイクロ(μ)はastropy.unitsではuと書くので注意。

別の単位系への換算も可能

from astropy import units as u

# 別の単位系への換算も可能

# mをインチに換算
one_meter = 1 * u.m
print(one_meter)
# 1.0 m
one_inch = one_meter.to(u.imperial.inch)
print(one_inch)
# 39.370078740157474 inch

また、メートルをインチに変換することも可能。こちらも同様に.to()の引数にインチを表すu.imperial.inchを指定するだけだ。

なお、inchは文字列で指定することができない。あくまでもimperial経由での使用となる。

# 帝国単位は文字列指定できない
one_meter.to('inch')
# ValueError: 'inch' did not parse as unit: At col 0, inch is not a valid unit.  If this is meant to be a custom unit, define it with 'u.def_unit'. To have it recognized inside a file reader or other code, enable it with 'u.add_enabled_units'. For details, see <https://docs.astropy.org/en/latest/units/combining_and_defining.html>

実現しない単位換算はエラー

one_meter = 1 * u.m
# 1mをgに変換できないのでエラー
one_meter.to('g')
# astropy.units.core.UnitConversionError: 'm' (length) and 'g' (mass) are not convertible

当然だが実現しない単位への換算はエラーとなる。上の例では長さの単位であるmを重さの単位であるgに換算した場合だ。長さから重さへは換算できないのでエラーとなる。

単位を定義して使う

from astropy import units as u

# titterという単位を定義
titter = u.def_unit('titter')
# titterの5倍をchuckleとして定義
chuckle = u.def_unit('chuckle', 5 * titter)
# chuckleの4倍をlaughとして定義
laugh = u.def_unit('laugh', 4 * chuckle)
# laughの3倍をguffawとして定義
guffaw = u.def_unit('guffaw', 3 * laugh)
# guffawの4倍をroflとして定義
rofl = u.def_unit('rofl', 4 * guffaw)
# death_by_laughingをroflの10として定義
death_by_laughing = u.def_unit('death_by_laughing', 10 * rofl)

# death_by_laughingは最終的にtitterの5*4*3*4*10=2,400倍
print((1. * death_by_laughing).to(titter))
# 2400.0 titter

astropy.unitsで定義されていなかったり同時の単位を作り活用したい場合は、単位を定義することが可能だ。

例えば上の例ではtitterという単位をはじめに定義し、これを起点にその他の単位を定義していった。

また、下の例では2mを新たな単位として値を計算、それをm単位に換算した。

from astropy import units as u

# 2mを新たな単位として定義
double_meter = u.def_unit('dm', 2 * u.m)
print(double_meter)
# dm

# m単位に換算
print((double_meter * 2).to(u.m))

単位を定義することでより自由度高く単位付きの値を計算することが可能となる。

単位付きの数値計算はみんな使うべき

今回はastropyの単位付与ライブラリastropy.unitsを使って単位を付与した値の計算と単位換算の方法を紹介した。

これまで単位間違いをしていた人はぜひastropy.unitsで計算ミスがなくなるようにしてほしい。

単位ミスという小さな部分でつまずかず、より本質的な問題に時間を割けることを願う。

  • この記事を書いた人
  • 最新記事

メガネ

ベンチャー企業のWebエンジニア駆け出し。独学のPythonで天文学系の大学院を修了→転職→今に至る。最近は主にPHPを触ってます。 メインのブログは「M天パ」https://megatenpa.com/です。

-astropy
-,