awkward のデータ型#
awkward は階層的・可変長データの取り扱いを得意とする配列ライブラリであり、type 属性を用いることで配列のデータ型(ArrayType)を取得できます。本章では、さまざまなデータ構造に対して type 属性がどのように表現されるかを観察し、その特徴を理解していきます。type 属性の読み取りは、Awkward Array が内部的にどのような構造を持っているかを理解するための第一歩となります。
import numpy as np
import awkward as ak
from IPython.core.magic import register_line_magic
import html
データ型を取得#
Awkward Array は type と repr(type) の 2 種類の形式で型を表示できます。
a = ak.Array([[1, 2, 3], [4, 5]])
print(a.type)
print(repr(a.type))
2 * var * int64
ArrayType(ListType(NumpyType('int64')), 2, None)
ここでは、
2 * var * int64のように簡易表記ArrayType(ListType(...))の詳細表記
の両方が得られます。
便利のため、%t マジックを定義し、Awkward Array の値と型をまとめて確認できるようにします。
@register_line_magic
def t(line):
arr = get_ipython().ev(line)
html_str = html.unescape(arr._repr_mimebundle_()['text/html'])
type_str = repr(arr.type)
html_str = html_str.replace("</pre>", f"\ntype: {type_str}").replace("<pre>", "")
print(html_str)
一次元配列#
一次元の整数配列では、型は単純に「要素数 × 基本型」として表示されます。
%t ak.Array([1, 2, 3, 4])
[1,
2,
3,
4]
---
backend: cpu
nbytes: 32 B
type: 4 * int64
type: ArrayType(NumpyType('int64'), 4, None)
要素欠損(Option 型)#
None が含まれると、その要素は ?int64 のように OptionType で表現されます。
%t ak.Array([1, None, 3, 4])
[1,
None,
3,
4]
------
backend: cpu
nbytes: 56 B
type: 4 * ?int64
type: ArrayType(OptionType(NumpyType('int64')), 4, None)
2次元配列(規則軸)#
NumPy の規則的(固定長)2 次元配列を渡すと、regular 軸として 4 * 3 * int32 のように表されます。
%t ak.Array(np.random.randint(0, 10, (4, 3)))
[[9, 6, 6],
[1, 7, 0],
[1, 3, 0],
[0, 7, 3]]
-----------
backend: cpu
nbytes: 48 B
type: 4 * 3 * int32
type: ArrayType(RegularType(NumpyType('int32'), 3), 4, None)
2次元配列(非規則軸)#
リストの長さがバラバラの軸は var として可変長で表されます。
%t ak.Array([[1, 2, 3], [4, 5], [6]])
[[1, 2, 3],
[4, 5],
[6]]
-----------
backend: cpu
nbytes: 80 B
type: 3 * var * int64
type: ArrayType(ListType(NumpyType('int64')), 3, None)
複数の非規則軸#
複数の非規則軸がある場合、var * var のように階層的に示されます。
%t ak.Array([[[1], [2], [3, 3]], [[4, 5]], [[6, 7]]])
[[[1], [2], [3, 3]],
[[4, 5]],
[[6, 7]]]
--------------------
backend: cpu
nbytes: 144 B
type: 3 * var * var * int64
type: ArrayType(ListType(ListType(NumpyType('int64'))), 3, None)
非規則軸+要素欠損#
可変長リストの中に None が含まれると、要素の型が ?int64 となります。
%t ak.Array([[1, None, 3], [4, 5], [6]])
[[1, None, 3],
[4, 5],
[6]]
--------------
backend: cpu
nbytes: 120 B
type: 3 * var * ?int64
type: ArrayType(ListType(OptionType(NumpyType('int64'))), 3, None)
非規則軸+リスト欠損#
リストそのものが None の場合、外側の型が option[var * int64] になります。
%t ak.Array([[1, 2, 3], None, [4, 5], [6]])
[[1, 2, 3],
None,
[4, 5],
[6]]
-----------
backend: cpu
nbytes: 112 B
type: 4 * option[var * int64]
type: ArrayType(OptionType(ListType(NumpyType('int64'))), 4, None)
非規則軸+リスト欠損+要素欠損#
リスト欠損と要素欠損の両方が同時にある場合の型表現です。
%t ak.Array([[1, None, 3], None, [4, 5], [6]])
[[1, None, 3],
None,
[4, 5],
[6]]
--------------
backend: cpu
nbytes: 152 B
type: 4 * option[var * ?int64]
type: ArrayType(OptionType(ListType(OptionType(NumpyType('int64')))), 4, None)
Union 型#
整数と文字列、のような異型データを含む配列は union[...] 型となります。
%t ak.Array([1, 'x', 2, 'y'])
[1,
'x',
2,
'y']
-----
backend: cpu
nbytes: 78 B
type: 4 * union[
int64,
string
]
type: ArrayType(UnionType([NumpyType('int64'), ListType(NumpyType('uint8', parameters={'__array__': 'char'}), parameters={'__array__': 'string'})]), 4, None)
構造体型#
Awkward Array では {x: ..., y: ...} というフィールドを持つ構造体型(RecordType)も扱えます。
%t ak.Array({'x':[1, 2, 3], 'y':[4, 5, 6]})
[{x: 1, y: 4},
{x: 2, y: 5},
{x: 3, y: 6}]
--------------
backend: cpu
nbytes: 48 B
type: 3 * {
x: int64,
y: int64
}
type: ArrayType(RecordType([NumpyType('int64'), NumpyType('int64')], ['x', 'y']), 3, None)
構造体型+欠損フィールド#
同じ構造体でも、あるフィールドのみ欠損していても良く、その型は ?int64 のように表されます。
%t ak.Array([{'x': 1, 'y': 4}, {'x': 2, 'y': 5}, {'y': 6}])
[{x: 1, y: 4},
{x: 2, y: 5},
{x: None, y: 6}]
-----------------
backend: cpu
nbytes: 64 B
type: 3 * {
x: ?int64,
y: int64
}
type: ArrayType(RecordType([OptionType(NumpyType('int64')), NumpyType('int64')], ['x', 'y']), 3, None)
構造体型+リストを持つフィールド#
フィールド自体がリストを持つ場合、y: var * int64 のように記述されます。
%t ak.Array([{'x': 2, 'y': [4, 5]}, {'x': 3, 'y': [5]}, {'x':4, 'y': [6, 7, 8]}])
[{x: 2, y: [4, 5]},
{x: 3, y: [5]},
{x: 4, y: [6, 7, 8]}]
----------------------
backend: cpu
nbytes: 104 B
type: 3 * {
x: int64,
y: var * int64
}
type: ArrayType(RecordType([NumpyType('int64'), ListType(NumpyType('int64'))], ['x', 'y']), 3, None)
タプル型#
フィールド名のない構造体はタプル型として扱われ、(int64, string) のような形になります。
%t ak.zip([[1, 2, 3], ['x', 'y', 'z']])
[(1, 'x'),
(2, 'y'),
(3, 'z')]
----------
backend: cpu
nbytes: 59 B
type: 3 * (
int64,
string
)
type: ArrayType(RecordType([NumpyType('int64'), ListType(NumpyType('uint8', parameters={'__array__': 'char'}), parameters={'__array__': 'string'})], None), 3, None)