はじめに
天文学の分野では、観測データをFITS(Flexible Image Transport System)形式で保存するのが一般的です。しかし、時にはデータ内に重複する行が含まれることがあります。本記事では、擬似的なFITSファイルを生成し、pandasを使って重複行を検出する方法を紹介します。
また、numpyとpandasのエンディアンの取り扱いに関する違いにも注意を向け、エンディアンの変換が必要な場合の対処法を解説します。
目次
- FITSファイルとエンディアンの取り扱いの違い
- 擬似FITSファイルの生成
- pandasを使った重複行の検出と保存
- エンディアンの確認と変換の方法
- サンプルコードと実行例
1. FITSファイルとエンディアンの取り扱いの違い
FITSファイルは、古いハードウェアや異なるプラットフォーム間の互換性を確保するため、ビッグエンディアン(Big-endian)形式 でデータを保存することが一般的です。
一方、numpy
とpandas
はデフォルトで リトルエンディアン(Little-endian) を使用します。
このエンディアンの不一致が原因で、pandas
でデータを処理する際にエラーが発生することがあります。
2. 擬似FITSファイルの生成
以下のコードは、イベントデータを持つ擬似的なFITSファイルを生成します。
FITSファイル生成コード
from astropy.io import fits
import numpy as np
def create_mock_fits(filename):
"""Generate a mock FITS file with event data, including duplicates."""
n_rows = 20
time = np.concatenate([np.linspace(0, 19, 20), [10]]) # Duplicate TIME at 10
itype = np.random.randint(0, 8, n_rows + 1)
pixel = np.random.randint(0, 36, n_rows + 1)
trig_lp = np.random.randint(0, 1000, n_rows + 1)
deriv_max = np.random.randint(-32768, 32767, n_rows + 1)
cols = [
fits.Column(name='TIME', format='D', array=time),
fits.Column(name='ITYPE', format='B', array=itype),
fits.Column(name='PIXEL', format='B', array=pixel),
fits.Column(name='TRIG_LP', format='J', array=trig_lp),
fits.Column(name='DERIV_MAX', format='I', array=deriv_max)
]
hdu = fits.BinTableHDU.from_columns(cols)
hdu.writeto(filename, overwrite=True)
print(f"Mock FITS file created: {filename}")
create_mock_fits('mock_event_data.fits')
3. pandasを使った重複行の検出と保存
以下のコードは、FITSファイルからデータを読み込み、TIME
に基づいて重複行を検出し、新しいFITSファイルに保存します。
重複行の検出コード
from astropy.io import fits
import pandas as pd
def load_fits_to_dataframe(fits_file):
"""Load FITS data into a pandas DataFrame with endian conversion."""
with fits.open(fits_file) as hdul:
data = hdul[1].data
# Ensure all data is converted to Little-endian for pandas compatibility
df = pd.DataFrame({
'TIME': data['TIME'].byteswap().newbyteorder(),
'ITYPE': data['ITYPE'].byteswap().newbyteorder(),
'PIXEL': data['PIXEL'].byteswap().newbyteorder(),
'TRIG_LP': data['TRIG_LP'].byteswap().newbyteorder(),
'DERIV_MAX': data['DERIV_MAX'].byteswap().newbyteorder()
})
return df
def find_and_save_duplicates(df, output_file):
"""Find duplicate rows based on 'TIME' and save them to a new FITS file."""
duplicates = df[df.duplicated('TIME', keep=False)]
print(f"Found {len(duplicates)} duplicate rows.")
if not duplicates.empty:
hdu = fits.BinTableHDU.from_columns([
fits.Column(name='TIME', format='D', array=duplicates['TIME']),
fits.Column(name='ITYPE', format='B', array=duplicates['ITYPE']),
fits.Column(name='PIXEL', format='B', array=duplicates['PIXEL']),
fits.Column(name='TRIG_LP', format='J', array=duplicates['TRIG_LP']),
fits.Column(name='DERIV_MAX', format='I', array=duplicates['DERIV_MAX'])
])
hdu.writeto(output_file, overwrite=True)
print(f"Duplicate rows saved to {output_file}")
df = load_fits_to_dataframe('mock_event_data.fits')
find_and_save_duplicates(df, 'duplicates.fits')
4. エンディアンの確認と変換の方法
エンディアンの確認
以下のコードで、numpy
配列のエンディアンを確認できます。
print(df['TIME'].dtype) # >f8: Big-endian, <f8: Little-endian
-
>f8
:Big-endian -
<f8
:Little-endian
エンディアンの変換
以下のように、byteswap()
とnewbyteorder()
を使ってエンディアンを変換します。
df['TIME'] = df['TIME'].byteswap().newbyteorder()
5. サンプルコードと実行例
実行手順
-
擬似FITSファイルを生成:
python create_mock_fits.py
FITSファイルの中身を
ftlist
を用いて確認します。
> ftlist mock_event_data.fits
Print options: H C K I T [C] T
TIME ITYP PIXE TRIG_LP DERIV_
1 0.00000000000000 4 28 503 -14406
2 1.00000000000000 1 26 368 5503
3 2.00000000000000 6 19 350 -3004
4 3.00000000000000 4 31 948 32573
5 4.00000000000000 7 0 494 -14526
6 5.00000000000000 5 32 51 -29495
7 6.00000000000000 7 9 496 -25354
8 7.00000000000000 5 9 572 32754
9 8.00000000000000 3 24 51 14589
10 9.00000000000000 2 32 658 -13708
11 10.0000000000000 7 2 294 32600
12 11.0000000000000 7 10 281 -27159
13 12.0000000000000 2 11 703 27509
14 13.0000000000000 2 14 283 7499
15 14.0000000000000 7 24 802 30085
16 15.0000000000000 1 4 897 22922
17 16.0000000000000 5 33 939 -30371
18 17.0000000000000 3 32 677 7238
19 18.0000000000000 2 28 960 6749
20 19.0000000000000 2 34 181 24114
21 10.0000000000000 6 25 644 -8361
-
重複行を検出して保存:
python find_duplicates.py
出力例
Mock FITS file created: mock_event_data.fits
Found 2 duplicate rows.
Duplicate rows saved to duplicates.fits
ファイルの中身も確認しましょう。
>ftlist duplicates.fits
TIME ITYP PIXE TRIG_LP DERIV_
1 10.0000000000000 7 2 294 32600
2 10.0000000000000 6 25 644 -8361
TIMEが 10.0 の部分だけが検出できていますね。
まとめ
本記事では、擬似FITSファイルの生成から重複行の検出、エンディアンの変換方法について説明しました。FITSファイルの解析では、numpy
とpandas
のエンディアンの違いに注意が必要です。必要に応じてエンディアンをリトルエンディアンに変換し、データの互換性を確保しましょう。