Helve’s Python memo

Pythonを使った機械学習やデータ分析の備忘録

<BeautifulSoup> XMLの解析

BeautifulSoupを使って、XMLを解析(parse)する。

環境

python 3.6.1
beautifulsoup4 4.6.0
lxml 3.8.0

インストール

$ pip install beautifulsoup4
$ pip install lxml

XMLの構文

XMLの構造について、以下の名称を用いる。

<要素名 属性="値">内容</要素名>

扱うXMLファイル

今回、書籍データを模擬した以下のXMLファイルを読み込む。
ファイルはローカルに置かれているものとする。
オンラインのファイルを取得するときは、requestやurllibを使う。

doc.xml
<data>
  <book id="001">
    <title language="English">Alice in Wonderland</title>
    <author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
    <genre>小説</genre>
  </book>
  <book id="002">
    <title language="Japanese">羅生門</title>
    <author autonym="芥川龍之介">芥川龍之介</author>
    <genre>小説</genre>
  </book> 
  <book id="003">
    <title language="Japanese">柿の種</title>
    <author autonym="寺田寅彦">寺田寅彦</author>
    <genre>随筆</genre>
  </book>
</data>

XMLファイルのパース

読み込んだXMLファイルオブジェクトをBeautifulSoupでパースする。
BeautifulSoupで使用できるパーサを次表に示す。今回はxmlパーサを使用する。

html.parser 標準ライブラリのパーサ
lxml lxmlライブラリのHTMLパーサ。処理が高速
lxml-xml または xml lxmlライブラリのXMLパーサ。処理が高速
html5lib HTML5に対応

>>> from bs4 import BeautifulSoup
>>> with open("doc.xml") as doc:
...     soup = BeautifulSoup(doc, "xml") # 第2引数でパーサを指定
>>> print(soup)
<?xml version="1.0" encoding="utf-8"?>
<data>
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>
<book id="002">
<title language="Japanese">羅生門</title>
<author autonym="芥川龍之介">芥川龍之介</author>
<genre>小説</genre>
</book>
<book id="003">
<title language="Japanese">柿の種</title>
<author autonym="寺田寅彦">寺田寅彦</author>
<genre>随筆</genre>
</book>
</data>

XMLが文字化けする場合は、open時のencodingを見直す。
prettifyメソッドを使うと、整形されたXMLが表示される。

>>> print(soup.prettify())
<?xml version="1.0" encoding="utf-8"?>
<data>
 <book id="001">
  <title language="English">
   Alice in Wonderland
  </title>
  <author autonym="Charles Lutwidge Dodgson">
   Lewis Carroll
  </author>
  <genre>
   小説
  </genre>
 </book>
 <book id="002">
  <title language="Japanese">
   羅生門
  </title>
  <author autonym="芥川龍之介">
   芥川龍之介
  </author>
  <genre>
   小説
  </genre>
 </book>
 <book id="003">
  <title language="Japanese">
   柿の種
  </title>
  <author autonym="寺田寅彦">
   寺田寅彦
  </author>
  <genre>
   随筆
  </genre>
 </book>
</data>

パースしたXMLの探索

要素の検索

find() 要素名または属性で検索し、該当する最初の要素を返す
find_all() 要素名または属性で検索し、該当する全ての要素を返す

>>> soup.find("book") # 最初の"book"要素
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>
>>> soup.book         # "."+"要素でも、同じ結果になる
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>
>>> soup.find(language="Japanese")  # language属性がJapaneseである最初の要素
<title language="Japanese">羅生門</title>
>>> soup.find_all("author")         # 全てのauthor要素
[<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>,
 <author autonym="芥川龍之介">芥川龍之介</author>,
 <author autonym="寺田寅彦">寺田寅彦</author>]
>>> soup.find_all(language="Japanese") # language属性がJapaneseである全ての要素
[<title language="Japanese">羅生門</title>,
 <title language="Japanese">柿の種</title>]

属性と値の取得

属性から値を取得する場合は、[ ]で属性を指定。
全ての属性と値を取得する場合は、attrsメソッドを使う。

>>> title001 = soup.book.title
>>> print(title001)
<title language="English">Alice in Wonderland</title>
>>> title001["language"] # 属性を指定
'English'
>>> title001.attrs       # 属性と値を辞書型で表示
{'language': 'English'}

内容の取得

内容を持つ直上の要素まで移動し、stringメソッドを使う。

>>> title001 = soup.book.title
>>> print(title001)
<title language="English">Alice in Wonderland</title>
>>> title001.string # 内容を取得
"Alice in Wonderland"

要素間の移動

next_sibling 同じ階層の次の要素に移動
previous_sibling 同じ階層の前の要素に移動
parent 上の階層の要素に移動

>>> book001 = soup.book
>>> print(book001)
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>
>>> author001 = book001.author
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
>>> author001.next_sibling # 改行(\n)も要素に含まれる
'\n'
>>> author001.next_sibling.next_sibling # 次の要素
<genre>小説</genre>
>>> author001.previous_sibling.previous_sibling # 前の要素
<title language="English">Alice in Wonderland</title>
>>> author001.parent # 上の要素
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>

参考:
Beautiful Soup Documentation — Beautiful Soup 4.4.0 documentation

<NumPy> 統計の関数

最大・最小

>>> import numpy as np
>>> a = np.array([[1, 2, 3], [4, 5, 6]])
>>> np.amax(a)         # 全要素の最大値
6
>>> np.amax(a, axis=0) # 列方向の最大値
array([4, 5, 6])
>>> np.amax(a, axis=1) # 行方向の最大値
array([3, 6])
>>> np.amax(a, axis=1, keepdims=True) # 元の配列構造を維持
array([[3],
       [6]])
>>> np.amin(a)         # 全要素の最小値
1
>>> np.argmax(a)       # 最大要素のインデックスを返す
>>> # 配列は1次元に変換 (flatten) される
5
>>> np.argmax(a, axis=0) # 列方向の最大要素インデックス
array([1, 1, 1], dtype=int64)
>>> np.argmin(a)         # 最小要素のインデックスを返す
0
>>> np.ptp(a)            # 最大値-最小値 (Peak To Peak)
5
>>> np.ptp(a, axis=0)    # 列方向の最大値-最小値
array([3, 3, 3])

平均と分散

>>> a = np.array([[1, 2, 3], [4, 5, 6]])
>>> np.median(a)          # 全要素の中央値
3.5
>>> np.median(a, axis=0)  # 列方向の中央値
array([ 2.5,  3.5,  4.5])
>>> np.average(a)         # 全要素の平均値
3.5
>>> np.average(a, axis=0) # 列方向の平均値
array([ 2.5,  3.5,  4.5])
>>> np.average([1, 2, 3], weights=[2.5, 1.5, 0.5]) # 重みづけ平均
>>> # (2.5*1 + 1.5*2 + 0.5*3) / (2.5+1.5+0.5)
1.5555555555555556
>>> np.mean(a) # 全要素の平均値(axisオプションはあるが、weightsオプションはない)
3.5
>>> np.std(a)          # 標準偏差 (axisオプションあり)
1.707825127659933
>>> np.std(a, ddof=1)  # 不偏標準偏差 (標本数-ddofで標準偏差を計算。ddof=0がデフォルト)
1.8708286933869707
>>> np.var(a)          # 標本分散 (axisオプションあり)
2.9166666666666665
>>> np.var(a, ddof=1)  # 不偏分散 (標本数-ddofで分散を計算。ddof=0がデフォルト)
3.5

相関係数

>>> a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b = np.array([1, 0, 4, 2, 6, 3, 5, 9, 8, 7])
>>> c = np.array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
>>> x = np.vstack([a, b, c])
>>> np.corrcoef(x)         # 相関係数行列
>>> # [0, 1]要素:aとbの相関係数
>>> # [0, 2]要素:aとcの相関係数
>>> # [1, 2]要素:bとcの相関係数
array([[ 1.        ,  0.85454545, -1.        ],
       [ 0.85454545,  1.        , -0.85454545],
       [-1.        , -0.85454545,  1.        ]])
>>> np.corrcoef(a, b) # 2つの1次元配列を引数にとっても良い
array([[ 1.        ,  0.85454545],
       [ 0.85454545,  1.        ]])
>>> np.cov(x)  # 共分散行列 (ddof=1がデフォルト)
array([[ 9.16666667,  7.83333333, -9.16666667],
       [ 7.83333333,  9.16666667, -7.83333333],
       [-9.16666667, -7.83333333,  9.16666667]])

参考
Statistics — NumPy v1.13 Manual

広告を非表示にする

<NumPy> 数学の関数

mathライブラリの数学の関数は、一般にスカラー値にしか適応できない。
一方、NumPyの数学の関数は、スカラー値に加え、リストやnumpy.arrayオブジェクトにも適応できる。

三角関数

角度の単位はラジアン

記法 説明
sin np.sin(a)
cos np.cos(a)
tan np.tan(a)
arcsin np.arcsin(a)
arccos np.arccos(a)
arctan np.arctan(a) 戻り値の範囲は[-pi/2, pi/2]
arctan2 np.arctan2(a, b) a/bのarctanを返す。戻り値の範囲は[-pi, pi]

>>> import numpy as np
>>> a = np.array([0, np.pi/6, np.pi/3, np.pi/2]) # np.piは円周率
>>> b = np.sin(a)
>>> b
array([ 0.       ,  0.5      ,  0.8660254,  1.       ])
>>> np.arcsin(b)
array([ 0.        ,  0.52359878,  1.04719755,  1.57079633])
>>> np.deg2rad([0, 90, 180])         # degからradへ変換
array([ 0.        ,  1.57079633,  3.14159265])
>>> np.rad2deg([0, np.pi/2, np.pi])  # radからdegへ変換
array([   0.,   90.,  180.])

双曲線関数

メソッド 記法
sinh np.sinh(a)
cosh np.cosh(a)
tanh np.tanh(a)
arcsinh np.arcsinh(a)
arccosh np.arccosh(a)
arctanh np.arctanh(a)

端数処理

記法 説明
四捨五入 np.around(a, decimals=0) 10^(-decimals)の1つ下の位を四捨五入
四捨五入 np.round_(a, decimals=0) aroundと同じ
0方向への丸め np.fix(a)
負方向への丸め(切捨て) np.floor(a)
正方向への丸め(切上げ) np.ceil(a)
0方向への丸め np.trunc(a)

>>> np.around(123.456, decimals=0)   # 0.1の位を四捨五入
123.0
>>> np.around(123.456, decimals=1)   # 0.01の位を四捨五入
123.5
>>> np.around(123.456, decimals=-2)  # 10の位を四捨五入
100.0
>>> np.fix([0.7, 3.2, -0.7, -3.2])   # 0方向への丸め
array([ 0.,  3., -0., -3.])
>>> np.floor([0.7, 3.2, -0.7, -3.2]) # 負方向への丸め
array([ 0.,  3., -1., -4.])
>>> np.ceil([0.7, 3.2, -0.7, -3.2])  # 正方向への丸め
array([ 1.,  4., -0., -3.])
>>> np.trunc([0.7, 3.2, -0.7, -3.2]) # 0方向への丸め
array([ 0.,  3., -0., -3.])

和・積・差分

1つの配列に含まれる要素の和・積・差分。

>>> a = np.array([[1, 2], [3, 4]])
>>> np.sum(a)          # 全要素の和
10
>>> np.sum(a, axis=0)  # 列方向の和
array([4, 6])
>>> np.sum(a, axis=1)  # 行方向の和
array([3, 7])
>>> np.prod(a)         # 全要素の積
24
>>> np.prod(a, axis=0) # 列方向の積
array([3, 8])
>>> np.prod(a, axis=1) # 行方向の積
array([ 2, 12])
>>> b = np.array([[1, 2, 4, 8], [3, 5, 9, 7]])
>>> np.diff(b)         # 最大の軸方向(axis=1)の差分
array([[ 1,  2,  4],
       [ 2,  4, -2]])
>>> np.diff(b, axis=0) # 列方向の差分
array([[ 2,  3,  5, -1]])
>>> np.diff(b, n=2)    # n: 差分をとる回数( =np.diff(np.diff(b)) )
array([[ 1,  2],
       [ 2, -6]])

指数関数・対数関数

>>> np.exp([0, 1])         # 指数関数
array([ 1.        ,  2.71828183])
>>> np.log([1, np.e])      # 自然対数
array([ 0.,  1.])
>>> np.log10([1, 10, 100]) # 常用対数
array([ 0.,  1.,  2.])

その他

>>> np.sqrt([1, 4, 9])          # 平方根
array([ 1.,  2.,  3.])
>>> np.cbrt([1, 8, 27])         # 立方根(三乗根)
array([ 1.,  2.,  3.])
>>> np.square([1, 2, 3])        # 二乗
array([1, 4, 9], dtype=int32)
>>> np.absolute([-3, -1, 1, 3]) # 絶対値
array([3, 1, 1, 3])
>>> np.sign([-3, -1, 1, 3])     # 符号
array([-1, -1,  1,  1])
>>> np.maximum([-3, -1, 1, 3], [4, 2, -2, -4]) # 各要素の最大値
array([4, 2, 1, 3])
>>> np.minimum([-3, -1, 1, 3], [4, 2, -2, -4]) # 各要素の最小値
array([-3, -1, -2, -4])

1つの配列の最大値・最小値を求める場合は、np.max, np.min関数。

参考:
Mathematical functions — NumPy v1.13 Manual

広告を非表示にする