2020年2月16日日曜日

インフルエンザの報告数の推移

報告数


新型コロナウイルスの話があふれていますが、毎年流行っているインフルエンザの報告数について調べてみました。

指定届出機関からのインフルエンザの週ごとの報告総数です。 データは https://www.niid.go.jp/niid/ja/data.htmlから入手できます。

今年は2018年や2019年に比べて3分の1くらいになっています。2019年12月頃までは2018年に比べて多かったにもかかわらず、年が明けると例年並みに減り(1週目の値)、そこから報告数が拡大していません。どうしてなのでしょうね。

死亡率


ついでに、インフルエンザによる死亡率についても調べてみました。 米国のデータでは、 https://www.ncc.go.jp/jp/ncce/division/safety_management/about/kansen/020/010/20181002160441.html から引用すると、
年齢10万人あたりの死亡者数(米国)
25歳-34歳0.1
65歳-74歳2.2
75歳-84歳8.7
85歳以上43.3
とのこと。

リンクされている元データをたどってみると、 https://www.cdc.gov/nchs/data/nvsr/nvsr68/nvsr68_09-508.pdf のTable 5がそれっぽいので、その値をみてみると、

年齢10万人あたりの死亡者数(米国) 2017年
25歳-34歳0.9
65歳-74歳29.6
75歳-84歳93.8
85歳以上375.3
何か桁が1つ違うような。どうしてだろう。

それはともかく、10万人あたりだと実感がわかないので、%にしてみると、

年齢死亡率(%) (米国) 2017年
25歳-34歳0.0009
65歳-74歳0.0296
75歳-84歳0.0938
85歳以上0.3753
となりました。

日本での死亡率は https://www.hosp.med.osaka-u.ac.jp/home/hp-infect/file/ictmon/ictmon162.pdf に掲載されている図3から数値をざっくり読み取ったところ、

年齢死亡率(%) (日本)
2009年8月3日〜2009年12月13日
30歳-39歳0.001
60歳-69歳0.016
70歳以上0.032

でした。年齢の区分が異なるのでなんともいえませんが、日米ともだいたい同じくらいなのかな。

インフルエンザとは?


インフルエンザの説明は
https://www.niid.go.jp/niid/ja/kansennohanashi/219-about-flu.html
あたりが参考になります。

2020年2月8日土曜日

C++のビルド済みバイナリをpipでインストール

目的

C++ と cmake で作った実行ファイルを、pipでインストールできる形式にします。 加えて、pythonのライブラリも添付します。

なお、PyPIへのアップロード・配布は考慮していません。

作り方

pythonの準備

skbuildを使うので、pip install scikit-build でインストールしておきます。

python 3.8.1 で動作確認しています。

pipでインストールするC++のプログラムの準備

練習用C++プログラムを準備します。既存の、C++ & cmakeでビルドするプログラムがあれば、ここはスキップします。

まず、練習用C++プログラムの本体です。

[aaa.cpp]

1
2
3
4
5
6
7
8
9
#include <iostream>

int main(int argc, char *argv[]){
  std::cout << "aaa bbb ccc" << std::endl;
  for(int i=0; i<argc; ++i){
    std::cout << argv[i] << std::endl;
  }
  return 0;
}
文字列を表示するだけのプログラムです。

これをビルドするCMakeLists.txtを作成します。

[CMakeLists.txt]

1
2
3
4
cmake_minimum_required(VERSION 3.11.0)
project(projAAA)
add_executable(aaa aaa.cpp)
install(TARGETS aaa RUNTIME DESTINATION .)
ここでは aaa という名前のコマンドを作成しています。C++やcmakeの説明は省略します。

setup.py

配布パッケージを作成するためのPythonスクリプト setup.py を作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from skbuild import setup
setup(name="bdist-template", # パッケージの名前。pipでインストール後、pip list で表示される名前
      version="0.0.0",
      author="Your NAME",
      author_email="your@name.com",
      packages=["bdist_example"],  # importするときに使う名前。nameと一致してなくても良い。
                                   # 同じ方がユーザーには親切かも。
      cmake_install_dir="bdist_example/bin", # 最初のディレクトリ名はpackagesで指定した名前と同じにする
      entry_points={
          "console_scripts": [
              "cmdaaa=bdist_example:python_function_aaa"
          ]
          # cmdaaa がpip install後にシェルから使えるコマンド名になる
          # =と:の間は、packagesで指定した名前と同じにする
          # :の右側は後ほど説明
      },
      url="http://yourname.abc",
      download_url="https://yourname.abc/download",
      description="Test package", # このパッケージの短い説明文
      long_description="Test package !!!", # このパッケージの詳細な説明文
      classifiers=[
          "Programming Language :: C++",
          'Programming Language :: Python'
      ],
      license="???" # ライセンス名を記載(GPLとかApacheとか)
)

__init__.py

pipでインストールする場合、C++でビルドした実行ファイルをそのまま実行するのではなく、Pythonを一旦経由するので、 そのためのスクリプトを準備します。

まず、 setup.py のpackagesで指定した名前(ここではbdist_example)のディレクトリを作成します。 そこに次のような内容を含む __init__.py を作成します。

[bdist_example/__init__.py]

1
2
3
4
5
6
7
8
import os
import subprocess
import sys

CMAKE_BIN_DIR = os.path.join(os.path.dirname(__file__), "bin")

def python_function_aaa():
    raise SystemExit(subprocess.call([os.path.join(CMAKE_BIN_DIR, "aaa")] + sys.argv[1:]))
"aaa"の部分を CMakeLists.txt で書いたプログラム名と一致させます。

python_function_aaa は setup.py の console_scripts の部分の : の右側部分に書いた名前と一致させます。

同梱するスクリプト

次のスクリプトも同梱するようにします。バイナリのみの配布であれば、ここはスキップします。

[bdist_example/aaalib.py]

1
2
def print_aaaaa():
    print("aaaaa")

.whlファイルの作成

ここまでそろうとパッケージを作ることができます。

$ python setup.py bdist_wheel
を実行すると、distディレクトリの中に.whlファイルが作成されます。

インストール

作成した.whlを次のようにしてインストールします。

$ pip install dist/bdist_template-0.0.0-cp38-cp38-linux_x86_64.whl 
Processing ./dist/bdist_template-0.0.0-cp38-cp38-linux_x86_64.whl
Installing collected packages: bdist-template
Successfully installed bdist-template-0.0.0

インストールされたことの確認は、

$ pip list
Package        Version
-------------- -------
bdist-template 0.0.0  
packaging      20.1   
pip            20.0.2 
pyparsing      2.4.6  
scikit-build   0.10.0 
setuptools     41.2.0 
six            1.14.0 
wheel          0.34.2 
でできます。bdist-templateがインストールされていることがわかります。

動作確認

先程作成したコマンドが呼び出せることを確認します。

$ cmdaaa x y z
aaa bbb ccc
/home/user/.pyenv/versions/3.8.1/envs/py38/lib/python3.8/site-packages/bdist_example/bin/aaa
x
y
z
C++でビルドしたコマンドそのものは aaa でしたが、setup.pyで書いたコマンド名 cmdaaa が有効になっていることが確認できました。

同梱したスクリプトをpythonから実行してみます。

>>> import bdist_example.aaalib
>>> bdist_example.aaalib.print_aaaaa()
aaaaa

おまけ1

データを同梱したい場合は、次のようなコードを setup.py のsetup関数に渡す引数に追加します。

setup(...
      include_package_data=True,
      package_data={
          "bdist_example": ["data/*.dat"],
      }
)
ここでは、bdist_example/data/*.dat にデータがあると仮定しています。

おまけ2

.whlのファイル名でインストールできるpythonのバージョンが制限されるので、

$ mv bdist_template-0.0.0-{cp38-cp38,py3-none}-linux_x86_64.whl
のようにリネームしておくと、Python3ならインストールできるようになります。

ファイル名での制限を外すと、動作しないバージョンのPythonにインストールできてしまうので、代わりに、

setup(...
      python_requires='~=3.6'
)
のように指定しておきます。バージョン指定の書き方は
https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
が参考になります。

まとめ

skbuild により、 setup.py と __init__.py を準備するだけで .whl ファイルを作ることができました。

参考文献

scikit-build (skbuild) のドキュメント
https://scikit-build.readthedocs.io/en/latest/usage.html#basic-usage

cmake-python-distributions のコード
https://github.com/scikit-build/cmake-python-distributions

プロジェクトのパッケージングと配布
https://python-packaging-user-guide-ja.readthedocs.io/ja/latest/distributing.html
https://packaging.python.org/guides/distributing-packages-using-setuptools/