LoginSignup
45
26

More than 3 years have passed since last update.

numpyで文字列の配列を作る際の注意点

Posted at

はじめに

後世の人たちが私のような愚かなはまり方をしないよう、この書を残す。

問題

データ型を指定せず文字列の配列を作ると、それはUなんたらというdtypeになる。
dtype=strと指定しても同様。

ソース
import numpy as np
arr=np.array(["A","AB","ABC","ABCD"],dtype=str)
print (arr)
print (arr.dtype)
結果
['A' 'AB' 'ABC' 'ABCD']
<U4

不等号はリトルエンディアンを、UはUnicodeを意味し、数値は文字数を示す。つまり、変数の文字数が固定されているのだ。
後で加工された文字列の文字数がこの値を超過するとはみ出た分は失われてしまう。

ソース
arr[1]=arr[1]+"XYZ"
print (arr[1])

arr[2]="XYZ"+arr[2]
print (arr[2])

arr[3]="まったく別の文字列"
print (arr[3])
結果
ABXY # "AB"+"XYZ"だが"ABXYZ"ではない
XYZA # "XYZ"+"ABC"だが"XYZABC"ではない
まったく # "まったく別の文字列"ではない

これはnp.fullやnp.emptyでも同様。

ソース
arr1=np.array(["A","B","C"])
arr2=np.array(["X","Y","Z"])
arr=np.empty(3,dtype=str)
for i in range(3):
  arr[i]=arr1[i]+arr2[i]

print(arr)
結果
['A' 'B' 'C']

np.emptyで確保されたのは1文字分だけなので、AXやBYやCZを格納することができないわけだ。
2文字以上の文字列でもってnp.fullしたときもdtype=strを指定すると1文字になってしまう。さすがにこれは意味不明だ。

ソース
# dtype=strを指定した場合
arr=np.full(3,"ABC",dtype=str)
print (arr)
print (arr.dtype)
結果
['A' 'A' 'A']  # ["ABC" "ABC" "ABC"]になってくれない
<U1  # 1文字分しか確保されていない
ソース
# dtypeを明示しない場合
arr=np.full(3,"ABC")
print (arr)
print (arr.dtype)
結果
['ABC' 'ABC' 'ABC']  # 正しく定義されるが
<U3  # 文字数が決まっているので加工しづらいことに変わりはない

対策

任意の文字数の文字列を格納できるようにするには、dtype=str でなくdtype=objectと指定する。

ソース
arr=np.array(["A","AB","ABC","ABCD"],dtype=object)

arr[1]=arr[1]+"XYZ"
print (arr[1])

arr[2]="XYZ"+arr[2]
print (arr[2])

arr[3]="まったく別の文字列"
print (arr[3])
結果
ABXYZ
XYZABC
まったく別の文字列

次回予告

もともとは、Excelのセル番地を模した

[['A0' 'B0' 'C0' 'D0' 'E0']
 ['A1' 'B1' 'C1' 'D1' 'E1']
 ['A2' 'B2' 'C2' 'D2' 'E2']
 ['A3' 'B3' 'C3' 'D3' 'E3']]

といった配列を手打ちでなくプログラムで作成して、それを元にnumpyのスライスやOpenCVの画像トリミングについて勉強するつもりだった。
ところがうまくいかず、「文字列の連結は+だよな? 文字列と数値は連結できないのでstr()を使うんだよな?」と基本に立ち返っても駄目で、ググりまくって今回の発見に至った次第。
次こそはスライスの勉強をするぞ。

45
26
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
26