20190226のPythonに関する記事は30件です。

Python の Iterator と Generator

まとめ

  • Iterator とは、__iter____next__ を持つオブジェクト。for などで繰り返しに使える。
  • Generator function とは、yield を含む関数。Generator を返す。
  • Generator とは、Iterator の一種。send() や throw() など拡張機能もある。

Iterator

まずイテレータの復習。__iter____next__ を持つオブジェクトをイテレータと呼び、for などで繰り返しに使える。

# 1 から max までの数を数えるカウンターをイテレータとして作った
class Counter():

    def __init__(self, max):
        self.count = 0
        self.max = max

    def __iter__(self):
        return self

    def __next__(self):
        self.count += 1
        if self.count <= self.max:
            return self.count
        raise StopIteration()

# 1 から 3 まで for で数える
for i in Counter(3):
    print(i)

# next(iterator, default) はイテレータの次の値を返す。無ければデフォルトを返す。
counter = Counter(3)
print(next(counter, '終わり'))
print(next(counter, '終わり'))
print(next(counter, '終わり'))
print(next(counter, '終わり'))

実行結果

1
2
3
1
2
3
終わり

Generator

Yield 文を使うと、クラス構文を使わずにイテレータを作る事が出来る。yield を含む関数をジェネレータ関数と呼ぶ。ジェネレータ関数は return を含まないのにジェネレータと呼ぶオブジェクトを返す。ジェネレータはイテレータとして使える。yield 文でイテレータとしての結果を返す。

# 1 から max までの数を数えるカウンターをジェネレータで作った
def counter_simple(max=None):
    count = 0
    while count < max:
        count += 1
        next = yield count

for i in counter_simple(3):
    print(i)

実行結果

1
2
3

ジェネレータにはイテレータに加えていろいろ機能がある。

  • generator.send() で値を渡す。渡した値は yield の戻り値となる。
  • generator.throw() で例外を投げられる。
  • generator.close() で中断出来る。
# 1 から max までの数を数えるカウンター高級版
def counter_rich(max=None):
    count = 0
    try:
        while count < max:
            count += 1
            try:
                next = yield count
                if next != None:
                    count = next
            except Exception as e:
                print(f'例外「{e}」がやってきた!')
    finally:
        print('終了します')

print('100 まで数えるカウンター')
counter = counter_rich(100)
print(next(counter))
print(next(counter))
print('counter に 5 を送ってスキップ')
print(counter.send(5))
print(next(counter))
counter.throw(Exception('ちょっと待って'))
print(next(counter))
print(next(counter))
print('100 に行く前に中断')
counter.close()
print(next(counter))

実行結果

100 まで数えるカウンター
1
2
counter に 5 を送ってスキップ
6
7
例外「ちょっと待って」がやってきた!
9
10
100 に行く前に中断
終了します
Traceback (most recent call last):
  File "generator.py", line 38, in <module>
    print(next(counter))
StopIteration

asyncio に続きます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

機械学習実行環境をDockerイメージにする時OpenCVに困ってませんか?

機械学習モデルの実行環境用にDockerイメージを作ろうとして、OpenCVのインストールにハマってしまい丸1日を費やしたので、同じことで悩む人が少しでも減ることを願ってシェアします。

問題点

PythonオフィシャルのDockerイメージに、機械学習に必要なライブラリをpipでインストールして起動し、必要ライブラリをインポートしてバージョン情報を表示するだけの下記プログラムを実行します。

import keras
import tensorflow
import numpy
import PIL
import cv2

print('keras:', keras.__version__)
print('tensorflow:', tensorflow.__version__)
print('numpy:', numpy.__version__)
print('pillow:', PIL.__version__)
print('cv2:', cv2.__version__)

すると、下記のOpenCVが依存しているネイティブ・ライブラリが見つからないというエラーがimportの時点で発生します。

Traceback (most recent call last):
  File "version.py", line 5, in <module>
    import cv2
  File "/usr/local/lib/python3.6/site-packages/cv2/__init__.py", line 3, in <module>
    from .cv2 import *
ImportError: libgthread-2.0.so.0: cannot open shared object file: No such file or directory

解決策

このエラーは、opencv-python自体はpipでインストールされておりcv2は見つかったものの、依存関係にある外部ライブラリが見つからないというエラーになります。「docker pip opencv」などをキーワードに対処方法をググってみると、大半はOpenCVのソースからコンパイルするスクリプトをDockerFileに書こうという記述ばかりが並びちょっと凹みます。

Macでは、pipでopencv-pythonがインストールできて使えていたので、余計に混乱しましたがちょっと冷静になって考えてみると、元々OpenCVはネイティブライブラリでありopencv-pythonはそれに皮を被せただけのラッパーに過ぎないと気づきました。

だったら、apt-getで元々のネイティブライブラリをインストールすれば、依存関係のエラーは解消できるはずと考えてDockerFileを以下のようにしてイメージを作成してみたところエラーは解消されました。

# Replace this line to use python official image as a base.
FROM python:3.6.8-slim-stretch

LABEL Name=try_ml_docker Version=0.0.1
EXPOSE 50000

# Add the following line to get native library of OpenCV.
RUN apt-get update && apt-get -y libopencv-dev 

WORKDIR /app
# Replace this line to copy requirements.txt inside the docker image.
ADD ./requirements.txt /app

RUN python3 -m pip install -r requirements.txt
CMD ["python3", "-m", "try_ml_docker"]

requirements.txtには以下の内容を記載します。coremltoolsはkerasとtensorflowのバージョンに著しく依存するので、coremltools2.0を利用する場合はkerasとtensorflowは下記バージョンに指定します。その他のpythonライブラリは最新版を利用します。

coremltools==2.0
keras==2.1.6
tensorflow==1.5.0
numpy
pillow
opencv-python

Tips

ソースコードやデータセットはVS Code上のものをホストとコンテナの間で共有したいのでカレント・ディレクトリを共有するようにコンテナを実行します。-vパラメーターで渡すのは絶対パスなので、`pwd`コマンドでカレントディレクトリの絶対パスを取得して渡しています。pwdコマンドをくくっているのはバッククォートですので気をつけてください。

$ docker run -v `pwd`:/app -it -d try_ml_docker:latest /bin/bash

おわりに

Apple Musicから流れてくる甲斐バンドの「安奈」を聴きながら、やっぱMac最強、Debian/Ubuntuまじめんどくせぇ…

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

matplotlibで一部のデータをプロットしない方法

はじめに

漫画の掲載順を取得してグラフ化する記事を書いている時に休載で掲載順を取得できない月があり、グラフ化するときに困った。
matplotlibで特定のデータをプロットしない方法が後から分かったのでメモ。

環境

# uname -a                                                                                                                              
Linux kali 4.18.0-kali2-amd64 #1 SMP Debian 4.18.10-2kali1 (2018-10-09) x86_64 GNU/Linux
# python --version                                                                                                                             
Python 3.7.2+
# pip3 show matplotlib                                                                                                                         
Name: matplotlib
Version: 2.2.2

問題

例えば、以下のようなデータがあったとする。

month 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月
data 13 15 21 5 10   21 17 15 16 21 13

6月だけデータがない。

Y_data=[13,15,21,5,10, ,21,17,15,16,21,13]

Y軸のデータの配列に空きができてしまった。どうすればいいのか。

解決法

プロットしたくないor欠損しているデータにはNoneを代入するとその項目はプロットされなくなる。

Y_data=[13,15,21,5,10,None,21,17,15,16,21,13]

こんな感じ。

#!/usr/bin/env python 
import matplotlib.pyplot as plt

X_data=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Y_data=[13,15,21,5,10,None,21,17,15,16,21,13]
month_name=['Jan.','Feb.','Mar.','Apr.','May','Jun.','Jul.','Aug.','Sep.','Oct.','Nov.','Dec.']

plt.xlabel('month')
plt.ylabel('data')

plt.xticks(X_data,month_name)
plt.plot(X_data,Y_data)
plt.show()

結果
plot_None.png

一件落着。

参考文献

python - matplotlibにおけるグラフの始点の指定 - スタック・オーバーフロー
これのお陰で助かりました。ありがとうございます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

matplotlibで特定のデータをプロットしない方法

はじめに

漫画の掲載順を取得してグラフ化する記事を書いている時に休載で掲載順を取得できない月があり、グラフ化するときに困った。
matplotlibで特定のデータをプロットしない方法が後から分かったのでメモ。

環境

# uname -a                                                                                                                              
Linux kali 4.18.0-kali2-amd64 #1 SMP Debian 4.18.10-2kali1 (2018-10-09) x86_64 GNU/Linux
# python --version                                                                                                                             
Python 3.7.2+
# pip3 show matplotlib                                                                                                                         
Name: matplotlib
Version: 2.2.2

問題

例えば、以下のようなデータがあったとする。

month 1月 2月 3月 4月 5月 6月 7月 8月 9月 10月 11月 12月
data 13 15 21 5 10   21 17 15 16 21 13

6月だけデータがない。

Y_data=[13,15,21,5,10, ,21,17,15,16,21,13]

Y軸のデータの配列に空きができてしまった。どうすればいいのか。

解決法

プロットしたくないor欠損しているデータにはNoneを代入するとその項目はプロットされなくなる。

Y_data=[13,15,21,5,10,None,21,17,15,16,21,13]

こんな感じ。

#!/usr/bin/env python 
import matplotlib.pyplot as plt

X_data=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Y_data=[13,15,21,5,10,None,21,17,15,16,21,13]
month_name=['Jan.','Feb.','Mar.','Apr.','May','Jun.','Jul.','Aug.','Sep.','Oct.','Nov.','Dec.']

plt.xlabel('month')
plt.ylabel('data')

plt.xticks(X_data,month_name)
plt.plot(X_data,Y_data)
plt.show()

結果
plot_None.png

一件落着。

参考文献

python - matplotlibにおけるグラフの始点の指定 - スタック・オーバーフロー
これのお陰で助かりました。ありがとうございます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スポーツがうまくなりたい・・・そうだ、姿勢推定してうまい人との差を取れれば・・・!! ~初級編:colaboratory、openposeで簡単動画の姿勢推定~

はじめに

ボルダリングを始めたが全く上手くならない…そうだ!!姿勢推定して他の人と比べて悪いところを具体的に見える形にすれば良いんだ!

というところから、まずはcolaboratoryで姿勢推定(openpose)をやってみようとなりました。

結果↓(全然推定できてない。。。)
IMAGE ALT TEXT HERE

システム構成

今回のシステム構成はこんな感じです。
主に使用するのは、Google Driveとgoogle colaboratoryのみです。
すべてクラウド上なので、ブラウジング用の貧弱なパソコンさえあればOKです。

image.png

Tips:colaboratoryとは?
無料で使うことができ、ほとんどの主要ブラウザで動作する、設定不要のJupyterノートブック環境です。 Googleが、機械学習の教育、研究用に使われることを目的に、無償提供しています。
引用:秒速で無料GPUを使う】深層学習実践Tips on Colaboratory

では、さっそく実装しましょう。

今回は、下記記事の内容を主に参考にしております。@nanako_ut様感謝します。
tensorflow(tf-openpose)で画像から骨格推定

手っ取り早くコードを見たい方は、下記をどうぞ!
https://github.com/sugupoko/OpenPose_movie/blob/master/OpenPose_movie.ipynb

Colaboratoryにアクセス!(初めての方向け)

まずは、このURLアクセスしてみてください。
https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja

そして、”ファイル→python3の新しいノートブック”をクリックしてください。
image.png

そうすると、下記のような新しいページが表示されます。
これで準備OKです!

ここにコードを記述して、”Shift+enter”でpythonスクリプトを簡単に実行できます。
image.png

さあ、開発環境整備しましょう

Openposeを動作させるためには、5つの作業が必要となります。

OpenPose_movie.ipynb
# SWIG を準備
!apt-get -q -y install swig

# TF-openposeをクローン
!git clone https://www.github.com/ildoonet/tf-openpose

# openpose動作のための、ライブラリをインストール
!pip3 install -r requirements.txt

# Openposeのモデルをダウンロード
%cd models/graph/cmu
!bash download.sh
%cd ../../../

# pafprocessをインストール
%cd tf_pose/pafprocess
!ls
!swig -python -c++ pafprocess.i && python3 setup.py build_ext --inplace
%cd ../../

実験!!

まずは、静止画で実験してみる。

こんなのができれば成功です!
image.png

OpenPose_movie.ipynb
# ネットから画像DL
!wget https://www.pakutaso.com/shared/img/thumb/150415022548_TP_V.jpg

# 実行!!
%run -i run.py --model=mobilenet_thin --resize=432x368 --image=150415022548_TP_V.jpg

続いて、動画で実行

ここに一癖あったので、ちょっと苦労しました。

まずは、Googleドライブから動画を読み込むための作業

下記のコードを実行。

OpenPose_movie.ipynb
from google.colab import drive
drive.mount('./gdrive')
drive_root_dir="./gdrive/My Drive/Colab Notebooks/"

URLにアクセスし次へを連打していくとURLがまた表示されるので、それを入力。
こんな画面が出ればOK。
image.png

Googleドライブからcolabへ動画をコピー

下記のようなコマンドを入力することで、コピーすることができます。ディレクトリは個々で異なるので、置いてある動画の場所に応じて変更してください。

OpenPose_movie.ipynb
!cp './gdrive/My Drive/Colab Notebooks/movies/climbing2.mp4' "./"

最後に、実行です!!

もとからある、run_video.pyだとうまく実行できなかったので、スクリプトを改造し実行しちゃいます。
ちょっとややこしいのが、DNNに入力するサイズは16の倍数を前提としているところです。
なのでスクリプト中では、Wは540 -> 544に変更しています。ただし動画を保存するときは、元のサイズで!

OpenPose_movie.ipynb
import argparse
import logging
import time
import os

import cv2
import numpy as np
import matplotlib.pyplot as plt

from tf_pose import common
from tf_pose.estimator import TfPoseEstimator
from tf_pose.networks import get_graph_path, model_wh

movie_name = 'climbing2'

img_outdir = './img'
os.makedirs(img_outdir, exist_ok=True)

# 動画作成
fourcc = cv2.VideoWriter_fourcc('m','p','4', 'v')
video  = cv2.VideoWriter('ImgVideo2.mp4', fourcc, 30.0, (540, 960))


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='tf-pose-estimation Video')

    outimg_files = []
    count = 0
    w = 544 
    h = 960
    e = TfPoseEstimator(get_graph_path('mobilenet_thin'), target_size=(w, h))

    # 動画出力先
    cap = cv2.VideoCapture('climbing2.mp4')

    # 動画用の画像作成
    while True:
        ret, image = cap.read()

        if ret == True:
            # 1フレームずつ処理
            count += 1
            if count % 100 == 0:
                print('Image No.:{0}'.format(count))

            humans = e.inference(image, resize_to_default=(w > 0 and h > 0), upsample_size=4)
            image = TfPoseEstimator.draw_humans(image, humans, imgcopy=False)

            # 画像出力
            outimg_file = '{}/{:05d}.jpg'.format(img_outdir, count)
            cv2.imwrite(outimg_file, image)
            video.write(image)       

        else:
            break
    video.release()

最後に保存

最後にGoogleドライブのコピーで終了です。

OpenPose_movie.ipynb
!cp './ImgVideo2.mp4' "./gdrive/My Drive/Colab Notebooks/movies/"

まとめ

OpenPoseで全然推定できなかったので、どう改善していくか考えなきゃいけません。。。
例えば、データセットを増やすとか?(いやいや厳しい。。。)

下記の記事のように野球のスイングだと取れているんですけどねぇ。。。
https://qiita.com/nanako_ut/items/1a9ce5d4eca672b38d2d

良いアイデアや、論文を知っている方募集しています!!

とはいえ、
姿勢推定のハードルは高くないので、みなさん試しにやってみましょう!!
python, colaboratoryの初心者でも数時間でできちゃいます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【機械学習入門】「PCA+K-meansクラスタリング」を3D見える化♬

頭の中ではきっとこんなイメージ;PCA+K-meansクラスタリング

pca3d512_72_n360.gif
Qiitaへのアップの都合上、若干サイズや分解能を犠牲にしたが、うまく表示できました。
つまり、第一主成分が一番広がりが大きく(分散が大きく)その広がりの方向に延びており(固有値問題の解)、二番目が第二主成分(固有値問題の二番目の解)。。。となっており、今回のように各要素を偏差値で置き換えてPCA分析するのが正解なのが分かる。
【参考】
[Python][Scikit-learn]主成分分析を用いた次元削減、主成分ベクトルを用いた予測と線形回帰による予測の比較

やったこと

・競馬騎手データをとりあえず3次元データのみを利用してクラスタリングしてみる
・3dプロットしてみる

・競馬騎手データを3次元のみのデータを利用してクラスタリングしてみる

データは偏差値にしたものを利用しました。
普通にDistorsionは以下のようになっています。だからクラスタは3クラスか4クラス
keiba3__Distortion.jpg
そして、PCAの第一主成分と第二主成分面でのプロットは以下のとおり
※上記の回転を第一主成分vs第二主成分面でとめたものとみることもできる
keiba3_std2_PCA12_plotSn3.jpg

相関は以下のとおり
※これも回転して1stvs2nd、2ndvs3rd, そして3rdvs1st面で止めた絵になっているはずです
keiba3_correlation.jpg

そして、第一主成分、第二主成分、そして第三主成分の寄与は以下の図のとおり
keiba3_contribution_PCA12_plotSn3.jpg
今回は、優勝、二着、三着のデータ120個を使っているので、上記のように相関が高く、第一主成分の寄与が88%以上と高く、第二と第三が6%、5%と小さいです。
ちなみに、第一、二、三主成分の軸方向のベクトル座標は以下のようになっています。
※固有値だからお互い直交(ベクトルの内積0)してます

v_pca0=[ 0.57958236  0.5776769   0.57478143]
v_pca1=[ 0.25818473  0.53882344 -0.80187901]
v_pca2=[ 0.77293269 -0.61315472 -0.1631452 ]

・3dプロットしてみる

今回は、少しずるしてもともとの座標で描画しています。
ということで、肝心な部分のコードは以下のとおり
※コード全体はおまけに記載します
まず、入力データに対して主成分分析をpcaで実施します。
それぞれの第一主成分などはpca.components_[0]などで求められます。

#主成分分析の実行
pca = PCA()
pca.fit(df.iloc[:, 1:])
PCA(copy=True, n_components=None, whiten=False)
v_pca0 = pca.components_[0]
v_pca1 = pca.components_[1]
v_pca2 = pca.components_[2]

出力してみると、元の座標軸での座標で示されています。
そこから、X座標などを分割します。
※ベクトルは本来原点からの座標になっているので、今回の偏差値に合わせて原点を(50,50,50)にずらします
第三主成分までのベクトルを引きたいのでそれぞれの座標(X,Y,Z)として以下のように求めます

print("v_pca0={},v_pca1={},v_pca2={}".format(v_pca0,v_pca1,v_pca2))
X_pca1=[50,50+30*v_pca0[0]]
Y_pca1=[50,50+30*v_pca0[1]]
Z_pca1=[50,50+30*v_pca0[2]]
X_pca2=[50,50+30*v_pca1[0]]
Y_pca2=[50,50+30*v_pca1[1]]
Z_pca2=[50,50+30*v_pca1[2]]
X_pca3=[50,50+30*v_pca2[0]]
Y_pca3=[50,50+30*v_pca2[1]]
Z_pca3=[50,50+30*v_pca2[2]]

ラベルの表示もしたいので、以下のように定義します。

# 分類結果のラベルを取得する
labels = np.unique(kmeans_model.labels_)

そして、これらを使ってangle毎にプロットを表示します。

def show_with_angle(angle):
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')

カメラ視点を以下のとおり定義します。
【参考】
how to set “camera position” for 3d plots using python/matplotlib?

    ax.view_init(elev = 10., azim = angle) #視点

以下で、求まったクラスタの中心近くにlabelsで定義した名前(0,1,2)をtext記載します。

    for kx, ky,kz, name in zip(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1], kmeans_model.cluster_centers_[:,2], labels):
        ax.text(kx, ky,kz, name, alpha=0.8, size=20)

そして上記で定義した第一成分などの軸を記載します。

    ax.plot(X_pca1,Y_pca1,Z_pca1, c='b', marker='o', alpha=0.5, label='1st pricipal')  
    ax.plot(X_pca2,Y_pca2,Z_pca2, c='r', marker='o', alpha=0.5, label='2nd principal') 
    ax.plot(X_pca3,Y_pca3,Z_pca3, c='g', marker='o', alpha=0.5, label='3rd principal') 

以下で本来のデータを分類されたcolorsの色でプロットします。

    ax.scatter(df.iloc[:, 1], df.iloc[:, 2], df.iloc[:, 3],  c=colors, marker='o', alpha=1)

次にクラスタの中心に大き目(s=100)なプロットをします。

    ax.scatter(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1], kmeans_model.cluster_centers_[:,2], c = "b", marker = "*", s = 100)

最後に軸ラベルと凡例(凡例は上記のプロットのlabelで定義したもの)を記載します。

    ax.set_xlabel('1st')
    ax.set_ylabel('2nd')
    ax.set_zlabel('3rd')
    ax.legend()
    plt.pause(0.01)
    plt.savefig('k-means/keiba3/pca3d/keiba3_PCA3d_angle_'+str(angle)+'.jpg')
    plt.close()

角度は360度を1度ずつ計算しました。
容量の関係で上記のGifアニメーションは5度ずつのデータを表示しています。

for angle in range(0, 360, 1):
    show_with_angle(angle)

まとめ

・PCA+K-meansクラスタリングを3D見える化してみた
・思い通りのGifアニメーションとなった

・さらなら高次元の見える化に挑戦したい

おまけ

import pandas as pd # データフレームワーク処理のライブラリをインポート
import matplotlib.pyplot as plt
from pandas.tools import plotting # 高度なプロットを行うツールのインポート
from sklearn.cluster import KMeans # K-means クラスタリングをおこなう
from sklearn.decomposition import PCA #主成分分析器
from mpl_toolkits.mplot3d import Axes3D
import numpy as np


df = pd.read_csv("keiba100_std3.csv", sep=',', na_values=".") # データの読み込み
df.iloc[:, 1:].head() #解析に使うデータは2列目以降
print(df.iloc[:, 1:])
X=df.iloc[:, 1:]

plotting.scatter_matrix(df[df.columns[1:]], figsize=(6,6), alpha=0.8, diagonal='kde')   #全体像を眺める
plt.savefig('k-means/keiba3/keiba3_scatter_plot4.jpg')
plt.pause(1)
plt.close()

distortions = []
distortions1 = []
for i  in range(1,21):                # 1~20クラスタまで一気に計算 
    km = KMeans(n_clusters=i,
                init='k-means++',     # k-means++法によりクラスタ中心を選択
                n_init=10,
                max_iter=300,
                random_state=0)
    km.fit(df.iloc[:, 1:])                # クラスタリングの計算を実行
    distortions.append(km.inertia_)       # km.fitするとkm.inertia_が得られる
    UF = km.inertia_ + i*np.log(20)*5e2   # km.inertia_ + kln(size)
    distortions1.append(UF)   

fig=plt.figure(figsize=(12, 10))
ax1 = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)
ax1.plot(range(1,21),distortions,marker='o')
ax1.set_xlabel('Number of clusters')
ax1.set_ylabel('Distortion')
ax2.plot(range(1,21),distortions,marker='o')
ax2.set_xlabel('Number of clusters')
ax2.set_ylabel('Distortion')
ax2.set_yscale('log')
ax3.plot(range(1,21),distortions1,marker='o')
ax3.set_xlabel('Number of clusters')
ax3.set_ylabel('Distortion+klog')
ax3.set_yscale('log')
plt.pause(1)
plt.savefig('k-means/keiba3/keiba3__Distortion.jpg')
plt.close()

s=3
# この例では s個のグループに分割 (メルセンヌツイスターの乱数の種を 10 とする)
kmeans_model = KMeans(n_clusters=s, random_state=10).fit(df.iloc[:, 1:])

# 分類結果のラベルを取得する
labels = kmeans_model.labels_
print(labels)     ##################  print(labels) ###################
# それぞれに与える色を決める。
color_codes = {0:'#00FF00', 1:'#FF0000', 2:'#0000FF', 3:'#00FFFF' , 4:'#007777', 5:'#f0FF00', 6:'#FF0600', 7:'#0070FF', 8:'#08FFFF' , 9:'#077777',10:'#177777', 11:'#277777', 12:'#377777', 13:'#477777' , 14:'#577777'}
# サンプル毎に色を与える。
colors = [color_codes[x] for x in labels]

fig, axes = plt.subplots(nrows=3, ncols=3, figsize=(18, 18),sharex=False,sharey=False)
for i in range(1,4):
    for j in range(1,4):
        ax = axes[i-1,j-1]
        x_data=df[df.columns[i]]
        y_data=df[df.columns[j]]
        ax.scatter(x_data,y_data,c=colors)
        cor=np.corrcoef(x_data,y_data)[0, 1]
        ax.set_title("{:.3f}".format(cor),fontsize=30)
plt.savefig('k-means/keiba3/keiba3_correlation.jpg')
plt.close()

#主成分分析の実行
pca = PCA()
pca.fit(df.iloc[:, 1:])
PCA(copy=True, n_components=None, whiten=False)
v_pca0 = pca.components_[0]
v_pca1 = pca.components_[1]
v_pca2 = pca.components_[2]

print("v_pca0={},v_pca1={},v_pca2={}".format(v_pca0,v_pca1,v_pca2))
X_pca1=[50,50+30*v_pca0[0]]
Y_pca1=[50,50+30*v_pca0[1]]
Z_pca1=[50,50+30*v_pca0[2]]
X_pca2=[50,50+30*v_pca1[0]]
Y_pca2=[50,50+30*v_pca1[1]]
Z_pca2=[50,50+30*v_pca1[2]]
X_pca3=[50,50+30*v_pca2[0]]
Y_pca3=[50,50+30*v_pca2[1]]
Z_pca3=[50,50+30*v_pca2[2]]

# 分類結果のラベルを取得する
labels = np.unique(kmeans_model.labels_)

feature = pca.transform(df.iloc[:, 1:])
x,y,z = feature[:, 0], feature[:, 1], feature[:, 2]
X=np.c_[x,y,z]

def show_with_angle(angle):
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.view_init(elev = 10., azim = angle)
    for kx, ky,kz, name in zip(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1], kmeans_model.cluster_centers_[:,2], labels):
        ax.text(kx, ky,kz, name, alpha=0.8, size=20)
    ax.plot(X_pca1,Y_pca1,Z_pca1, c='b', marker='o', alpha=0.5, label='1st pricipal')  
    ax.plot(X_pca2,Y_pca2,Z_pca2, c='r', marker='o', alpha=0.5, label='2nd principal') 
    ax.plot(X_pca3,Y_pca3,Z_pca3, c='g', marker='o', alpha=0.5, label='3rd principal') 
    ax.scatter(df.iloc[:, 1], df.iloc[:, 2], df.iloc[:, 3],  c=colors, marker='o', alpha=1)
    ax.scatter(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1], kmeans_model.cluster_centers_[:,2], c = "b", marker = "*", s = 100)
    ax.set_xlabel('1st')
    ax.set_ylabel('2nd')
    ax.set_zlabel('3rd')
    ax.legend()
    plt.pause(0.01)
    plt.savefig('k-means/keiba3/pca3d/keiba3_PCA3d_angle_'+str(angle)+'.jpg')
    plt.close()

for angle in range(0, 360, 1):
    show_with_angle(angle)

print("pca.explained_variance_ratio_={}".format(pca.explained_variance_ratio_))
plt.bar([1, 2,3], pca.explained_variance_ratio_, align = "center")
plt.title("pca.explained_variance_ratio_={}".format(pca.explained_variance_ratio_))
plt.xlabel("components")
plt.ylabel("contribution")
plt.savefig('k-means/keiba3/keiba3_contribution_PCA12_plotSn'+str(s)+'.jpg')
plt.pause(1)
plt.close()

# データを主成分空間に写像 = 次元圧縮
feature = pca.transform(df.iloc[:, 1:])
x,y = feature[:, 0], feature[:, 1]
X=np.c_[x,y]
kmeans_model = KMeans(n_clusters=s, random_state=10).fit(X) #PCA平面(x、y)で再度クラスタリング

plt.figure(figsize=(6, 6))
for kx, ky, name in zip(x, y, df.iloc[:, 0]):
    plt.text(kx, ky, name, alpha=0.8, size=10)
plt.scatter(x, y, alpha=0.8, color=colors)
plt.scatter(kmeans_model.cluster_centers_[:,0], kmeans_model.cluster_centers_[:,1], c ="b" , marker = "*", s = 200)
plt.title("Principal Component Analysis")
plt.xlabel("The first principal component score")
plt.ylabel("The second principal component score")
plt.savefig('k-means/keiba3/keiba3_std2_PCA12_plotSn'+str(s)+'.jpg')
plt.pause(1)
plt.close()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【pandas】最も近い値でマージするmerge_asof関数

はじめに

今まで存在を知らなかったのですが、めちゃめちゃ便利なのでメモ。
pandas の merge_asof関数について紹介します。
初投稿ですのでお手柔らかに。

基本的な例

import pandas as pd
df_left = pd.DataFrame({'a': [1, 5, 10], 'left_val': ['a', 'b', 'c']})
df_right = pd.DataFrame({'a': [1, 2, 3, 6, 7], 'right_val': [1, 2, 3, 6, 7]})

と2つのテーブルがあったとします。

このとき、

pd.merge_asof(df_left, df_right, on='a', direction='nearest')

と書くだけで、df_left のカラム['a'] に対し、df_right['a'] の最も近い値をキーとして、
2つのテーブルを結合することができます。

キャプチャ.PNG

図のように、

  • df_left['a'] = 1 に最も近い、df_right['a'] = 1の right_val を結合
  • df_left['a'] = 5 に最も近い、df_right['a'] = 6の right_val を結合
  • df_left['a'] = 10 に最も近い、df_right['a'] = 7の right_val を結合

していることが分かります。

許容する範囲の指定

"tolerance" という引数を使うことで、最も近い値をどこまで許容するか、
指定することができます。

import pandas as pd
pd.merge_asof(df_left, df_right, on='a', direction='nearest', tolerance=2)

キャプチャ2.PNG
a=10 に最も近い df_right['a'] は7ですが、
指定した tolerance=2 よりも差が大きいので、NaNが入っています。

参考

公式リファレンス:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.merge_asof.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

本当の初心者でもわかるBottleの使い方【@route】

半分忘備録、半分共有したい思いで書いてます。
この記事はいろいろな記事を見て、

「Bottle動いた!」
「これだけで動くなんてすげえ!」

…知りたいのはそこじゃなくて具体的な使い方なんだよ!!!!
ってなった人に対する記事です。

私自体がいろいろな言語を触るも仕事では一切使いませんし、何だったら今はpythonはおろかVBAともほとんど縁がない仕事しています。
そんな人間がBottleをつかってwebアプリ?を作ろうともがく記事です。

対象と筆者のレベル

対象:ちゃんと意味が分かりながら触りたい人向け
著者のレベル(全般):実務経験なし。基本情報、応用情報合格。
筆者のレベル(コーディング):読めって言われたら定義とかループとかならわかるけど、それ以上は…といった感じ。
筆者の特徴:学校の先生ができる(しているとはいっていない)ので、教えるほうにスキルポイント振ってます

bottleのインストール

これはほかの記事を見て頑張ってください。私はpycharmを使っているので、設定からインタープリターを+し、bottleと検索して使えるようになりました。

bottleのhello worldと@route の使い方

要約:「@route('/○○/')のurlがリクエストされたら以下を返すよ!」

初投稿(2019/02/26)時点ではこれ以外のことはしっかりマニュアル読まないとわからないレベルでした。

便利なことは
@route('/') ←これが最小単位
@route('/○○/')←色々足していける。urlでよく見る感じ
 ・・・・・・・
としておけば、あれとこれとそれの時に実行するという風にできることです。同じことをたくさん書かなくていいのでとても便利で好き。ほかの言語もこういうことできるんでしょうねきっと。

bottleのhello world

helloworld.py
from bottle import route, run

 @route('/')#今回は一番簡単な奴
 def hibottle():#関数名なんてなんでもよい
     return "so easy! :)"#ここの文面が出てくる

run(host='localhost',port=8080,debug=True)

※コピペするとスペースとか微妙なところでエラーはいて実行できないので注意

実行すると出てくる画面にhttp://…みたいなのがでるのでそれをクリックするとhello world成功です。

この段階ではファイル名なんてなんでもよいです。run(○○)はローカルサーバーを立てるおまじないなので、特に気にしないで大丈夫です。ここでエラーが出る時はそもそもbottleが入っていないか、ポートが悪いことが多そうです。8080がなんたらっていう記事を探しましょう。

もうすこし遊びたい奴のhello world

helloworld2.py
from bottle import route, run

 @route('/')#今回は一番簡単な奴
 @route('/hi/')#hiでも同じものが出る
 def hibottle():#関数名なんてなんでもよい
     return "so easy! :)"#ここの文面が出てくる

 @route('/hi/im/gosu/')
 def imnotgosu():#関数名なんてなんでもよい
     return "support is so easy dude? :)"#わかるひとにはわかる

run(host='localhost',port=8080,debug=True)

※コピペするとスペースとか微妙なところでエラーはいて実行できないので注意

実行して出てきたページからurl末尾を '/'→'/hi/im/gosu/' にすると2つ目に設定した文字が出てきます。また '/hi/' も設定してある(こちらは1つ目)のでページが表示されますが、 '/hi/im/' は設定をしていないので、404 Notfoundでエラーになります。

これ弄っているだけで個人的にはまあまあ楽しいです。
また更新します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

redis-pyを使ったzaddコマンドの引数について (v3.2.0)

はじめに

インメモリKVS型DBのRedisをPythonから呼び出す方法として、redis-pyモジュールを使うやり方があります。
このredis-pyにZADDと呼ばれるデータを格納するコマンドがあります。
このZADDの引数に変更があり、古い記事の呼び出し方ではエラーを吐くので、新しい呼び出し方を共有します。

Version

Redis本体は5.0.3, redis-pyはv3.2.0を想定

 Redis 5.0.3 (00000000/0) 64 bit
tikeda:Redis tikeda$ pip show redis
Name: redis
Version: 3.2.0
Summary: Python client for Redis key-value store
Home-page: https://github.com/andymccurdy/redis-py
Author: Andy McCurdy
Author-email: sedrik@gmail.com
License: MIT
Location: /usr/local/var/pyenv/versions/3.7.0/lib/python3.7/site-packages
Requires: 
Required-by: 

ZADDとは

SortedSet型でデータを格納するコマンドです。
SortedSet型は、その名の通り順序付けされた集合の型です。
各データがscoreと呼ばれる値を持っており、それを基にソートされます。

参考: http://redis.shibu.jp/commandreference/sortedsets.html

呼び出し方

これまではzadd(key, score, value)やzadd(key, value, score)といった形でコマンドを叩いていましたが、現バージョンからは以下のようになりました。

import redis

r = redis.Redis(host='localhost', port=6379, db=0)

dict = {}
dict['value'] = 10
r.zadd('aaa', dict)

print(r.zrangebyscore('aaa', '-inf', '+inf'))

ここではZRANGEBYSCOREコマンドを用いて確認しています。

辞書型になったので、まとめてvalueを与えることも可能です。

dict = {}
dict['value'] = 10
dict['has'] = 11
dict['to'] = 12
dict['be'] = 13
dict['set'] = 14
dict['here'] = 15
r.zadd('bbb', dict)

終わりに

redis-pyですが、いつからかZADDコマンドの引数順序(latitudeとlongitudeの順序)が変わっていたりと 闇深な カオスな印象をうけますね

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

sqlalchemy で euc-jp を取り扱う

error
sqlalchemy.exc.ProgrammingError: (ProgrammingError) You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings. u'INSERT INTO category (parent_id, category_name) VALUES (?, ?)' (999, '\xa4\xa2')
対策
from sqlalchemy.interfaces import PoolListener

class SetTextFactory(PoolListener):
    def connect(self, dbapi_con, con_record):
        dbapi_con.text_factory = lambda x: unicode(unescape(x), "euc-jp", "ignore")

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker

def create_session():
    engine = create_engine('sqlite:///./test.db', echo=False,  listeners=[SetTextFactory()])
    Session = scoped_session(sessionmaker(autocommit=False,
                                          autoflush=False,
                                          bind=engine))

参考

sanko-:http://saygox.blogspot.jp/2013/08/sqlalchemy.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

No.041【Python】無限大を表す" inf "について②

python-logo-master-v3-TM-flattened.png

前回に引き続き、無限大を表す「inf」について書いていきます。

I'll write about "inf()",which indicates infinity.

■ infによる判定:==/math.isinf()/ np.isinf()

 Judgement by "inf"

>>> # 参考例:float型 最大値を超える・範囲内の値
>>> # eXXX = 10のXXX乗とする
>>> import math
>>> import numpy as np
>>> 
>>> print(1e1000)
inf
>>> 
>>> print(1e100)
1e+100

■ == 演算子

 Calculation with "=="

>>> # 値が無限であるかを判定
>>> 
>>> print(1e1000 == float("inf"))
True
>>> 
>>> print(1e100 == float("inf"))
False
>>> # infの作成方法は複数あり、どれを使っても問題はない
>>> 
>>> print(float("inf") == math.inf == np.inf)
True
>>> 
>>> print(1e1000 == math.inf)
True
>>> 
>>> print(1e1000 == np.inf)
True
>>> 
>>> print(1e100 == math.inf)
False
>>> 
>>> print(1e100 == np.inf)
False
>>> # 以下式でも、判定結果は真(True)となる
>>> 
>>> print(float("inf") == float("inf") * 100)
True

■ mathモジュール:math.isinf( )

 Math module as for inf

>>> # math.isinf()の場合、負の無限に対しても真(True)を返す
>>> 
>>> print(math.isinf(1e1000))
True
>>> 
>>> print(math.isinf(1e100))
False
>>> 
>>> print(math.isinf(-1e1000))
True

■ NumPy:np.isinf( )

 NumPy as for inf

>>> # 上記 mathモジュールと同様、負の無限に対しても真(True)を返す
>>> 
>>> print(np.isinf(1e1000))
True
>>> 
>>> print(np.isinf(1e100))
False
>>> 
>>> print(np.isinf(-1e1000))
True
>>> # 引数にNumPy配列 "ndarray" を指定可能
>>> # 正負のing → "True", その他 → Falseとなる同サイズの"ndarray"を返す
>>> 
>>> a_inf = np.array([1, np.inf, 3, -np.inf])
>>> 
>>> print(a_inf)
[  1.  inf   3. -inf]
>>> 
>>> print(type(a_inf))
<class 'numpy.ndarray'>
>>> 
>>> print(np.isinf(a_inf))
[False  True False  True]
>>> 
>>> 
>>> a_inf[np.isinf(a_inf)] = 0
>>> 
>>> print(a_inf)
[1. 0. 3. 0.]

■ infの比較

 Infinite comparison

>>> # 比較演算子(>, <)でinfの比較が可能
>>> 
>>> # float および inf の値と比較が可能
>>> # ただし、nanの比較は Falseとなる

■ floatとの比較

 Comparison with "float"

>>> import sys
>>> 
>>> print(sys.float_info.max)
1.7976931348623157e+308
>>> 
>>> print(float("inf") > sys.float_info.max)
True
>>> 
>>> print(-float("inf") < sys.float_info.max)
True

■ nanとの比較

 Comparison with "nan"

>>> # 前述の通り、 nanとの比較は全て"False"となる
>>> 
>>> print(float("inf") > float("nan"))
False
>>> 
>>> print(float("inf") < float("nan"))
False
>>> 
>>> print(float("inf") == float("nan"))
False

■ 整数との比較

 Calculation with "integer"

>>> print(float("inf") > 100)
True
>>> # Python3では、integerの上限はない
>>> # ただし、infはそれよりも値が大きい
>>> 
>>> large_int = int(sys.float_info.max) * 100
>>> 
>>> print(large_int)
17976931348623157081452742373170435679807056752584499659891747680315726078002853876058955863276687817154045895351438246423432132688946418276846754670353751698604991057655128207624549009038932894407586850845513394230458323690322294816580855933212334827479782620414472316873817718091929988125040402618412485836800
>>> 
>>> print(type(large_int))
<class 'int'>
>>> 
>>> print(large_int > sys.float_info.max)
True
>>> 
>>> print(float("inf") > large_int)
True
>>> # float最大値以下のintの値は、float()でfloatに変換可能
>>> # ただし、floatの最大値を超える場合なNG
>>> 
>>> print(float(10**306))
1e+306
>>> 
>>> print(float(10**309))
Traceback (most recent call last):
  File "<pyshell#156>", line 1, in <module>
    print(float(10**309))
OverflowError: int too large to convert to float

随時に更新していきますので、
定期的な購読をよろしくお願いします。
I'll update my article at all times.
So, please subscribe my articles from now on.

本記事について、
何か要望等ありましたら、気軽にメッセージをください!
If you have some requests, please leave some messages! by You-Tarin

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AtCoderの問題を分類しました

はじめに

2019年1月から AtCoder を始めました。問題の復習と自分の技術力を分析するために、問題を解いて得られた知見をメモとして残しています。周りの方から「知見を共有して欲しい」「公開することでコードレビューされて、技術力がより高まるよ」などのアドバイスを頂いたため、本記事を執筆する運びとなりました。

これまでの取り組みは下記ブログに記載しています。参考のためにリンクを記載しますが、本記事とは論点が異なるため、読み飛ばして頂いて構いません。

本記事について

記事の構成

本記事では分類観点を定義し、分類観点ごとに問題を分類します。各分類観点では、サンプルコードと解答例を記載しています。サンプルコードと解答例の定義は下記の通りです。

  • サンプルコード:問題から得られた知見と検証によって得られた知見を整理したコード
  • 解答例:提出したACのコード(一部、TLEのコードがあります。その場合は、「解答例(TLE)」と記載しています。)

実行環境

サンプルコードは下記環境で動作することを確認しています。

$ python --version
Python 3.6.4

解答例はAtCoderの下記言語でACになることを確認しています。

Python3 (3.4.3)

分類観点の定義

分類観点の定義は下記の通りです。1つの問題から複数の観点で分類できる問題は、複数の観点に分類します。

  • 実装観点:実装方式を知っていれば解ける問題
  • 処理観点:処理方式を知っていれば解ける問題
  • 数学観点:数学的知見を知っていれば解ける問題
  • アルゴリズム観点:アルゴリズムを知っていれば解ける問題
  • 計算量観点:計算量を工夫すれば解ける問題

分類する問題の範囲

分類する問題の範囲は下記の通りです。ABC-C問題とARC-A問題は一部問題が同じです。同じ問題の場合、ABC-C問題として扱います。

  • ABC‐A問題(ABC001 - ABC119)
  • ABC‐B問題(ABC001 - ABC119)
  • ABC‐C問題(ABC001 - ABC119)
  • ARC‐A問題(ARC001 - ABC103)

分類する対象の問題

本記事では、上記分類範囲で示したすべての問題が記載されているわけではありません私が上記分類観点で知見が得られた問題のみを記載しています。そのため、参考として私がAtCoderを始めた頃の知識・能力を示します。

  • コーディングができる
    • 四則演算
    • 簡易な if-else文 / for文 / while文
  • コーディングができない
    • 入出力処理
    • 三項演算
    • bit演算 / bool演算
    • リスト処理 / タプル処理 / 辞書処理 / 集合処理
    • 正規表現
    • 各アルゴリズム
    • 計算量を工夫したコード
  • AtCoderの問題解答レベル
    • ABC-A問題が5割解ける
    • ABC-B問題が3割解ける
    • ABC-C問題は全く解けない

本記事の対象者

下記のような方に向けた記事を想定しています。

  • AtCoderを始めようとしている方(使用言語の候補としてPython3がある方)
  • AtCoderをPython3以外でやっている方(使用言語をPython3にしたい方)
  • Python3のコードバリデーションを参考にしたい方
  • Python3の仕様に依らない問題分類を参考にしたい方(処理観点 / 数学観点 / アルゴリズム観点 / 計算量観点)
  • 本記事の内容 / コードをレビューして頂ける方

コーディング規約

利用しているコーディング規約はありません。しかし、下記の方針でコーディングを行っています。※あくまで方針なので、厳密にコーディングしている訳ではありません。

  • インデントは4とする
  • 1行の長さは定義しない
  • 空行はしない(可読性のために一部入れることもある)
  • importは行を分けて定義する
  • クオーテーションはダブルクオテーションで統一する
  • 不要な半角スペースは入れない(可読性のために一部入れることもある)
  • 1処理は1行で記載する
  • 変数 / 型を1行で定義できる場合、1行で定義する
  • if文 / for文 / while文の処理行数が1行の場合、文と処理を1行でコーディングする
  • 命名規則はない
  • 自分の直感に合うコーディングをする

記事の更新方針

分類範囲の問題で未分類 / 未解答の問題があります。また、今後はABC-D問題を解く予定です。そのため、本記事は今後、下記の更新する予定です。更新情報は編集履歴より確認をお願い致します。

  • 未分類問題の追加
  • 未解答問題の追加
  • ABC-D問題の追加

知的財産

本記事に記載しているコードはすべて私が作成したコードです。また、AtCoderにおける知的財産権は下記の通りです。

知的財産権
1.本サービスに対して投稿されたプログラムの所有権と著作権は、そのプログラムを作成したユーザに帰属します
2.本サービスを構成する文章、画像、プログラムその他のデータ等についての一切の権利(所有権、知的財産権、肖像権、パブリシティー権等)は、ユーザ自身が作成したものを除き、弊社又は当該権利を有する第三者に帰属しています
3.ユーザ自身が作成した著作物を本サービスを通じて掲載した場合、弊社が宣伝告知等に利用することを許諾するものとします。また、かかる使用に際して、当該ユーザは著作者人格権を行使しないものとします

本記事に記載しているコードを私的利用する場合、自由に活用して頂いて構いません。また、作成したコードは Github で公開しています。コードを転用する / 商業利用する場合は、本記事のコメント欄 / メール / Twitter で事前にご相談をお願い致します。

学習方法の特性上「他人のコードに酷似している」ことがあります。気分を害される方がいましたら、相談の上で引用元の記載 / 記事の更新 / 文章の削除等に対応しますので、ご連絡をお願い致します。※学習方法は ブログ に記載しています。

最後に

最後となりましたが、読者の方におかれましては初心者競プロerの成長過程と思い、温かく見守って頂けると幸いです。また、このような学習環境を提供して頂いている AtCoder社、SNS等で関わって頂いている競プロerの方に感謝を申し上げます。

以下から分類一覧となります。

実装観点

入力処理

1行 / C列

  • 変数に格納する
サンプルコード
# 入力
1 2

a,b=map(int,input().split())
print(a,b)
# 1 2
  • リストに格納する
サンプルコード
# 入力
1 2 3 4 5

List=[int(i) for i in input().split()]
print(List)
# [1, 2, 3, 4, 5]
  • 変数とリストに格納する
サンプルコード
# 入力
abcdefg

a,*List,b=input() # アンパック
print(a)
# a
print(List)
# ['b', 'c', 'd', 'e', 'f']
print(b)
# g

ABC063 B - Varied

解答例
a,b=map(int,input().split())
print(a+b if a+b<10 else "error")

ABC069 B - i18n

解答例
print(sorted(map(int,"2 1 4 3".split())))
# [1, 2, 3, 4]

ABC051 A - Haiku

解答例
print(*input().split(','))

ABC056 A - HonestOrDishonest

解答例
a,_,b=input()
print("DH"[a==b])

ABC079 A - Good Integer

解答例
a,b,c,d=input()
print("Yes" if a==b==c or b==c==d else "No")

ABC103 A - Task Scheduling Problem

解答例
*a,=map(int,input().split())
print(max(a)-min(a))

R行 / 1列

  • 変数に格納する
サンプルコード
# 入力
1
2

a=int(input())
b=int(input())
print(a,b)
# 1 2
サンプルコード
# 入力
1
2

a,b=(int(input()) for i in range(2))
# a,b=[int(input()) for i in range(2)]
print(a,b)
# 1 2
  • リストに格納する
サンプルコード
# 入力
1
2
3
4
5

List=[int(input()) for i in range(5)]
print(List)
# [1, 2, 3, 4, 5]
  • 入力行数が指定される
サンプルコード
# 入力
5 # 入力行数指定(Raw=5)
1
2
3
4
5

Raw=int(input()) 
List=[int(input()) for i in range(Raw)]
print(List)
# [1, 2, 3, 4, 5]
  • 終了フラグ(-1)が指定される
サンプルコード
# 入力
1
2
3
4
5
-1 # 終了フラグ

List=[]
while True:
    Raw=int(input())
    if Raw==-1:
        break
    List.append(Raw)
print(List)
# [1, 2, 3, 4, 5]

ABC044 A - 高橋君とホテルイージー / Tak and Hotels (ABC Edit)

解答例
n,k,x,y=(int(input()) for i in [0]*4)
print(n*x-(x-y)*max(n-k,0))

R行 / C列

  • 2次元リストに格納する
サンプルコード
# 入力
3 # 行数(Raw)を指定する
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

Raw=int(input())
List=[[int(j) for j in input().split()] for i in range(Raw)]
print(List)
# [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
サンプルコード
# 入力
3 # 行数(Raw)を指定する
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

Raw=int(input())
List=[]
for i in range(Raw):
    List.append(list(map(int,input().split())))
print(List)
# [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]]
サンプルコード
# 入力
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

List=[input().split() for i in range(3)]
print(List)
# [['1', '2', '3', '4', '5'], ['6', '7', '8', '9', '10'], ['11', '12', '13', '14', '15']]
  • 1次元リストに格納する
サンプルコード
# 入力
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

List=[]
for i in range(3):
    List+=list(map(int,input().split()))
print(List)
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
  • 変数に格納する
サンプルコード
# 入力
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

a=" ".join([input() for i in [0]*3])
print(a)
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
print(type(a))
# <class 'str'>

ABC090 A - Diagonal String

解答例
print(input()[0]+input()[1]+input()[2])

不定形

サンプルコード
# 入力
1 2
hoge

(a,b),s=map(int,input().split()),input()
print(a,b,s)
# 1 2 hoge

出力処理

int型

  • 1次元リストを出力する
サンプルコード
Lists=[1,2,3,4,5]
for List in Lists:
    print(List,end=' ')
# 1 2 3 4 5
サンプルコード
List=[1,2,3,4,5]
for i in range(len(List)):
    print(List[i],end=' ')
# 1 2 3 4 5
  • 2次元リストを出力する
サンプルコード
Lists=[[1,2,3],[4,5,6],[7,8,9]]
for List in Lists:
    print(List,end=' ')
# [1, 2, 3] [4, 5, 6] [7, 8, 9]
サンプルコード
List=[[1,2,3],[4,5,6],[7,8,9]]
for i in List:
    for j in i:
        print(j,end=' ')
# 1 2 3 4 5 6 7 8 9
サンプルコード
List=[[1,2,3],[4,5,6],[7,8,9]]
for i in range(len(List)):
    for j in range(len(List[i])):
        print(List[i][j],end=' ')
# 1 2 3 4 5 6 7 8 9

ABC061 B - Counting Roads

解答例
from itertools import chain
List=[[1,2,3],[4,5,6],[7,8,9]]
print(*chain(*List))
# 1 2 3 4 5 6 7 8 9

str型

  • 1次元リストを出力する
サンプルコード
Lists=["ab","cd","ef"]
for List in Lists:
    print(List,end=' ')
# ab cd ef
サンプルコード
List=["ab","cd","ef"]
for i in List:
    for j in i:
        print(j,end=' ')
# a b c d e f
サンプルコード
List=["ab","cd","ef"]
for i in range(len(List)):
    print(List[i],end=' ')
# ab cd ef
サンプルコード
List=["ab","cd","ef"]
for i in range(len(List)):
    for j in range(len(List[i])):
        print(List[i][j],end=' ')
# a b c d e f
  • 2次元リストを出力する
サンプルコード
List=[["ab","cd","ef"],["gh","ij","kl"]]
for i in List:
    for j in i:
        print(j,end=' ')
# ab cd ef gh ij kl
サンプルコード
List=[["ab","cd","ef"],["gh","ij","kl"]]
for i in List:
    for j in i:
        for k in j:
            print(k,end=' ')
# a b c d e f g h i j k l
サンプルコード
List=[["ab","cd","ef"],["gh","ij","kl"]]
for i in range(len(List)):
    for j in range(len(List[i])):
        print(List[i][j],end=' ')
# ab cd ef gh ij kl
サンプルコード
List=[["ab","cd","ef"],["gh","ij","kl"]]
for i in range(len(List)):
    for j in range(len(List[i])):
        for k in range(len(List[i][j])):
            print(List[i][j][k],end=' ')
# a b c d e f g h i j k l

ABC012 A - スワップ

解答例
print(*input().split()[::-1])

ABC048 A - AtCoder *** Contest

解答例
print("A%sC"%input()[8])

区切り文字指定

  • 空白(デフォルト)
サンプルコード
a=1
b=2
c=3
print(a,b,c)
# 1 2 3
  • 改行を指定する
サンプルコード
a=1
b=2
c=3
print(a,b,c,sep='\n')
# 1
# 2
# 3
  • カンマを指定する
サンプルコード
a=1
b=2
c=3
print(a,b,c,sep=',')
# 1,2,3
  • 区切り文字なしを指定する
サンプルコード
a=1
b=2
c=3
print(a,b,c,sep='')
# 123

数値リテラル

指数

サンプルコード
print(10**9+7)
# 1000000007

print(9**.5)
# 3.0

ARC036 A - 数え上げ

解答例
print(10**int(input())+7)

浮動点小数

サンプルコード
print(5e10)
# 50000000000.0

print(1.1e-3)
# 0.0011

ARC018 A - BMI

解答例
H,B=map(float,input().split())
print(H**2*B/1e4)

ABC003 A - AtCoder社の給料

解答例
print((int(input())+1)*5e3)

進数変換

サンプルコード
# 2進数⇒10進数
print(int("1101",2))
# 13

# 8進数⇒10進数
print(int("700",8))
# 448

# 16進数⇒10進数
print(int("FE",16))
# 254

# 10進数⇒2進数
print(bin(23))
# 0b10111

# 10進数⇒8進数
print(oct(23))
# 0o27

# 10進数⇒16進数
print(hex(23))
# 0x17

# 2進数表示
print(0b10111)
# 23

# 8進数表示
print(0o27)
# 23

# 16進数表示
print(0x17)
# 23

ABC105 C - Base -2 Number

解答例
n=int(input())
x=""
while n!=0:
    x=str(n%2)+x
    n=-(n//2)
print(0 if x=="" else x)

ABC068 B - Break Number

解答例
print(2**(len(bin(int(input())))-3))
解答例
n=int(input())
l=[1,2,4,8,16,32,64]
m=0
for i in l:
    if i <= n:
        m=max(m,i)
print(m)

複素数

サンプルコード
print(3+4j)
# (3+4j)

四則演算

小数点切り捨て

  • 床関数(切り捨て):floor
サンプルコード
print(5//3)
# 1

import math
print(math.floor(5/3))
# 1

ABC005 A - おいしいたこ焼きの作り方

解答例
x,y=map(int,input().split())
print(y//x)

ABC108 A - Pair

解答例
print(int(input())**2//4)
解答例
k=int(input())
print((k//2)*((k+1)//2))

小数点切り上げ

  • 天井関数(切り上げ):ceil
サンプルコード
print(-(-5//3))
# 2

print(math.ceil(5/3))
# 2

print(-~(4+5)//2)
# 5

print(-~(5+5)//2)
# 5

ABC009 A - 引越し作業

解答例
print(-(-int(input())//2))

ABC024 A - 動物園

解答例
print(5//3+(5%3>0))

ABC036 A - お茶

解答例
a,b=map(int,input().split())
print(-(-b//a))

ABC082 A - Round Up the Mean

解答例
print(-~sum(map(int,input().split()))//2)

四捨五入

  • 四捨五入:rounding
サンプルコード
print(round(5/3))
# 2

べき乗

  • べき乗:power
サンプルコード
print(2**3)
# 8

import math
print(math.pow(2,3))
# 8.0

平方根

  • 平方根:square root
サンプルコード
print(4**(1/2))
# 2.0

print(4**.5)
# 2.0

import math
print(math.sqrt(4))
# 2.0

ABC077 B - Around Square

解答例
print(int(int(input())**.5)**2)

ABC086 B - 1 21

解答例
print("No" if int(input().replace(" ",""))**.5%1 else "Yes")
解答例
c=int(input().replace(" ",""))
print("Yes" if c==int(c**.5)**2 else "No")

階乗

  • 階乗:factorial
サンプルコード
import math
print(math.factorial(5))
# 120=5×4×3×2×1

ABC055 B - Training Camp

解答例
import math
print(math.factorial(int(input()))%(10**9+7))

乗算

  • 乗算:Multiplication

ABC028 A - テスト評価

解答例
print((["Bad"]*6+["Good"]*3+["Great"]+["Perfect"])[int(input())//10])

ABC115 A - Christmas Eve Eve Eve

解答例
print("Christmas"+" Eve"*(25-int(input())))

剰余演算

  • 剰余演算:modulo

ABC011 A - 来月は何月?

解答例
print(int(input())%12+1)

ABC054 A - One Card Poker

解答例
a,b=map(int,input().split())
print("Draw" if a==b else "Bob" if (a+13)%15<(b+13)%15 else "Alice")

ABC057 A - Remaining Time

解答例
print(sum(map(int,input().split()))%24)

ABC081 A - Placing Marbles

解答例
print(int(input())%9)

ABC102 A - Multiple of 2 and N

解答例
n=int(input())
print(n+n%2*n)

ABC105 A - AtCoder Crackers

解答例
print((eval(input().replace(" ","%"))>0)+0)

繰り返し文

インクリメント/デクリメント

サンプルコード
for i in range(2,5,1):
    print(i, end=' ')
# 2 3 4

for i in range(5,2,-1):
    print(i, end=' ')
# 5 4 3

インクリメント数/デクリメント数の指定

サンプルコード
for i in range(2,10,2):
    print(i, end=' ')
# 2 4 6 8

for i in range(10,2,-2):
    print(i, end=' ')
# 10 8 6 4

条件文

if文

ABC054 A - One Card Poker

解答例
a,b=map(int,input().split())
print("Draw" if a==b else "Bob" if (a+13)%15<(b+13)%15 else "Alice")

if/break/else文

ARC010 A - 名刺交換

解答例
N,M,A,B=map(int,input().split())
for i in range(M):
    if N<=A:N+=B
    N-=int(input())
    if N<0:
        print(i+1)
        break
else:print("complete")

if/in文

サンプルコード
if "abc" in input():
    print("Include")
else:
    print("Not incluede")

ABC006 A - 世界のFizzBuzz

解答例
print("YES" if input() in "369" else "NO")

ABC073 A - September 9

解答例
print("Yes" if "9" in input() else "No")

ABC109 A - ABC333

解答例
print("No" if "2" in input() else "Yes")

ABC111 A - AtCoder Beginner Contest 999

解答例
print("".join(["9" if x=="1" else "1" for x in input()]))

ABC114 A - 753

解答例
print("YES" if input() in "753" else "NO")

複数条件式

サンプルコード
print("True" if a<=x<=a+b else "False")

ABC061 A - Between Two Integers

解答例
a,b,c=map(int,input().split())
print("Yes" if a<=c<=b else "No")

ABC079 A - Good Integer

解答例
a,b,c,d=input()
print("Yes" if a==b==c or b==c==d else "No")

ABC094 A - Cats and Dogs

解答例
a,b,x=map(int,input().split())
print("YES" if a<=x<=a+b else "NO")

bit演算

反転

サンプルコード
print(~(5-3))
# -3

print(~-3)
# 2

print(~-4)
# 3

ABC008 A - アルバム

解答例
print(~eval(input().replace(" ","-"))+2)

ABC069 A - K-City

解答例
a,b=map(int,input().split())
print(~-a*~-b)

ABC106 A - Garden

解答例
a,b=map(int,input().split())
print(~-a*~-b)

シフト

ABC104 A - Rated for Me

解答例
print(["ABC","ARC","AGC"][int(input())//50+8>>5])

ABC108 A - Pair

解答例
print(int(input())**2>>2)

bool演算

bit変換

サンプルコード
print(True+0)
# 1
print(False+0)
# 0
print(-(3>2))
# -1
print(-(3<2))
# 0

ABC022 A - Best Body

解答例
n,s,t=map(int,input().split())
w=c=0
for i in range(n):
    w+=int(input())
    c+=s<=w<=t
print(c)

ABC024 A - 動物園

解答例
a,b,c,k=map(int,input().split())
s,t=map(int,input().split())
print(a*s+b*t-(s+t)*c*(s+t>=k))

ABC096 A - Day of Takahashi

解答例
a,b=map(int,input().split())
print(a-(a>b))

ABC105 A - AtCoder Crackers

解答例
print((eval(input().replace(" ","%"))>0)+0)

リスト処理

  • リスト[ ]はミュータブルで要素の挿入と削除を行うことができ、インデックス(番号)で要素にアクセスします。

リストの長さ

  • len

ABC046 A - AtCoDeerくんとペンキ / AtCoDeer and Paint Cans

解答例
print(len(set(input().split())))

ABC093 A - abc of ABC

解答例
print("Yes" if len(set(input()))==3 else "No")

要素の合計値

  • sum

ABC017 A - プロコン

解答例
print(sum(eval(input().replace(' ','*')) for i in range(3))//10)

要素の追加

  • append/extend/insert
サンプルコード
List=['a','b','c']
List.append('d')
print(List)
# ['a', 'b', 'c', 'd']

List.extend(['e','f'])
print(List)
# ['a', 'b', 'c', 'd', 'e', 'f']

List.insert(1,'z')
print(List)
# ['a', 'z', 'b', 'c', 'd', 'e', 'f']

List.append(['g','h'])
print(List)
# ['a', 'z', 'b', 'c', 'd', 'e', 'f', ['g', 'h']]

List.insert(1,['x','y'])
print(List)
# ['a', ['x', 'y'], 'z', 'b', 'c', 'd', 'e', 'f', ['g', 'h']]

ARC049 A - "強調"

解答例
S=list(input())
A,B,C,D=map(int,input().split())
S.insert(D,"\"")
S.insert(C,"\"")
S.insert(B,"\"")
S.insert(A,"\"")
print(*S,sep="")

要素の探索

  • index
サンプルコード
List=['a','b','c','d','e','f']
print(List.index('c',0,5))
# 2

List=['a','b','c','d','c','c']
print(List.index('c', 0, 5))
# 2

ARC003 A - GPA計算

解答例
print((1/int(input()))*sum("FDCBA".index(r) for r in input()))
解答例
N=int(input())
print(sum(map(int,input().translate(str.maketrans("FDCBA","01234"))))/N)

ARC012 A - 週末

解答例
print(["Saturday","Friday","Thursday","Wednesday","Tuesday","Monday","Sunday"].index(input())%6)

要素の削除

  • pop/remove/del
サンプルコード
List=['a','b','c','d','e','f']
print(List.pop(1))
# b

print(List)
# ['a', 'c', 'd', 'e', 'f']

List.pop()
print(List)
# ['a', 'c', 'd', 'e']

List.remove('d')
print(List)
# ['a', 'c', 'e']

del List[1]
print(List)
# ['a', 'e']

要素の出現回数

  • count
サンプルコード
List=['a','b','b','c','c','c']
print(List.count('c'))
# 3

print(List.count('d'))
# 0

ARC001 A - センター採点

解答例
input()
C=input()
print(*sorted(C.count(c) for c in "1234")[::-3])
解答例
input()
C=input()
l=[C.count(c) for c in "1234"]
print(max(l),min(l))
解答例
input()
C=input()
a=C.count("1")
b=C.count("2")
c=C.count("3")
d=C.count("4")
print(max(a,b,c,d),min(a,b,c,d))

ABC084 B - Postal Code

解答例
a,b=map(int,input().split())
s=input()
print("Yes" if s[a]=="-" and s.count("-")==1 else "No")

要素の連結

  • join
サンプルコード
List=["ab","cd","ef"]
print(List)
# ['ab', 'cd', 'ef']

s=''.join(List)
print(s)
# abcdef

ARC045 A - スペース高橋君

解答例
S=list(input().split())
a=[]
for s in S:
    if s=="Left":a.append("<")
    elif s=="Right":a.append(">")
    else:a.append("A")
print(" ".join(a))

要素のユニーク化

  • set
サンプルコード
# 1次元リスト
List=[2,3,1,2]
print(list(set(List)))
# [1, 2, 3]

# 多次元リスト
List=[[1,0],[0,0],[1,1],[1,0],[0,1],[0,0]]
print(list(map(list,set(map(tuple,List)))))
# [[0, 1], [1, 0], [0, 0], [1, 1]]

ABC046 A - AtCoDeerくんとペンキ / AtCoDeer and Paint Cans

解答例
print(len(set(input().split())))

スライス

サンプルコード
List=["a","b","c","d","e"]

print(List[1:3])
# ['b', 'c']

print(List[1:4:2])
# ['b', 'd']

print(List[:3])
# ['a', 'b', 'c']

print(List[3:])
# ['d', 'e']

print(List[::-1])
# ['e', 'd', 'c', 'b', 'a']

print(List[::-2])
# ['e', 'c', 'a']

ARC005 A - 大好き高橋君

解答例
input()
print(input()[:-1].lower().split().count("takahashikun"))

ARC049 A - "強調"

解答例
S=input()
A,B,C,D=map(int,input().split())
print(S[:A]+'"'+S[A:B]+'"'+S[B:C]+'"'+S[C:D]+'"'+S[D:])

ABC072 B - OddString

解答例
print(input()[::2])

ABC064 A - RGB Cards

解答例
print("NO" if int(input()[::2])%4 else "YES")

ABC066 A - ringring

解答例
print(sum(sorted(map(int,input().split()))[:2]))

ABC077 A - Rotation

解答例
print("YES" if input()==input()[::-1] else "NO")

ABC085 A - Already 2018

解答例
print("2018"+input()[4:])

リスト内包表記

サンプルコード
# 非ネスト
List=[1*i for i in range(5)]
print(List)
# [0, 1, 2, 3, 4]

# ネスト
List=[1*i + 10*j + 100*k for k in range(2) for j in range(3) for i in range(4)]
print(List)
#[0, 1, 2, 3, 10, 11, 12, 13, 20, 21, 22, 23, 100, 101, 102, 103, 110, 111, 112, 113, 120, 121, 122, 123]

in演算子

サンプルコード
List=["a","b","c"]

print("a" in List)
# True

print("a" not in List)
# False

print("d" in List)
# False

print("d" not in List)
# True

print("a" in "auieo")
# True

ABC033 C - 数式の書き換え

解答例
S=map(str,input().split("+"))
ans=0
for s in S:
    if "0" not in s:ans+=1
print(ans)

ABC081 B - Shift only

解答例
A=[2,4,6,8,10]
A=[a/2 for a in A]
print(A)
# [1.0, 2.0, 3.0, 4.0, 5.0]

ABC089 B - Hina Arare

解答例
input()
l=map(str,input().split())
print("Three" if len(set(l))==3 else "Four")
解答例
input()
print("Four" if "Y" in input() else "Three")

ABC049 A - 居合を終え、青い絵を覆う / UOIAUAI

解答例
print("vowel" if input() in "aiueo" else "consonant")

タプル処理

  • タプル( )はイミュータブルで要素の書き換えができません。リストと同様、インデックス(番号)で要素にアクセスします。

要素の探索

ABC054 C - One-stroke Path

解答例
import itertools
N,M=map(int,input().split())
edges={tuple(sorted(map(int,input().split()))) for i in range(M)}
ans=0
for i in itertools.permutations(range(2,N+1),N-1):
    l=[1]+list(i)
    ans+=sum(1 for edge in zip(l,l[1:]) if tuple(sorted(edge)) in edges)==N-1
print(ans)

辞書処理

  • 辞書{ }はミュータブルでリストに似ていますが、要素へのアクセスは値に一意なキーで行います。

要素の探索

ARC012 A - 週末

解答例
print({'Mo':5,'Tu':4,'We':3,'Th':2,'Fr':1,'Sa':0,'Su':0}[input()[:2]])
解答例
d=({"Saturday":0,"Sunday":0,"Monday":5,"Tuesday":4,"Wednesday":3,"Thursday":2,"Friday":1})
print(d[input()])

ABC036 C - 座圧

解答例
N=int(input())
A=[int(input()) for i in range(N)]
B={a:i for (i,a) in enumerate(sorted(set(A)))}
for a in A:
    print(B[a])
解答例
import bisect
N=int(input())
A=[int(input()) for i in range(N)]
B=sorted(list(set(A)))
for a in A:
    print(bisect.bisect_left(B,a))

ABC119 B - Digital Gifts

解答例
XU=[input().split() for i in range(int(input()))]
print(sum([float(x)*{"JPY":1,"BTC":380000}[u] for x,u in XU]))

集合処理

  • 集合{ }は辞書と同様、要素へのアクセスは値に一意なキーで行いますが同じ要素を一つしか持てないため辞書のように値はありません。

A \cup B
サンプルコード
print({"a","b","c"}|{"c","d","e"})
# {'a', 'b', 'd', 'e', 'c'}

A - B
サンプルコード
print({"a","b","c"}-{"c","d","e"})
# {'a', 'b'}

A \cap B
サンプルコード
print({"a","b","c"}&{"c","d","e"})
# {'c'}

ABC079 C - Cat Snuke and a Voyage

解答例
N,M=map(int,input().split())
sa=set()
sb=set()
for i in range(M):
    a,b=map(int,input().split())
    if a==1:sb.add(b)
    if b==N:sa.add(a)
print("IMPOSSIBLE" if len(sa&sb)==0 else "POSSIBLE")

ABC118 B - Foods Loved by Everyone

解答例
n,m=map(int,input().split())
S=set(range(1,m+1))
for i in range(n):
    K,*A=map(int,input().split())
    S&=set(A)
print(len(S))

対称差

A ⊕ B
サンプルコード
print({"a","b","c"}^{"c","d","e"})
# {'a', 'b', 'e', 'd'}

ABC073 C - Write and Erase

解答例
N=int(input())
s=set()
for i in range(N):s^={input()}
print(len(s))

ABC027 A - 長方形

解答例
print(eval(input().replace(' ','^')))

ABC075 A - One out of Three

解答例
print(eval(input().replace(" ","^")))

部分集合

A \subseteq B
サンプルコード
# 左辺の要素すべてが右辺の集合に含まれている場合
print({"a","b"}<={"a","b","c"})
# True

# 左辺の要素すべてが右辺の集合に含まれていない場合
print({"a","d"}<={"a","b","c"})
# False

ABC062 A - Grouping

解答例
x,y=input().split()
a={"1","3","5","7","8","10","12"}
b={"4","6","9","11"}
print("Yes" if {x,y}<=a or {x,y}<=b else "No")

文字の集合

サンプルコード
print(sorted(map(chr,range(97,123))))
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

print(sorted(map(chr,range(65,91))))
# ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']

ABC071 B - Not Found

解答例
print(min(set(map(chr,range(97,123)))-set(input())or["None"]))

ABC093 B - Small and Large Integers

解答例
a,b,k=map(int,input().split())
r=range(a,b+1)
for i in sorted(set(r[:3])|set(r[-3:])):
    print(i)

文字列処理

文字列の長さ

ABC015 A - 高橋くんの研修

解答例
print(max(input(),input(),key=len))

文字列の参照

サンプルコード
s="abc"
print(s[-1])
# c

s="abc"
print(s[len(s)-1])
# c

ABC060 A - Shiritori

解答例
a,b,c=input().split()
print("YES" if a[-1]==b[0] and b[-1]==c[0] else "NO")

文字列の逆順

サンプルコード
s="abc"
print(s[::-1])
# cba

ABC012 A - スワップ

解答例
print(*input().split()[::-1])

文字列のコピー

ABC018 B - 文字列の反転

解答例
s=input()
for i in range(int(input())):
    l,r=map(int,input().split())
    s=s[:l-1]+s[l-1:r][::-1]+s[r:]
print(s)

文字列の判定

サンプルコード
s="dog"
[print(chr(i), end=" ") for i in range(ord('a'), ord('z')+1) if chr(i) in s]
# d g o

s="dog"
[print(chr(i), end=" ") for i in range(ord('a'), ord('z')+1) if chr(i) not in s]
# a b c e f h i j k l m n p q r s t u v w x y z

ABC071 B - Not Found

解答例
print(min(set(map(chr,range(97,123)))-set(input())or["None"]))

文字列からリスト型に変換

サンプルコード
s="abcde"
print(s)
# abcde

l=list(s)
print(l)
# ['a', 'b', 'c', 'd', 'e']

大文字小文字変換

  • upper:すべての文字列を大文字に変換する
サンプルコード
s="this is a pen."
print(s.upper())
# THIS IS A PEN.

ABC059 A - Three-letter acronym

解答例
for a in input().upper().split():print(a[0],end="")
解答例
a,b,c=input().split()
print((a[0]+b[0]+c[0]).upper())
  • lower:すべての文字列を小文字に変換する
サンプルコード
s="THIS IS A PEN."
print(s.lower())
# this is a pen.
  • capitalize:文字列の先頭文字を大文字に変換する
サンプルコード
s="this is a pen."
print(s.capitalize())
# This is a pen.

ABC011 B - 名前の確認

解答例
print("abcd".capitalize())
# Abcd
  • title:各単語の先頭文字を大文字に変換する
サンプルコード
s="this is a pen."
print(s.title())
# This Is A Pen.

三項演算

サンプルコード
print("1" if a == 1 else "other")
# if a == 1:
#     print("1")
# else:
#     print("other")

print("1" if a == 1 else "2" if a == 2 else "3" if a == 3 else "other")
# if a == 1:
#     print("1")
# elif a == 2:
#     print("2")
# elif a == 3:
#     print("3")
# else:
#     print("other")

Lambda式

ABC045 A - 台形 / Trapezoids

解答例
x=lambda:int(input())
print((x()+x())*x()//2)

ABC054 A - One Card Poker

解答例
a,b=map(lambda x:(int(x)+13)%15,input().split())
print("Alice" if a>b else "Bob" if a<b else "Draw")

ABC087 A - Buying Sweets

解答例
i=lambda:int(input())
print((i()-i())%i())

ABC092 A - Traveling Budget

解答例
f=lambda:min(int(input()),int(input()))
print(f()+f())

正規表現

  • 正規表現:Regular Expression

findall

  • findall:マッチする部分すべてをリストで返す

ARC052 A - 何期生?

解答例
import re
print(*re.findall("[0-9]+",input()))

match

  • match:文字列の先頭がパターンにマッチするかを調べる

ABC049 C - 白昼夢 / Daydream

解答例
import re
print("YES" if re.match("^(dream|dreamer|erase|eraser)+$",input()) else "NO")

ABC076 C - Dubious Document 2

解答例
import re
s=input().replace("?",".")
t=input()
for i in range(len(s)-len(t),-1,-1):
    if re.match(s[i:i+len(t)],t):
        s=s.replace(".","a")
        print(s[:i]+t+s[i+len(t):])
        exit()
print("UNRESTORABLE")
解答例
import re
s=input().replace("?",".")
t=input()
for i in range(len(s)-len(t)+1):
    if re.match(s[i:i+len(t)],t):
        s=s.replace(".","a")
        print(s[:i]+t+s[i+len(t):])
        exit()
print("UNRESTORABLE")

ABC104 B - AcCepted

解答例
import re
S = input()
print("AC" if(re.match("^A[a-z]+C[a-z]+$",S)) else "WA")

search

  • search:先頭に限らずパターンにマッチするかを調べる

ARC022 A - スーパーICT高校生

解答例
import re
print("YES" if re.search("i.*c.*t",input().lower()) else "NO")
解答例
import re
print("YES" if re.search("[i|I].*[c|C].*[t|T]",input()) else "NO")

sub

  • sub:マッチした部分を置換する

ARC052 A - 何期生?

解答例
import re
print(re.sub("\D","",input()))

ABC002 B - 罠

解答例
import re
print(re.sub("[aiueo]","",input()))

ABC017 B - choku語

解答例
import re
print("NO" if re.sub(r"ch|o|k|u","",input()) else "YES")

ABC023 B - 手芸王

解答例
import re
print(re.sub("[aiueo]","",input()))

import

bisect

サンプルコード
import bisect
List=[ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

print(bisect.bisect_left(List,5))
#2
"""
List=[ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
       1  2  3  4  5   6   7   8   9  10
          ^ 
"""
print(bisect.bisect_right(List,5))
#3
"""
List=[ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
       1  2  3  4  5   6   7   8   9  10
             ^
"""
print(bisect.bisect_left(List,15))
#7
"""
List=[ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
       1  2  3  4  5   6   7   8   9  10
                           ^ 
"""
print(bisect.bisect_right(List,15))
#8
"""
List=[ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
       1  2  3  4  5   6   7   8   9  10
                               ^
"""

List=[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]

print(bisect.bisect_left(List,2))
#4
"""
List=[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
      1  2  3  4  5  6  7  8  9 10 11 12
               ^
"""
print(bisect.bisect_right(List,2))
#8
"""
List=[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
      1  2  3  4  5  6  7  8  9 10 11 12
                           ^
"""
print(bisect.bisect_right(List,2))
#8
"""
List=[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
      1  2  3  4  5  6  7  8  9 10 11 12
                        ^
"""
print(bisect.bisect_right(List,3))
#12
"""
List=[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
      1  2  3  4  5  6  7  8  9 10 11 12
                                    ^
"""

ABC084 C - Snuke Festival

解答例
import bisect
N=int(input())
A=sorted(list(map(int,input().split())))
B=sorted(list(map(int,input().split())))
C=sorted(list(map(int,input().split())))
print(sum(bisect.bisect_left(A,b)*(N-bisect.bisect_right(C,b)) for b in B))
解答例
from collections import Counter
N=int(input())
A=Counter(input().split())
B=Counter(input().split())
C=Counter(input().split())
ans=0
for a_key,a_count in A.most_common():
    for b_key,b_count in B.most_common():
        for c_key,c_count in C.most_common():
            a_key,b_key,c_key=int(a_key),int(b_key),int(c_key)
            if a_key<b_key and b_key<c_key:
                ans+=a_count*b_count*c_count
print(ans)

collections

  • Counter
サンプルコード
List=['a','a','a','a','b','c','c']
c=collections.Counter(l)

print(c)
# Counter({'a': 4, 'c': 2, 'b': 1})

print(type(c))
# <class 'collections.Counter'>

print(issubclass(type(c), dict))
# True

print(c.keys())
# dict_keys(['a', 'b', 'c'])

print(c.values())
# dict_values([4, 1, 2])

print(c.items())
# dict_items([('a', 4), ('b', 1), ('c', 2)])

print(c.most_common())
# [('a', 4), ('c', 2), ('b', 1)]

print(c.most_common()[0])
# ('a', 4)

print(c.most_common()[-1])
# ('b', 1)

print(c.most_common()[0][0])
# a

print(c.most_common()[0][1])
# 4

print(c.most_common()[::-1])
# [('b', 1), ('c', 2), ('a', 4)]

print(c.most_common(2))
# [('a', 4), ('c', 2)]

values,counts=zip(*c.most_common())

print(values)
# ('a', 'c', 'b')

print(counts)
# (4, 2, 1)

print(c['a'])
# 4

print(c['b'])
# 1

print(c['c'])
# 2

print(c['d'])
# 0

ARC024 A - くつがくっつく

解答例
from collections import Counter
input()
L=Counter(input().split())
R=Counter(input().split())
print(sum([min(value,L[key]) for key,value in R.items()]))

ARC081 C - Make a Rectangle

解答例
from collections import Counter
N=int(input())
A=Counter(list(map(int,input().split())))
x=[0,0]
for a in A:
    if A[a]>1:x.append(a)
    if A[a]>3:x.append(a)
x.sort()
print(x[-1]*x[-2])

ABC071 C - 怪文書 / Dubious Document

解答例
from collections import Counter
n=int(input())
s=Counter(input())
for i in range(n-1):
    s&=Counter(input())
print("".join(sorted(s.elements())))

ABC073 C - Write and Erase

解答例
from collections import Counter
N=int(input())
A=Counter([int(input()) for i in range(N)])
print(sum(1 if count%2 else 0 for count in A.values()))

ABC081 C - Not so Diverse

解答例
from collections import Counter
n,k=map(int,input().split())
a=Counter(input().split())
print(sum(sorted(a.values(),reverse=True)[k:]))
解答例
from collections import Counter
n,k=map(int,input().split())
a=Counter(input().split())
ans=0
keys,counts=zip(*a.most_common())
for num,(key,count) in enumerate(zip(keys,counts)):
    if int(num)>k-1:ans+=count
print(ans)

ABC082 C - Good Sequence

解答例
from collections import Counter
n=int(input())
a=Counter(input().split())
ans=0
for i,j in a.items():
    i=int(i)
    if i>j:
        ans+=j
    elif i<j:
        ans+=j-i
print(ans)

ABC103 C - /\/\/\/

解答例
from collections import Counter
n=int(input())
v=list(map(int,input().split()))
a=Counter(v[0::2]).most_common()
b=Counter(v[1::2]).most_common()
a.append([0,0])
b.append([0,0])
if a[0][0]!=b[0][0]:
    print(n-(a[0][1]+b[0][1]))
else:
    print(min(n-(a[1][1]+b[0][1]),n-(a[0][1]+b[1][1])))

ABC110 C - String Transformation

解答例
from collections import Counter
s=Counter(list(input()))
t=Counter(list(input()))
s,t=list(s.values()),list(t.values())
print("Yes" if sorted(s)==sorted(t) else "No")

ABC008 B - 投票

解答例
from collections import Counter
a=Counter([input() for i in range(int(input()))])
print(a)
# Counter({'taro': 2, 'jiro': 1, 'saburo': 1})
print(a.most_common()[0][0])
# taro

functools

  • reduce
サンプル
from functools import reduce
from operator import add
from operator import sub
from operator import mul
List=[20,1,2,3,4,5]

print(reduce(add,List)) # 35
# add:20+1+2+3+4+5=35
print(reduce(sub,List)) # 5
# sub:20-1-2-3-4-5=5
print(reduce(mul,List)) # 2400
# mul:20*1*2*3*4*5=2400

# Lambda式に変換が可能
print(reduce(lambda a,b:a+b,List)) # 35
print(reduce(lambda a,b:a-b,List)) # 5
print(reduce(lambda a,b:a*b,List)) # 2400

ABC109 C - Skip

解答例
from functools import reduce
from fractions import gcd
N,X=map(int,input().split())
x=[abs(X-int(i)) for i in input().split()]
print(reduce(gcd,x))

heapq

ARC081 C - Make a Rectangle

解答例
import heapq
N=int(input())
s=set()
q=[0,0]
for a in map(int,input().split()):
    if a>q[0]:
        try:
            s.remove(a)
            heapq.heapreplace(q,a)
        except:
            s.add(a)
print(q[0]*q[1])

itertools

  • permutations
4! = 4 × 3 × 2 × 1 = 24通り
サンプルコード
from itertools import permutations
List=["a","b","c","d","e"]
print(list(permutations(List)))
# [('a', 'b', 'c', 'd'), ('a', 'b', 'd', 'c'), ('a', 'c', 'b', 'd'), ('a', 'c', 'd', 'b'), ('a', 'd', 'b', 'c'), ('a', 'd', 'c', 'b'), ('b', 'a', 'c', 'd'), ('b', 'a', 'd', 'c'), ('b', 'c', 'a', 'd'), ('b', 'c', 'd', 'a'), ('b', 'd', 'a', 'c'), ('b', 'd', 'c', 'a'), ('c', 'a', 'b', 'd'), ('c', 'a', 'd', 'b'), ('c', 'b', 'a', 'd'), ('c', 'b', 'd', 'a'), ('c', 'd', 'a', 'b'), ('c', 'd', 'b', 'a'), ('d', 'a', 'b', 'c'), ('d', 'a', 'c', 'b'), ('d', 'b', 'a', 'c'), ('d', 'b', 'c', 'a'), ('d', 'c', 'a', 'b'), ('d', 'c', 'b', 'a')]
print(len(list(permutations(List))))
# 24
_4 P _2 = 4 \times 3 = 12通り
サンプルコード
from itertools import permutations
List=["a","b","c"]
print(list(permutations(List,2)))
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'a'), ('b', 'c'), ('b', 'd'), ('c', 'a'), ('c', 'b'), ('c', 'd'), ('d', 'a'), ('d', 'b'), ('d', 'c')]
print(len(list(permutations(List,2))))
# 12

ARC013 A - 梱包できるかな?

解答例
from itertools import permutations
n,m,l=map(int,input().split())
P=list(map(int,input().split()))
v=0
for p,q,r in permutations(P):
    v=max(v,(n//p)*(m//q)*(l//r))
print(v)
  • product

ABC029 C - Brute-force Attack

解答例
from itertools import product
[print("".join(i)) for i in product("abc",repeat=int(input()))]

ABC114 C - 755

解答例
import itertools
N=int(input())
ans=0
S=[]
for i in range(10):
    S+=list(itertools.product("357",repeat=i))
for s in S:
    if len(set(s))>2 and int("".join(s))<=N:
        ans+=1
print(ans)
  • groupby

ABC063 C - 一次元リバーシ / 1D Reversi

解答例
from itertools import groupby
S=input()
G=groupby(S)
print(len(list(G))-1)

ABC019 B - 高橋くんと文字列圧縮

解答例
import itertools
print("".join([i+str(len(list(j))) for i,j in itertools.groupby(list(input()))]))
解答例
import itertools
s=""
for i,j in itertools.groupby(list(input())):
    s+=i+str(len(list(j)))
print(s)
  • combinations
_4 C _2 = \frac{_4 P _2}{2!} = 6通り
サンプル
from itertools import combinations
List=["a","b","c","d"]
print(list(combinations(List,2)))
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
print(len(list(combinations(List,2))))
# 6

ABC028 C - 数を3つ選ぶマン

解答例
from itertools import combinations
S=map(int,input().split())
print(sorted(map(sum,combinations(S,3)))[-3])

ABC089 C - March

サンプルコード
from itertools import combinations
for a,b,c in combinations("MARCH",3):
    print(a,b,c)
# M A R
# M A C
# M A H
# M R C
# M R H
# M C H
# A R C
# A R H
# A C H
# R C H
解答例
from itertools import combinations
from collections import Counter
N=int(input())
S=Counter()
for i in range(N):
    S[input()[0]]+=1
print(sum([S[a]*S[b]*S[c] for a,b,c in combinations("MARCH",3)]))

math

ABC067 C - Factors of Factorial

解答例
import math
N=math.factorial(int(input()))
i=2
ans=1
M=10**9+7
while i*i<=N:
    cnt=1
    while N%i==0:
        cnt+=1
        N//=i
    ans*=cnt
    i+=1
if N!=1:ans*=2
print(int(ans%M))

ABC055 B - Training Camp

解答例
import math
print(math.factorial(int(input()))%(10**9+7))

組み込み関数

abs

サンプルコード
print(abs(-1))
# 1

all/any

  • all
サンプルコード
print(all([True,True]))
# True

print(all([True,False]))
# False

print(all([False,False]))
# False

ABC081 B - Shift only

解答例
n=int(input())
a=[int(i) for i in input().split()]
c=0
while(True):
    for i in range(len(a)):
        if a[i]==0:
            print(c)
            exit()
        elif a[i]%2==0:
            a[i]=a[i]/2
        else:
            print(c)
            exit()
    c+=1
解答例
input()
A=list(map(int,input().split()))
c=0
while all(a%2==0 for a in A):
    A=[a/2 for a in A]
    c+=1
print(c)
  • any
サンプルコード
print(any([True,True]))
# True

print(any([True,False]))
# True

print(any([False,False]))
# False

enumerate

サンプルコード
List=['Alice', 'Bob', 'Charlie']
for num,name in enumerate(List):
    print(num,name)
# 0 Alice
# 1 Bob
# 2 Charlie

ABC041 C - 背の順

解答例
N=int(input())
A=[(int(a), i) for i,a in enumerate(input().split(),1)]
for a in sorted(A,reverse=True):
    print(a[1])

ABC102 C - Linear Approximation

解答例
N=int(input())
A=sorted(a-i-1 for i,a in enumerate(map(int,input().split())))
print(sum(abs(a-A[N//2]) for a in A))

eval

サンプルコード
print(eval("1+2"))
# 3

ARC018 A - BMI

解答例
print(eval(input().replace(" ","**2*"))/1e4)

ARC035 A - テレビ

解答例
print("4:3" if eval(input().replace(" ","*"))%144 else "16:9")

ABC017 A - プロコン

解答例
print(sum(eval(input().replace(' ','*')) for i in range(3))//10)

ABC050 A - Addition and Subtraction Easy

解答例
print(eval(input()))

map

ABC110 C - String Transformation

解答例
s=sorted(map(list(input()).count,set(s)))
t=sorted(map(list(input()).count,set(t)))
print("Yes" if s==t else "No")

max/min

  • max
サンプルコード
# 2値
print(max(1,2))
# 2

# 多値
print(max(2,1,3))
# 3

# リスト
print(max([2,1,3]))
# 3

# 文字リスト
print(max(['b','a','c','d']))
# d

# 文字列リスト
print(max(['ab','aa','ca','bd']))
# ca

# 文字列長さ
print(max(['a','bcde','fg','hij'],key=len))
# bcde

ABC015 A - 高橋くんの研修

解答例
print(max(input(),input(),key=len))

ABC037 A - 饅頭

解答例
a,b,c=map(int,input().split())
print(max(c//a,c//b))
  • min
サンプルコード
# 2値
print(min(1,2))
# 1

# 多値
print(min(2,1,3))
# 1

# リスト
print(min([2,1,3]))
# 1

# 文字リスト
print(min(['b','a','c','d']))
# a

# 文字列リスト
print(min(['ab','aa','ca','bd']))
# aa

# 文字列長さ
print(min(['a','bcde','fg','hij'],key=len))
# a

ABC037 A - 饅頭

解答例
a,b,c=map(int,input().split())
print(c//min(a,b))

ABC040 A - 赤赤赤赤青

解答例
n,x=map(int,input().split())
print(min(x-1,n-x))

ord/chr

  • ord
サンプルコード
print([chr(i) for i in range(ord('a'),ord('z')+1)])
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

ABC013 A - A

解答例
print(ord(input())-64)
解答例
print(["A","B","C","D","E"].index(input())+1)
  • chr
サンプルコード
print([chr(i) for i in range(97, 97+26)])
# ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

range

サンプルコード
r=range(2,10)

print(r)
# range(2, 10)

print(r[:3])
# range(2, 5)

print(set(r[:3]))
# {2, 3, 4}

print(r[3:])
# range(5, 10)

print(set(r[3:]))
# {5, 6, 7, 8, 9}

print(r[-3:])
# range(7, 10)

print(set(r[-3:]))
# {8, 9, 7}

print(r[:-3])
# range(2, 7)

print(set(r[:-3]))
# {2, 3, 4, 5, 6}

zip

サンプルコード
Matrix=[
    [1,2,3],
    [4,5,6],
    [7,8,9]
]
print(list(map(list,zip(*Matrix))))
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

ARC025 A - ゴールドラッシュ

解答例
print(sum(map(max,zip(*[list(map(int,input().split())) for i in range(2)]))))
解答例
D=map(int,input().split())
J=map(int,input().split())
print(sum(max(d,j) for d,j in zip(D,J)))

ABC058 B - ∵∴∵

解答例
o=list(input())
e=list(input())+[""]
for x,y in zip(o,e):print(x+y,end="")

メソッド

find/rfind

ABC039 C - ピアニスト高橋君

解答例
S=input()[0:12]
key="WBWBWWBWBWBW"*2
ans=["Do","","Re","","Mi","Fa","","So","","La","","Si"]
print(ans[(key.find(S))])

ABC053 B - A to Z String

解答例
s=input()
print(s.rfind("Z")-s.find("A")+1)

isdecimal/isdigit/isnumeric/isalpha/isalnum

  • isdecimal:全ての文字が十進数字なら真、そうでなければ偽(半角・全角のアラビア数字が真)
サンプルコード
s="1234567890"
print(s.isdecimal())
# True

ABC084 B - Postal Code

解答例
a,b=map(int,input().split())
s=input()
if 1<=a<=5 and 1<=b<=5:
    if s[a]=="-":
        if s[0:a].isdecimal() and s[a+1:a+b+1].isdecimal():
            print("Yes")
            exit()
print("No")
  • isdigit:全ての文字が数字なら真、そうでなければ偽(半角・全角のアラビア数字、特殊数字が真)
サンプルコード
s="\u00B2" # 2乗
print(s.isdigit())
# True

ARC052 A - 何期生?

解答例
print("".join(i for i in input() if i.isdigit()))
  • isnumeric:全ての文字が数を表す文字なら真、そうでなければ偽(半角・全角のアラビア数字、特殊数字、漢数字が真)
サンプルコード
s="一二三四五六七八九〇壱億参阡萬"
print(s.isnumeric())
# True
  • isalpha:全ての文字が英字なら真、そうでなければ偽(便宜上「英字」と書いているが、平仮名やカタカナ、漢字なども真)
サンプルコード
s="abcあいうアイウ漢字"
print(s.isalpha())
# True
  • isalnum::全ての文字が英数字なら真、そうでなければ偽(各文字が上のメソッドで真となれば真)
サンプルコード
s="abc100"
print(s.isalnum())
# True

replace

サンプルコード
List=["aabbaa","bbaabb","ababab"]

List=",".join(List)
print(List)
# aabbaa,bbaabb,ababab

List=List.replace('a','c')
print(List)
# ccbbcc,bbccbb,cbcbcb

List=List.split(',')
print(List)
# ['ccbbcc', 'bbccbb', 'cbcbcb']
サンプルコード
List=["aabbaa", "bbaabb", "ababab"]

List=",".join(List).replace('a', 'c').split(',')
print(List)
# ['ccbbcc', 'bbccbb', 'cbcbcb']

ARC019 A - お買い物クライシス

解答例
S=input()
for b,a in zip("ODIZSB","001258"):
    S=S.replace(b,a)
print(S)
解答例
S=input()
b="ODIZSB"
a="001258"
for i in range(6):
    S=S.replace(b[i],a[i])
print(S)
解答例
print(input().replace("O","0").replace("D","0").replace("I","1").replace("Z","2").replace("S","5").replace("B","8"))

ARC045 A - スペース高橋君

解答例
print(input().replace("Left","<").replace("Right",">").replace("AtCoder","A"))

ABC017 A - プロコン

解答例
print(sum(eval(input().replace(' ','*')) for i in range(3))//10)

ABC027 A - 長方形

解答例
print(eval(input().replace(' ','^')))

ABC107 A - Train

解答例
print(eval(input().replace(" ","-"))+1)

ABC109 A - ABC333

解答例
print("No" if eval(input().replace(" ","*"))%2==0 else "Yes")

ABC111 A - AtCoder Beginner Contest 999

解答例
print(input().replace("1","x").replace("9","1").replace("x","9"))

sort/reverse

  • sort
サンプルコード
# 昇順
List=[2,1,3]
List.sort()
print(List)
# [1, 2, 3]

# 降順
List=[2,1,3]
List.sort(reverse=True)
print(List)
# [3, 2, 1]

# 多次元昇順
List=[[0,1],[1,1],[1,0],[0,0]]
List.sort(key=lambda List:(List[0],List[1]))
print(List)
# [[0, 0], [0, 1], [1, 0], [1, 1]]

# 多次元昇順
from operator import itemgetter
List=[[0,1],[1,1],[1,0],[0,0]]
Listsort(key=itemgetter(0,1))
print(List)
# [[0, 0], [0, 1], [1, 0], [1, 1]]

# 多次元降順
List=[[0,1],[1,1],[1,0],[0,0]]
List.sort(key=lambda List:(List[0],List[1]),reverse=True)
print(List)
# [[1, 1], [1, 0], [0, 1], [0, 0]]

# 多次元降順
from operator import itemgetter
List=[[0,1],[1,1],[1,0],[0,0]]
List.sort(key=itemgetter(0,1),reverse=True)
print(List)
# [[1, 1], [1, 0], [0, 1], [0, 0]]
  • reverse
サンプルコード
# 1次元
List=[2,1,3]
List.reverse()
print(List)
# [3, 1, 2]

# 多次元
List=[[0,1],[1,1],[1,0],[0,0]]
List.reverse()
print(List)
# [[0, 0], [1, 0], [1, 1], [0, 1]]

translate/maketrans

ARC019 A - お買い物クライシス

解答例
print(input().translate(str.maketrans("ODIZSB","001258")))

処理観点

行列処理

行集計

\begin{pmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9 \\
\end{pmatrix}
\begin{pmatrix}
1 \\
1 \\
1 \\
\end{pmatrix}
=
\begin{pmatrix}
6 \\
15 \\
24 \\
\end{pmatrix}
サンプルコード
Matrix=[[1,2,3],[4,5,6],[7,8,9]]
print([sum(x) for x in Matrix])
# [6, 15, 24]

列集計

\begin{pmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9 \\
\end{pmatrix}^T
\begin{pmatrix}
1 \\
1 \\
1 \\
\end{pmatrix}
=
\begin{pmatrix}
12 \\
15 \\
18 \\
\end{pmatrix}
サンプルコード
Matrix=[[1,2,3],[4,5,6],[7,8,9]]
print([sum(x) for x in zip(*Matrix)])
# [12, 15, 18]

転置行列

A =
\begin{pmatrix}
1 & 2 \\
3 & 4 \\
5 & 6 \\
\end{pmatrix}
A^T =
\begin{pmatrix}
1 & 3 & 5 \\
2 & 4 & 6 \\
\end{pmatrix}

ABC107 B - Grid Compression

解答例
h,w=map(int,input().split())
a=[[j for j in input()] for i in range(h)]
b=[x for x in a if "#" in x]
c=zip(*[y for y in zip(*b) if "#" in y])
for d in c:print("".join(d))

回転行列

A =
\begin{pmatrix}
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9 \\
\end{pmatrix}
A^{回転} =
\begin{pmatrix}
3 & 6 & 9 \\
2 & 5 & 8 \\
1 & 4 & 7 \\
\end{pmatrix}

ABC004 B - 回転

解答例
print("\n".join(input() for _ in range(4))[::-1])
解答例
for i in reversed([input() for i in range(4)]):
    print(i[::-1])

ABC036 B - 回転

解答例
s=[input() for i in range(int(input()))]
for x in zip(*s):print("".join(x)[::-1])
解答例
s=reversed([input() for i in range(int(input()))])
for x in zip(*s):print("".join(x))

順位行列

ABC004 C - ID

解答例
import collections
import bisect
n,m=map(int,input().split())
p=[[int(j) for j in input().split()] for i in range(m)]
a=collections.defaultdict(list)
for x,y in sorted(p):
    a[x]+=[y]
for x,y in p:
    z=bisect.bisect(a[x],y)
    print("%06d%06d"%(x,z))

素数判定

  • 素数:Prime number

ARC017 A - 素数、コンテスト、素数

解答例
N=int(input())
print("YES" if all([N%n for n in range(2,int(N**.5)+1)]) else "NO")
解答例
N=int(input())
print("YES" if all([N%n for n in range(2,N)]) else "NO")
解答例
N=int(input())
print("NO" if any([N%n==0 for n in range(2,N)]) else "YES")

ARC032 A - ホリドッグ

解答例
N=int(input())
S=sum(n for n in range(N+1))
flag=0
for s in range(2,S):
    if S%s==0:
        flag=1
print("WANWAN" if flag==0 and N!=1 else "BOWWOW")

ARC044 A - 素数判定

解答例
N=int(input())
flag=1
if N==1:flag=0
elif N==2 or N==3 or N==5:flag=1
elif N%2==0 or N%3==0 or N%5==0:flag=0
else:flag=1
print("Prime" if flag==1 else "Not Prime")

ABC106 B - 105

解答例
n=int(input())
print(sum(i<=n for i in [105,135,165,189,195]))
解答例
N = int(input())
prime = 0
for i in range(105, N+1, 2):
    count = 0
    for j in range(1, i+1):
        if(i%j == 0):
            count += 1
    if(count == 8):
        prime += 1
print(prime)

うるう年判定

  • うるう年:Leap year

ARC002 A - うるう年

解答例
import calendar
print("YES" if calendar.isleap(int(input())) else "NO")
解答例
Y=int(input())
print("YES" if Y%4==0 and Y%100!=0 or Y%400==0 else "NO")

奇数/偶数判定

  • 入力数1
f(x) = \left\{
\begin{array}{ll}
Even & (x\;\;mod\;\;2\;\;=\;\;0) \\
Odd & (x\;\;mod\;\;2\;\;=\;\;1)
\end{array}
\right.
サンプルコード
x=int(input())
print(["Even","Odd"][x%2])
x 1 2
x%2 1 0
["Even","Odd"][x%2] Odd Even
  • 入力数2
f(x,y) = \left\{
\begin{array}{ll}
Even & (x y\;\;mod\;\;2\;\;=\;\;0) \\
Odd & (x y\;\;mod\;\;2\;\;=\;\;1)
\end{array}
\right.
サンプルコード
x,y=map(int,input().split())
print(["Even","Odd"][x*y%2])
# Even
x*y 1 2
x*y%2 1 0
["Even","Odd"][x*y%2] Odd Even
  • 入力数3以上
f(x) = \left\{
\begin{array}{ll}
Even & (if\;\;x_{all}\;\;mod\;\;2\;\;=\;\;0) \\
Odd & (otherwise)
\end{array}
\right.
サンプルコード
x=[2,4,6,8]
print("Even" if all([i%2==0 for i in x]) else "Odd")
# Even

x=[2,4,6,9]
print("Even" if all([i%2==0 for i in x]) else "Odd")
# Odd

ARC014 A - 君が望むなら世界中全てのたこ焼きを赤と青に染め上げよう

解答例
print("Blue" if int(input())%2==0 else "Red")

N値判定

  • 2値判定(Zero/NotZero判定)
f(x) = \left\{
\begin{array}{ll}
Zero & (x=0) \\
Not Zero & (x\neq0)
\end{array}
\right.
サンプルコード
x=int(input())
print(["Not Zero","Zero"][x==0])
x 0 1
x==0 True False
["Not Zero","Zero"][x==0] Zero Not Zero

ABC056 A - HonestOrDishonest

解答例
print("HD"[len(set(input()))%2])

ABC099 A - ABD

解答例
print(['ABC','ABD'][len(input())>3])

ABC102 A - Multiple of 2 and N

解答例
n=int(input())
print([N,N*2][N%2])
  • 3値判定(正の数/0/負の数判定)
f(x) = \left\{
\begin{array}{ll}
Positive & (x > 0) \\
0 & (x = 0) \\
Negative& (x < 0)
\end{array}
\right.
サンプルコード
x=int(input())
print(["0","Positive","Negative"][x>0 or -(x<0)])
x -1 0 1
x>0 False False True
x<0 True False Flase
-(x<0) -1 0 0
x>0 or -(x<0) -1 0 True
["0","Positive","Negative"][x>0 or -(x<0)] Negative 0 Positive

ABC078 A - HEX

解答例
x,y=input().split()
print("=><"[x>y or -(x<y)])

ABC083 A - Libra

解答例
a,b,c,d=map(int,input().split())
print(['Balanced','Left','Right'][(a+b>c+d)-(a+b<c+d)])

ABC104 A - Rated for Me

解答例
print(["ABC","ARC","AGC"][(int(input())+400)//1600])

桁数の和

f(x) = \sum_{1}^{length(x)} x_i (x_i:xのi桁目の数)
サンプルコード
x=1234
print(sum(map(int,x)))
# 10(=1+2+3+4)

ABC083 B - Some Sums

解答例
n,a,b=map(int,input().split())
print(sum(i for i in range(n+1) if(a<=sum(map(int,str(i)))<=b)))
解答例
n,a,b=map(int,input().split())
s=0
for i in range(n+1):
    if a<=sum(map(int,str(i)))<=b:
        s+=i
print(s)
解答例
n,a,b=map(int,input().split())
s=0
for i in range(n+1):
    if a<=sum(int(j) for j in str(i))<=b:
        s+=i
print(s)
解答例
n,a,b=map(int,input().split())
s=0
for i in range(n+1):
    c=0
    d=str(i)
    for j in range(len(d)):
        c+=int(d[j])
    if a<=c<=b:
        s+=i
print(s)

ABC101 B - Digit Sums

解答例
N=input()
print("Yes" if int(N)%sum(map(int,list(N)))==0 else "No")
解答例
N=input()
print("Yes" if int(N)%sum(int(_) for _ in N)==0 else "No")
解答例
N=input()
s=0
for n in N:
    s+=int(n)
print("Yes" if int(N)%s==0 else "No")

ABC023 A - 加算王

解答例
print(sum(map(int,input())))

桁の数

ABC057 C - Digits in Multiplication

解答例
N=int(input())
i=int(N**(1/2))
while N%i!=0:
    i-=1
print(len(str(N//i)))
解答例
def ketasu(N):
    count=1
    while N>=10:
        N//=10
        count+=1
    return count
N=int(input())
keta=10**10
for i in range(1,int(N**.5)+1):
    if N%i==0:
        keta=min(keta,max(ketasu(i),ketasu(N//i)))
print(keta)

ARC046 A - ゾロ目数

解答例
N=int(input())-1
print(str(N%9+1)*(N//9+1))
解答例
N=int(input())
num=1
while N>0:
    if len(set(str(num)))==1:N-=1
    num+=1
print(num-1)

日時

ARC023 A - 経過日数

解答例
import datetime
y=int(input())
m=int(input())
d=int(input())
print((datetime.date(2014,5,17)-datetime.date(y,m,d)).days)
解答例
Y=int(input())
M=int(input())
D=int(input())
if M==1 or M==2:
    Y-=1
    M+=12
print(735369-(365*Y+Y//4-Y//100+Y//400+306*(M+1)//10+D-429))

ABC012 B - 入浴時間

解答例
n=int(input())
print("%02d:%02d:%02d"%(n//3600,(n%3600)//60,n%60))

ABC119 A - Still TBD

解答例
print("Heisei" if input()<="2019/04/30" else "TBD")

時計

ABC030 B - 時計盤

解答例
n,m=map(int,input().split())
a=abs(n%12*30-5.5*m)
print(min(a,360-a))

コイン

ARC041 A - コインの反転

解答例
x,y=map(int,input().split())
k=int(input())
print(x+y-abs(k-y))

カード

ABC090 C - Flip,Flip, and Flip......

解答例
N,M=map(int,input().split())
print(1 if N==1 and M==1 else max(N,M)-2 if N==1 or M==1 else N*M-2*N-2*M+4)

グラフ

ARC030 A - 閉路グラフ

解答例
N=int(input())
K=int(input())
print("YES" if K<=N//2 else "NO")

ABC016 C - 友達の友達

解答例
V,E=map(int,input().split())
edges=[set() for i in range(V)]
for i in range(E):
    a,b=map(int,input().split())
    edges[a-1].add(b-1)
    edges[b-1].add(a-1)
for i in range(V):
    print(len({n for v in edges[i] for n in edges[v] if not n in edges[i] and n!=i}))

ABC054 C - One-stroke Path

解答例
import itertools
N,M=map(int,input().split())
edges={tuple(sorted(map(int,input().split()))) for i in range(M)}
ans=0
for i in itertools.permutations(range(2,N+1),N-1):
    l=[1]+list(i)
    ans+=sum(1 for edge in zip(l,l[1:]) if tuple(sorted(edge)) in edges)==N-1
print(ans)

ABC075 C - Bridge

解答例
N,M=map(int,input().split())
edges=[list(map(int,input().split())) for i in range(M)]
ans=0
for x in edges:
    l=list(range(N))
    for y in edges:
        if y!=x:l=[l[y[0]-1] if l[i]==l[y[1]-1] else l[i] for i in range(N)]
    if len(set(l))!=1:ans+=1
print(ans)

ソート

ARC042 A - 掲示板

解答例
N,M=map(int,input().split())
A=[int(input()) for i in range(M)][::-1]
ans=[]
s=set()
for a in A:
    if a not in s:ans.append(a)
    s.add(a)
for i in range(1,N+1):
    if i not in s:ans.append(i)
print(*ans,sep="\n")

順位/ランキング

ABC018 A - 豆まき

解答例
X=[int(input()) for i in range(3)]
for x in X:print(3-sorted(X).index(x))
解答例
l=[int(input()) for _ in range(3)]
s=sorted(l)[::-1]
for i in l:
    print(s.index(i)+1)

宝くじ

ARC006 A - 宝くじ

解答例
E=set(input().split())
b=input()
L=set(input().split())
l=len(E&L)
ans=0
if l==5 and b in L:ans=2
elif l==6:ans=1
elif l>2:ans=8-l
else:ans=0
print(ans)
解答例
a = [int(i) for i in input().split()]
b = int(input())
c = [int(i) for i in input().split()]
k = 6 - len(set(a) - set(c))
if k == 5 and b in c: print(2)
else: print({6:1,5:3,4:4,3:5}.get(k,0))

グリッド

ABC096 C - Grid Repainting 2

解答例
H,W=map(int,input().split())
S=["."+input()+"." for i in range(H)]
S=["."*(W+2)]+S+["."*(W+2)]
flag=0
for i in range(H):
    for j in range(W):
        if S[i][j]=="#":
            if S[i-1][j]=="." and S[i+1][j]=="." and S[i][j-1]=="." and S[i][j+1]==".":
                flag=1
print("Yes" if flag==0 else "No")

ABC107 B - Grid Compression

解答例
h,w=map(int,input().split())
a=[[j for j in input()] for i in range(h)]
b=[x for x in a if "#" in x]
c=zip(*[y for y in zip(*b) if "#" in y])
for d in c:print("".join(d))

ABC075 B - Minesweeper

解答例
h,w=map(int,input().split())
s=[input() for _ in range(h)]
for i in range(h):
    l=""
    for j in range(w):
        if s[i][j]=="#":
            l+="#"
        else:
            l+=str(sum([t[max(0,j-1):min(w,j+2)].count("#") for t in s[max(0,i-1):min(h,i+2)]]))
    print(l)

ABC054 B - Template Matching

解答例
n,m=map(int,input().split())
a=[input() for _ in range(n)]
b=[input() for _ in range(m)]
r=any([r[j:j+m] for r in a[i:i+m]]==b for i in range(n-m+1) for j in range(n-m+1))
print('Yes' if r else 'No')

回文

ABC090 B - Palindromic Numbers

解答例
a,b=map(int,input().split())
print(sum(i==i[::-1] for i in map(str,range(a,b+1))))
解答例
a,b=map(int,input().split())
print(len([i for i in map(str,range(a,b+1)) if i==i[::-1]]))

数列

ABC050 C - Lining Up

解答例
import math
N=int(input())
A=list(map(int,input().split()))
flag=True
if N%2==0:
    if 0 in A or len(set(A))!=N//2:flag=False
else:
    if len([0 for a in A if a==0])!=1 or len(set(A))!=N//2+1:flag=False
if flag:print(2**(N//2)%(10**9+7))
else:print(0)

ABC059 C - Sequence

解答例
n=input()
a=[int(i) for i in input().split()]
def chk(a,t):
    ans=0
    x=0
    for i in a:
        x+=i
        if t==True and x<1:
            ans+=1-x
            x=1
        elif t==False and x>-1:
            ans+=x+1
            x=-1
        t=not t
    return ans
print(min(chk(a,True),chk(a,False)))

ABC087 C - Candies

解答例
n=int(input())
a=list(map(int,input().split()))
b=list(map(int,input().split()))
print(max(sum(a[:i+1])+sum(b[i:]) for i in range(n)))
解答例
n=int(input())
a=list(map(int,input().split()))
b=list(map(int,input().split()))
ans=0
for i in range(n):
    ans=max(ans,sum(a[:i+1])+sum(b[i:]))
print(ans)

ABC092 C - Traveling Plan

解答例
N=int(input())
A=[0]+list(map(int,input().split()))+[0]
cost=sum(abs(A[i+1]-A[i]) for i in range(N+1))
for i in range(1,N+1):
    print(cost-abs(A[i+1]-A[i])-abs(A[i]-A[i-1])+abs(A[i+1]-A[i-1]))
解答例
N=int(input())
A=list(map(int,input().split()))+[0]
A.insert(0,0)
cost=0
for i in range(N+1):
    cost+=abs(A[i+1]-A[i])
for i in range(1,N+1):
    print(cost-abs(A[i+1]-A[i])-abs(A[i]-A[i-1])+abs(A[i+1]-A[i-1]))

ABC093 C - Same Integers

解答例
l=sorted(map(int,input().split()))
a=2*l[2]-l[1]-l[0]
print((a+3)//2 if a%2 else a//2)

ABC100 C - *3 or /2

解答例
n=int(input())
a=list(map(int,input().split()))
c=0
for i in a:
    while i%2==0:i,c=i/2,c+1
print(c)

範囲

ABC060 C - Sentou

解答例
N,T=map(int,input().split())
t=list(map(int,input().split()))
ans=0
for i in range(N-1):
    ans+=min(t[i+1]-t[i],T)
print(ans+T)

ABC070 B - Two Switches

解答例
a,b,c,d=map(int,input().split())
print(max(0,min(b,d)-max(a,c)))
解答例
a,b,c,d=map(int,input().split())
t=len(set(map(int,range(a,b+1)))&set(map(int,range(c,d+1))))-1
print("0" if t==-1 else t)

文字列の回転

ABC103 B - String Rotation

解答例
print("Yes" if input() in input()*2 else "No")

文字列の辞書順

ABC025 A - 25個の文字列

解答例
s=input()
n=int(input())-1
print(s[n//5]+s[n%5])

剰余算

ABC099 C - Strange Bank

解答例
N=int(input())
ans=N
for i in range(N+1):
    cnt=0
    while i>0:
        cnt+=i%6
        i//=6
    j=N-i
    while j>0:
        cnt+=j%9
        j//=9
    ans=min(ans,cnt)
print(ans)

ABC111 B - AtCoder Beginner Contest 111

解答例
N=int(input())
print((((N-1)//111)+1)*111)

ABC008 A - たこ焼き買えるかな?

解答例
N=int(input())
print(N//10*100+min(100,N%10*15)

ABC014 A - けんしょう先生のお菓子配り

解答例
print(-int(input())%int(input()))
解答例
a=int(input())
b=int(input())
print((((a//b)+1)*b-a) if a%b else "0")

数学観点

和差算

ABC096 B - Maximum Sum

解答例
a,b,c=sorted(map(int, input().split()))
print(a+b+c*2**int(input()))
解答例
l=[int(_) for _ in input().split()]
k=int(input())
print(sum(l)-max(l)+max(l)*2**k)

ABC110 A - Maximize the Formula

解答例
l=list(map(int,input().split()))
print(sum(l)+max(l)*9)
解答例
print(eval('+'.join(sorted(input()))+'*10'))

ABC111 A - AtCoder Beginner Contest 999

解答例
print(1110-int(input()))

数直線

ABC110 B - 1 Dimensional World's Tale

解答例
N,M,X,Y=map(int,input().split())
xi=list(map(int,input().split()))
yi=list(map(int,input().split()))
xi.append(X)
yi.append(Y)
print("No War" if max(xi)<min(yi) else "War")

円と長方形

解答例
x,y,r=map(int,input().split())
a,b,c,d=map(int,input().split())
if a<=x-r and x+r<=c and b<=y-r and y+r<=d:print("NO")
else:print("YES")
if max((a-x)**2,(c-x)**2)+max((b-y)**2,(d-y)**2)<=r**2:print("NO")
else:print("YES")

座標

ABC051 C - Back and Forth

解答例
sx,sy,tx,ty=map(int,input().split())
ans=[]

for i in range(ty-sy):
    ans.append("U")
for i in range(tx-sx):
    ans.append("R")
for i in range(abs(sy-ty)):
    ans.append("D")
for i in range(abs(sx-tx)):
    ans.append("L")

ans.append("L")
for i in range(ty-sy+1):
    ans.append("U")
for i in range(tx-sx+1):
    ans.append("R")
ans.append("D")
ans.append("R")
for i in range(abs(sy-ty)+1):
    ans.append("D")
for i in range(abs(sx-tx)+1):
    ans.append("L")
ans.append("U")

print("".join(ans))

ABC035 B - ドローン

解答例
s=input()
d=abs(s.count("L")-s.count("R"))+abs(s.count("U")-s.count("D"))
q=s.count("?")
if int(input())==1:print(d+q)
else:print(max(len(s)%2,d-q))

ABC108 B - Ruined Square

解答例
x1,y1,x2,y2=map(int,input().split())
x=x2-x1
y=y2-y1
print(x2-y,y2+x,x1-y,y1+x)

面積

ABC062 C - Chocolate Bar

解答例
h,w=map(int,input().split())
pattern=[h//2+w//3+1,h//3+w//2+1,h,w]
if h%3==0 or w%3==0:
    pattern+=[0]
if h%2==0:
    pattern+=[h//2]
if w%2==0:
    pattern+=[w//2]
print(min(pattern))

ABC047 B - すぬけ君の塗り絵 2 イージー / Snuke's Coloring 2 (ABC Edit)

解答例
w,h,n=map(int,input().split())
b=c=0
for _ in range(n):
    x,y,a=map(int,input().split())
    if a==1:b=max(b,x)
    if a==2:w=min(w,x)
    if a==3:c=max(c,y)
    if a==4:h=min(h,y)
print(max(0,(w-b))*max(0,(h-c)))
解答例
w,h,n=map(int,input().split())
l=[[int(j) for j in input().split()] for i in range(n)]
b=c=0
for i in range(n):
    x,y,a=l[i][0],l[i][1],l[i][2]
    if a==1:b=max(b,x)
    if a==2:w=min(w,x)
    if a==3:c=max(c,y)
    if a==4:h=min(h,y)
print([(w-b)*(h-c),0][(w<b)|(h<c)])

ABC016 A - Right Triangle

解答例
a,b,c=map(int,input().split())
print(a*b//2)

ABC039 A - 高橋直体

解答例
a,b,c=map(int,input().split())
print(2*(a*b+b*c+c*a))

倍数

ABC100 B - Ringo's Favorite Numbers

解答例
D,N=map(int,input().split())
l=[int(pow(100,D)*i) for i in range(1,N+1)]
print(l[N-1])

約数

ABC106 B - 105

解答例
N=int(input())
prime=0
for i in range(105,N+1,2):
    count=0
    for j in range(1,i+1):
        if(i%j==0):
            count+=1
    if(count==8):
        prime+=1
print(prime)

約数の個数

ある整数 $ x $ が素因数分解によって $ x= p^n × q^m × ... (p,q,...は素数) $ と表される時、 $ x $ の約数の個数は $ (n+1) × (m+1) × ... $ となる。

ABC067 C - Factors of Factorial

解答例
import math
N=math.factorial(int(input()))
i=2
ans=1
M=10**9+7
while i*i<=N:
    cnt=1
    while N%i==0:
        cnt+=1
        N//=i
    ans*=cnt
    i+=1
if N!=1:ans*=2
print(int(ans%M))

順列

  • 順列:permutation
_4 P _2 = 4 \times 3 = 12通り
サンプルコード
from itertools import permutations
List=["a","b","c","d"]

print(list(permutations(List,2)))
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'a'), ('b', 'c'), ('b', 'd'), ('c', 'a'), ('c', 'b'), ('c', 'd'), ('d', 'a'), ('d', 'b'), ('d', 'c')]

print(len(list(permutations(List,2))))
# 12

ARC013 A - 梱包できるかな?

解答例
from itertools import permutations
n,m,l=map(int,input().split())
P=list(map(int,input().split()))
v=0
for p,q,r in permutations(P):
    v=max(v,(n//p)*(m//q)*(l//r))
print(v)

組み合わせ

  • 組み合わせ:combination
_4 C _2 = \frac{_4 P _2}{2!} = 6通り
サンプル
from itertools import combinations
List=["a","b","c","d"]

print(list(combinations(List,2)))
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]

print(len(list(combinations(List,2))))
# 6

ABC028 C - 数を3つ選ぶマン

解答例
from itertools import combinations
S=map(int,input().split())
print(sorted(map(sum,combinations(S,3)))[-3])

ABC089 C - March

解答例
from itertools import combinations
from collections import Counter
N=int(input())
S=Counter()
for i in range(N):
    S[input()[0]]+=1
print(sum([S[a]*S[b]*S[c] for a,b,c in combinations("MARCH",3)]))

ABC108 A - Pair

解答例
K=int(input())
print((K//2)*((K+1)//2))

経路

\frac{(width+height -2)!}{(width-1)!(height -1)!}

ABC034 C - 経路

解答例
from math import factorial
W,H=map(int,input().split())
m=10**9+7
print(factorial(W+H-2)*pow(factorial(H-1)*factorial(W-1)%m,m-2,m)%m)

色塗り

ABC046 B - AtCoDeerくんとボール色塗り / Painting Balls with AtCoDeer

解答例
n,k=map(int,input().split())
print(k*(k-1)**(n-1))

重複組み合わせ

サンプルコード
from itertools import combinations_with_replacement
List=["a","b","c","d"]

print(list(combinations_with_replacement(List,3)))
# [('a', 'a', 'a'), ('a', 'a', 'b'), ('a', 'a', 'c'), ('a', 'a', 'd'), ('a', 'b', 'b'), ('a', 'b', 'c'), ('a', 'b', 'd'), ('a', 'c', 'c'), ('a', 'c', 'd'), ('a', 'd', 'd'), ('b', 'b', 'b'), ('b', 'b', 'c'), ('b', 'b', 'd'), ('b', 'c', 'c'), ('b', 'c', 'd'), ('b', 'd', 'd'), ('c', 'c', 'c'), ('c', 'c', 'd'), ('c', 'd', 'd'), ('d', 'd', 'd')]

print(len(list(combinations_with_replacement(List,3))))
# 20

期待値

ABC078 C - HSI

解答例
n,m=map(int,input().split())
print((1900*m+100*(n-m))*2**m)

ABC003 A - AtCoder社の給料

解答例
print((int(input())+1)*5e3)

数列の和

f(x) = \sum_{1}^n x = \frac{n(n + 1)}{2}
サンプルコード
n=int(input())
print(n*(n+1)//2)
サンプルコード
n=int(input())
print(n*-~n//2)
サンプルコード
print(sum(range(int(input())+1)))

ABC099 B - Stone Monument

解答例
a, b = map(int, input().split())
n = b - a
print(n*(n+1)//2-b)

ABC043 A - キャンディーとN人の子供イージー / Children and Candies (ABC Edit)

解答例
n=int(input())
print(n*(n+1)//2)

連立方程式の解

2x+3y+4z=10 (0≦x<20, 0≦y<30, 0≦z<40)
サンプルコード
List=[(x,y,z) for z in range(40) for y in range(30) for x in range(20) if 2*x+3*y+4*z==10]
print(List)
# [(5, 0, 0), (2, 2, 0), (3, 0, 1), (0, 2, 1), (1, 0, 2)]

List=list(map(list,set(List)))
print(List)
# [[2, 2, 0], [3, 0, 1], [0, 2, 1], [5, 0, 0], [1, 0, 2]]

print(len(List))
# 5
  • 解に条件がある場合
2x+3y+4z=10 (0≦x<20, 0≦y<30, 0≦z<40, x+y+z=4)
サンプルコード
List=[(x,y,z) for z in range(40) for y in range(30) for x in range(20) if 2*x+3*y+4*z==10 and x+y+z==4]
print(List)
# [(2, 2, 0), (3, 0, 1)]

List=list(map(list,set(List)))
print(List)
# [[3, 0, 1], [2, 2, 0]]

print(len(List))
# 2

ABC085 C - Otoshidama

連立方程式の解の個数

2x+3y+4z=10 (0≦x<20, 0≦y<30, 0≦z<40)
サンプルコード
print([2*x + 3*y + 4*z for z in range(40) for y in range(30) for x in range(20)].count(10))
# 5
サンプルコード
# 1はdummy変数
print(len([1 for x in range(20) for y in range(30) for z in range(40) if 2*x+3*y+4*z==10]))
# 5

ABC087 B - Coins

x+y+z=S (0≦x, y, z<k≦2500)(0≦S<3K)
サンプルコード
s=7000
k=2500
# 1はdummy変数
print(len([1 for y in range(k) for x in range(k) if 0<=s-x-y<=k]))
# 124750
サンプルコード
s=7000
k=2500
# 1はdummy変数
print([1 for y in range(k) for x in range(k) if 0<=s-x-y<=k].count(1))
# 124750

ABC051 B - Sum of Three Integers

平方根の整数部と小数部の算出

y = x^{1/2} (a:整数部, b:小数部)
サンプルコード
x=2
y=x**.5

# 平方値
print(y)
# 1.4142135623730951

# 整数部
a=int(y)
print(a)
# 1

# 小数部
b=y-a
print(b)
# 0.41421356237309515

ABC077 B - Around Square

解答例
print(int(int(input())**.5)**2)

相加相乗平均

\frac{a+b}{2} ≧ \sqrt{ab}

ABC026 A - 掛け算の最大値

解答例
print(int(input())**2//4)
解答例
n=int(input())
print((n//2)*(-(-n//2)))

ユークリッド距離

distance(\boldsymbol{x},\boldsymbol{y}) = \sqrt{\sum_{i=1}^n(x_i - y_i)^2}
\sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}

ARC004 A - 2点間距離の最大値 ( The longest distance )

解答例
p=[list(map(int,input().split())) for i in range(int(input()))]
print(max(((a[0]-b[0])**2+(a[1]-b[1])**2)**.5 for b in p for a in p))
解答例
import math
p=[list(map(int,input().split())) for i in range(int(input()))]
print(max(math.hypot(a[0]-b[0],a[1]-b[1]) for b in p for a in p))
解答例
N=int(input())
p=[]
for i in range(N):
    x,y=map(int,input().split())
    p.append([x,y])
d=0
for i in range(N):
    for j in range(N):
        if i!=j:d=max(d,((p[i][0]-p[j][0])**2+(p[i][1]-p[j][1])**2)**.5)
print(d)

マンハッタン距離

distance(\boldsymbol{x},\boldsymbol{y}) = \sum_{i=1}^n|x_i - y_i|
|x_1 - x_2| + |y_1 - y_2|

ABC057 B - Checkpoints

解答例
n,m=map(int,input().split())
ab=[[int(j) for j in input().split()] for i in range(n)]
cd=[[int(j) for j in input().split()] for i in range(m)]
for a,b in ab:
    l=[abs(a-c)+abs(b-d) for c,d in cd]
    print(l.index(min(l))+1)
解答例
n,m=map(int,input().split())
a=[[int(j) for j in input().split()] for i in range(n)]
c=[[int(j) for j in input().split()] for i in range(m)]
for i in range(n):
    d=10e8
    b=0
    for j in range(m):
        if abs(a[i][0]-c[j][0])+abs(a[i][1]-c[j][1])<d:
            d=abs(a[i][0]-c[j][0])+abs(a[i][1]-c[j][1])
            b=j+1
    print(b)

ヘロンの公式

S = \sqrt{s(s-a)(s-b)(s-c)} \\
s = \frac{a+b+c}{2}

ヘロンの公式 - Wikipedia
ABC002 C - 直訴

解答例
x1,y1,x2,y2,x3,y3=map(int,input().split())
a=((x1-x2)**2+(y1-y2)**2)**.5
b=((x2-x3)**2+(y2-y3)**2)**.5
c=((x3-x1)**2+(y3-y1)**2)**.5
s=(a+b+c)/2
print((s*(s-a)*(s-b)*(s-c))**.5)

コラッツ予想

f(n) = \left\{
\begin{array}{ll}
n / 2 & (if\;\;n=0) \\
3n + 1 & (if\;\;n=1)
\end{array}
\right.

コラッツの問題 - Wikipedia
ABC116 B - Collatz Problem

解答例
S=int(input())
l=[]
while (S not in l):
    l.append(S)
    if S%2==0:S//=2
    else:S=3*S+1
print(len(l)+1)

必要十分条件

P \rightarrow Q
解答例
x,y,r=map(int,input().split())
a,b,c,d=map(int,input().split())
if a<=x-r and x+r<=c and b<=y-r and y+r<=d:print("NO")
else:print("YES")
if max((a-x)**2,(c-x)**2)+max((b-y)**2,(d-y)**2)<=r**2:print("NO")
else:print("YES")

アルゴリズム観点

ユークリッドの互除法

  • 2つの自然数の最大公約数を求める手法

ユークリッドの互除法 - Wikipedia

サンプルコード
while y!=0:
    x,y=y,x%y

ABC032 A - 高橋君と青木君の好きな数

解答例
a,b,n=(int(input()) for _ in range(3))
while n%a!=0 or n%b!=0:n+=1
print(n)

最大公約数

  • GCD:Greatest Common Divisor
サンプルコード
from functools import reduce
from fractions import gcd
x=[15,25,30]
print(reduce(gcd,x))
# 5

ABC109 C - Skip

解答例
from functools import reduce
from fractions import gcd
N,X=map(int,input().split())
x=[abs(X-int(i)) for i in input().split()]
print(reduce(gcd,x))

ABC118 C - Monsters Battle Royale

解答例
import functools,fractions
n=input()
a=list(map(int,input().split()))
print(functools.reduce(fractions.gcd,a))

最小公倍数

  • LCM:Least Common Multiple

ABC070 C - Multiple Clocks

解答例
from fractions import gcd
def lcm(a,b): return a*b//gcd(a,b)
N=int(input())
ans=1
for i in range(N):
    t=int(input())
    ans=lcm(ans,t)
print(ans)

ABC118 C - Monsters Battle Royale

解答例
import functools,fractions
n=input()
a=list(map(int,input().split()))
print(functools.reduce(fractions.gcd,a))

ABC032 A - 高橋君と青木君の好きな数

解答例
a,b,n=(int(input()) for _ in range(3))
while n%a!=0 or n%b!=0:n+=1
print(n)

DP

  • DP:Dynamic Programming(動的計画法)

動的計画法 - Wikipedia

ABC040 C - 柱柱柱柱柱

解答例
N=int(input())
A=list(map(int,input().split()))+[0]
dp=[0]*N
dp[1]=abs(A[1]-A[0])
for i in range(1,N-1):
    dp[i+1]=min(dp[i]+abs(A[i+1]-A[i]),dp[i-1]+abs(A[i+1]-A[i-1]))
print(dp[N-1])
  • 未解答

ABC011 C - 123引き算
ABC034 C - 経路

DFS

  • DFS:Depth First Search(深さ優先探索)

深さ優先探索 - Wikipedia

  • 未解答

ABC054 C - One-stroke Path

BFS

  • BFS:Breadth First Search(幅優先探索)

幅優先探索 - Wikipedia

ABC007 C - 幅優先探索

解答例
h,w=map(int,input().split())
sy,sx=map(int,input().split())
gy,gx=map(int,input().split())
grid=[list(input()) for x in range(h)]
grid[sy-1][sx-1]=0
loc=[[sy-1,sx-1]]
for k in range(1,h*w):
    next_loc=[]
    for y,x in loc:
        for i,j in ([1,0],[-1,0],[0,1],[0,-1]):
            if grid[y+i][x+j]=='.':
                grid[y+i][x+j]=k
                next_loc.append([y+i,x+j])
    loc=next_loc
    if [gy-1,gx-1] in loc:
        break
print(k)

UnionFind

素集合データ構造 - Wikipedia

ABC114 C - 755

解答例
N = int(input())
def dfs(s):
    if int(s)>N:
        return 0;
    ret = 1 if all(s.count(c) > 0 for c in "753") else 0
    for c in "753":
        ret += dfs(s+c)
    return ret
print(dfs("0"))
  • 未解答

ABC075 C - Bridge
ABC054 C - One-stroke Path
ABC015 C - 高橋くんのバグ探し

しゃくとり法

ABC032 C - 列

解答例
N,K=map(int,input().split())
S=[int(input()) for i in range(N)]
length=left=0
mul=1
if 0 in S:
    length=N
else:
    for right in range(N):
        mul*=S[right]
        if mul<=K:
            length=max(length,right-left+1)
        else:
            mul//=S[left]
            left+=1
print(length)
解答例(TLE)
N,K=map(int,input().split())
S=[int(input()) for i in range(N)]
length=0
if 0 in S:
    length=N
else:
    for i in range(N):
        for j in range(i+1,N):
            mul=1
            for k in range(i,j+1):
                mul*=S[k]
            if mul<=K:
                length=max(length,j-i+1)
print(length)

ABC038 C - 単調増加

解答例
N=int(input())
A=list(map(int,input().split()))
diff=0
ans=N
for i in range(N-1):
    if A[i]<A[i+1]:
        diff+=1
        ans+=diff
    else:
        diff=0
print(ans)

全探索

ABC045 C - たくさんの数式 / Many Formulas

解答例
S=input()
ans=0
for i in range(len(S)):
    for j in range(i+1):
        ans+=int(S[-(i+1)])*(10**j)*(2**(len(S)-1))//(2**min(i,j+1))
print(ans)
解答例
S=input()
ans=0
for i in range(2**(len(S)-1)):
    tmp=S[0]
    for j in range(len(S)-1):
        if i&(1<<j):tmp+="+"
        tmp+=S[j+1]
    ans+=eval(tmp)
print(ans)

ABC080 C - Shopping Street

解答例
N=int(input())
F=[int(input().replace(' ',''),2) for i in range(N)]
P=[list(map(int,input().split())) for i in range(N)]
print(max(sum([p[bin(f&i).count('1')] for f,p in zip(F,P)]) for i in range(1,2**10)))

ABC107 C - Candles

解答例
n,k=map(int,input().split())
x=sorted(list(map(int,input().split())))
print(min((min(abs(x[i])+abs(x[i+k-1]-x[i]),abs(x[i+k-1])+abs(x[i]-x[i+k-1]))) for i in range(n-k+1)))
解答例
n,k=map(int,input().split())
x=sorted(list(map(int,input().split())))
a=[]
for i in range(n-k+1):
    l=x[i]
    r=x[i+k-1]
    a.append(min(abs(l)+abs(r-l),abs(r)+abs(l-r)))
print(min(a))

ARC029 A - 高橋君とお肉

解答例
N=int(input())
T=sorted(int(input()) for i in range(N))[::-1]
x=y=0
for t in T:
    if x<y:x+=t
    else:y+=t
print(max(x,y))

ARC041 A - コインの反転

解答例
x,y=map(int,input().split())
k=int(input())
print(x+y-abs(k-y))

貪欲法

ABC011 C - 123引き算

解答例
N=int(input())
NG=[int(input()) for i in range(3)]
if N in NG:
    print("NO")
    exit()
for i in range(100):
    N-=3
    if N in NG:
        N+=1
        if N in NG:
            N+=1
            if N in NG:
                print("NO")
                exit()
print("YES" if N<=0 else "NO")

ABC048 C - Boxes and Candies

解答例
A=list(map(int,input().split()))+[0]
ans=0
for i in range(N):
    eated=max(0,A[i]+A[i-1]-x)
    ans+=eated
    A[i]-=eated
print(ans)
  • 未解答

ABC011 C - 123引き算

最大フロー

最大フロー問題 - Wikipedia

エラトステネスのふるい

エラトステネスの篩 - Wikipedia

  • 未解答

ABC084 D - 2017-like Number

ワーシャル–フロイド法

ワーシャル–フロイド法 - Wikipedia

  • 未解答

ABC016 C - 友達の友達

クラスカル法/プリム法

クラスカル法 - Wikipedia

プリム法 - Wikipedia

  • 未解答

ARC076 D - Built?

計算量観点

ソート

ABC004 C - 入れ替え

解答例
N=int(input())%30
X=[1,2,3,4,5,6]
for i in range(N):
    tmp=X[i%5+1]
    X[i%5+1]=X[i%5]
    X[i%5]=tmp
print(*X,sep="")
解答例(TLE)
N=int(input())
X=[1,2,3,4,5,6]
for i in range(N):
    tmp=X[i%5+1]
    X[i%5+1]=X[i%5]
    X[i%5]=tmp
print(*X,sep="")

つるかめ算

ABC006 C - スフィンクスのなぞなぞ

解答例
N,M=map(int,input().split())
if 2*N<=M<=4*N:
    y=M%2
    z=((M-3*y)-2*(N-y))//2
    x=N-y-z
    print(x,y,z)
else:
    print("-1 -1 -1")
解答例(TLE)
N,M=map(int,input().split())
for x in range(N+1):
    for y in range(N+1):
        z=N-x-y
        if 2*x+3*y+4*z==M and z>=0:
            print(x,y,z)
            exit()
print("-1 -1 -1")

いもす法

ABC017 C - ハイスコア

解答例
n,m=map(int,input().split())
imos=[0]*(m+1)
t=0
for i in range(n):
    l,r,s=map(int,input().split())
    imos[l-1]+=s
    imos[r]-=s
    t+=s
for i in range(m):
    imos[i+1]+=imos[i]
print(t-min(imos[:-1]))

ABC035 C - オセロ

解答例
N,Q=map(int,input().split())
O=[0]*(N+1)
for i in range(Q):
    l,r=map(int,input().split())
    O[l-1]+=1
    O[r]-=1
for i in range(N):
    if i>0:O[i]+=O[i-1]
    print(O[i]%2,end="")
print()
解答例(TLE)
N,Q=map(int,input().split())
O=[0]*N
for i in range(Q):
    l,r=map(int,input().split())
    for j in range(l,r+1):
        O[j-1]+=1
for i in range(N):
    if O[i]%2==0:
        O[i]=0
    else:
        O[i]=1
print(*O,sep="")

ABC014 C - AtColor

解答例
N=int(input())
n=10**6+1
x=[0]*(n+1)
for i in range(N):
    a,b=map(int,input().split())
    x[a]+=1
    x[b+1]-=1
for i in range(n):
    x[i+1]+=x[i]
print(max(x))

累積和

ABC067 C - Splitting Pile

解答例
N=int(input())
A=list(map(int,input().split()))
S=sum(A)
T=[0]*N
for i in range(N-1):
    T[i+1]=T[i]+A[i]
print(min(abs(S-2*T[i]) for i in range(1,N)))
解答例(TLE)
N=int(input())
A=list(map(int,input().split()))
print(min(abs(sum(A[:i])-sum(A[i:])) for i in range(1,N)))

ABC098 C - Attention

解答例
N=int(input())
S=input()
cnt=S.count("E")
m=cnt
for i in S:
    if i=="E":
        cnt-=1
    else:
        cnt+=1
    m=min(m,cnt)
print(m)

二分探索

ABC030 C - 飛行機乗り

解答例
import bisect
N,M=map(int,input().split())
X,Y=map(int,input().split())
A=list(map(int,input().split()))
B=list(map(int,input().split()))
ans=0
time=0
while time<=A[-1]:
    time=A[bisect.bisect_left(A,time)]+X
    if time<=B[-1]:
        time=B[bisect.bisect_left(B,time)]+Y
        ans+=1
    else:break
print(ans)

ABC084 C - Snuke Festival

解答例
import bisect
N=int(input())
A=sorted(list(map(int,input().split())))
B=sorted(list(map(int,input().split())))
C=sorted(list(map(int,input().split())))
print(sum(bisect.bisect_left(A,b)*(N-bisect.bisect_right(C,b)) for b in B))
解答例(TLE)
from collections import Counter
N=int(input())
A=Counter(input().split())
B=Counter(input().split())
C=Counter(input().split())
ans=0
for a_key,a_count in A.most_common():
    for b_key,b_count in B.most_common():
        for c_key,c_count in C.most_common():
            a_key,b_key,c_key=int(a_key),int(b_key),int(c_key)
            if a_key<b_key and b_key<c_key:
                ans+=a_count*b_count*c_count
print(ans)

中央値の算出

解答例
N=int(input())
X=list(map(int,input().split()))
S=sorted(X)
b=S[N//2]
a=S[(N//2)-1]
for i in X:
    print(b if i<b else a)
解答例
N=int(input())
X=list(map(int,input().split()))
s=[]
for i in range(N):
    s=sorted(X[:i]+X[i+1:])
    print(s[N//2-1])

条件式によるループ回数削減

ABC097 B - Exponential

解答例
x=int(input())
c=1
for b in range(1,x):
    for p in range(2,x):
        if b**p<=x:c=max(c,b**p)
        else:break # b**pがx以上は計算を省く
print(c)
解答例(TLE)
x=int(input())
c=1
for b in range(1,x):
    for p in range(2,x):
        if b**p<=x:c=max(c,b**p)
print(c)

集計から除算に変換

ABC048 B - Between a and b ...

解答例
a,b,x=map(int,input().split())
print(b//x-(a-1)//x)
解答例(TLE)
a,b,x=map(int,input().split())
print(sum(1 for i in range(a,b+1) if i%x==0))

処理中の剰余算(10*n+7)

ABC034 C - 経路

解答例
from math import factorial
W,H=map(int,input().split())
m=10**9+7
print(factorial(W+H-2)*pow(factorial(H-1)*factorial(W-1)%m,m-2,m)%m)

ABC065 C - Reconciled?

解答例
import math
N,M=map(int,input().split())
print(max(2-abs(N-M),0)*math.factorial(N)*math.factorial(M)%(10**9+7))

ABC006 B - トリボナッチ数列

解答例
a,b,c=0,0,1
for i in range(int(input())-1):
    a,b,c=b,c,(a+b+c)%10007
print(a)
解答例(TLE)
a,b,c=0,0,1
for i in range(int(input())-1):
    a,b,c=b,c,a+b+c
print(a%10007)

方程式

ABC085 C - Otoshidama

解答例
N,Y=map(int,input().split())
for x in range(N+1):
    for y in range(N-x+1):
        z=N-x-y
        if 0<=z<=2000 and 10000*x+5000*y+1000*z==Y:
            print(x,y,z)
            exit()
print(-1,-1,-1)

キュー

  • キュー:Queue

ABC077 C - pushpush

解答例
N=int(input())
A=list(map(int,input().split()))
print(*A[::-2],*A[N%2::2])
解答例(TLE)
N=int(input())
A=list(map(int,input().split()))
B=[]
for i in range(N):
    B.append(A[i])
    B=B[::-1]
print(*B)

部分数列の総和

ABC037 C - 総和

解答例
N,K=map(int,input().split())
A=list(map(int,input().split()))
print(sum(A[i]*min(i+1,K,N-i,N-K+1) for i in range(N)))
解答例(TLE)
N,K=map(int,input().split())
A=list(map(int,input().split()))
print(sum(sum(A[i:i+K]) for i in range(N-K+1)))

用語

AtCoder用語集

ハーシャッド数

  • 各位の数字和が元の数の約数にある自然数

ハーシャッド数 - Wikipedia

ABC080 B - Harshad Number

解答例
n=input()
print("No" if int(n)%sum(map(int,n)) else "Yes")

リュカ数

  • 初項(最初のリュカ数)を 2、次の項を 1 と定義し、それ以降の項は前の2つの項の和になっている数列
L_0 = 2, L_1 = 1
L_{n+2} = L_n + L_{n+1}

リュカ数 - Wikipedia

ABC079 B - Lucas Number

解答例
a,b=2,1
for i in range(int(input())):
    a,b=b,a+b
print(a)
解答例
n=int(input())
l=[2,1]
for i in range(2,n+3):
    l.append(l[i-2]+l[i-1])
print(l[n])

トリボナッチ数列

L_0 = 0, L_1 = 0, L_2 = 1
L_{n} = L_{n-1} + L_{n-2} + L_{n-3}

ABC006 B - トリボナッチ数列

解答例
a,b,c=0,0,1
for i in range(int(input())):
    a,b,c=b,c,a+b+c
print(a)

参考記事/サイト

実装観点

計算量観点

関連サイト

AtCoder情報

競技プログラミング情報

レート情報

緑色

水色

青色

黄色

コーディング規約

PEP 8 -- Style Guide for Python Code
[Pythonコーディング規約]PEP8を読み解く

マークダウン記法

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TelloPyでハマった事と対処方法

このページは?

  • トイドローンTelloをPythonで操作するライブラリTelloPy利用時に遭遇した問題(Issue)と対処方法を記載しています。
    https://github.com/hanyazou/TelloPy
  • 自分用メモなので環境によって事象/対処方法は異なる可能性があります。

前提事項

  • 検証PC
    • Windows 10 Professional
    • Visual Studio 2017, Python3.7 導入済み(非Anaconda環境)
  • 検証ドローン … 無印Tello

Issues

PyAV導入時に 'cl.exe' が見つからないエラー発生

事象

pip install av 実行が下記エラーにより失敗。

‘error: command 'cl.exe' failed: No such file or directory‘  

対応方法

  1. 下記URLを開く
    https://visualstudio.microsoft.com/ja/downloads/
  2. Tools for Visual Studio 2017 のセクションを展開し Build Tools Visual Studio 2017ダウンロードボタンをクリック。その後は指示に従ってインストール
  3. プログラムから VS 2017用 x64_x86 Cross Toolsコマンド プロンプト を起動してpip install av 実行
    ---> 本エラーは解消

PyAV導入時に 'avfilter.lib' が見つからないエラー発生

事象

pip install av 実行が下記エラーにより失敗

LINK : fatal error LNK1181: 入力ファイル 'avfilter.lib' を開けません。

対応方法

  1. 下記URLを開く
    https://ffmpeg.zeranoe.com/builds/
  2. 該当するArchitecture を選択し、LinkageのSharedDev をそれぞれ選択してDownload Buildを押下
  3. ダウンロードしたファイルを展開し任意のフォルダ(ここではC:\dev\ffmpeg)に配置
  4. VS 2017用 x64_x86 Cross Toolsコマンド プロンプト を開いて下記コマンドを実行後にpip install av 実行

    set INCLUDE=%INCLUDE%;c:\dev\ffmpeg\include
    set LIB=%LIB%;c:\dev\ffmpeg\lib
    set PATH=%PATH%;c:\dev\ffmpeg\bin
    

    ---> 本エラーは解消

PyAV導入時に アーキテクチャ競合エラー発生

事象

pip install av 実行が下記エラーにより失敗

python37.lib(python37.dll) : fatal error LNK1112: モジュールのコンピューターの種類 'x64' は対象コンピューターの種類 'x86' と競合しています。

対応方法

python3.7を64bit版から32bit版に入れ替えて本エラーは解消。(併せてffmpegも32bit版に入れ替え)
しかし、この対処方法で正しいのか不明…

サンプル実行時にffmpeg関連ライブラリが参照できないエラー

事象

py -m video_effect.py 実行時に下記エラーが発生。

C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\Lib\site-packages\tellopy\examples>py -m video_effect.py
Traceback (most recent call last):
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\lib\runpy.py", line 183, in _run_module_as_main
    mod_name, mod_spec, code = _get_module_details(mod_name, _Error)
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\lib\runpy.py", line 109, in _get_module_details
    __import__(pkg_name)
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\Lib\site-packages\tellopy\examples\video_effect.py", line 4, in <module>
    import av
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\lib\site-packages\av\__init__.py", line 9, in <module>
    from av._core import time_base, pyav_version as __version__
ImportError: DLL load failed: 指定されたモジュールが見つかりません。

対応方法

VS 2017用 x64_x86 Cross Toolsコマンド プロンプト を開いて下記コマンド実行でffmpegへの参照を追加することで解消

set INCLUDE=%INCLUDE%;c:\dev\ffmpeg\include
set LIB=%LIB%;c:\dev\ffmpeg\lib
set PATH=%PATH%;c:\dev\ffmpeg\bin

Videoを使うサンプル実行時にmplayerが見つからないエラー発生

事象

python -m tellopy.examples.joystick_and_video 実行時に下記エラー発生

Tello: 23:29:25.923: Error: video recv: [WinError 2] 指定されたファイルが見つかりません。
Traceback (most recent call last):
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\lib\site-packages\tellopy\_internal\tello.py", line 694, in __video_thread
    self.__publish(event=self.EVENT_VIDEO_FRAME, data=data[2:])
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\lib\site-packages\tellopy\_internal\tello.py", line 154, in __publish
    dispatcher.send(event, sender=self, **args)
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\lib\site-packages\tellopy\_internal\dispatcher.py", line 35, in send
    receiver(event=sig, **named)
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\lib\site-packages\tellopy\examples\joystick_and_video.py", line 191, in handler
    video_player = Popen(['mplayer', '-fps', '35', '-'], stdin=PIPE)
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\lib\subprocess.py", line 775, in __init__
    restore_signals, start_new_session)
  File "C:\Users\<ユーザー名>\AppData\Local\Programs\Python\Python37-32\lib\subprocess.py", line 1178, in _execute_child
    startupinfo)
FileNotFoundError: [WinError 2] 指定されたファイルが見つかりません。

対応方法

mplayer を導入する。

下記URLを開き mplayer-svn-38119-x86_64.7z をダウンロードして展開して mplayer.exe があるフォルダにパスを通す

http://mplayerwin.sourceforge.net/downloads.html

動いたところ

video_effect

joystick_and_video

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミング初心者の2月

この記事について

プログラミングとは何なのか1も知らなかった人間が新しい道を歩き始めた経緯を簡単に記録します。
(初の投稿で自分記録用として書いているので間違えているところや勘違いしているところも多いと思います。)

プログラミングを始めたきっかけ

私は大学の時工学部所属で勉強はしていましたが、プログラミングや機械、電子、物理などの工学系ではなくどちらかというとデザインが重視される建築設計をやっていました。その後、建築の模型製作の仕事を過ぎ物の表現、具現に興味を持つことになりました。建築模型の場合、最終の提出用ぐらいが実際多くの人に見られみんながものを短く感じさせることが可能かと思います。世界を動かすとか世界的に使われたいとかの大きいことではなくても使ってくれる人々から「お、こういう機能も使えるんだ。」とか「前より使いやすくなったな。」を言われることやりたいと思うところプログラミングを勉強させていただくいい機会が来て本格的にこちらの道に関しての勉強を始めました。

勉強の進み

この文章を書くのはちょうど私が勉強始めて1か月が経っている時点です。
パソコンを使ってないわけではありませんが、目に見えるように具現化されているのを主に使ったため、そのプログラムがどういう原理で動いているのかについてはあまり考えてみたことがありませんでした。

少しでも手をかけてみたことを整理してみると....

-Python 3.7
-HTML(css,bootstrap)
-MySQL
-Bottle

どれも基本の中での基本的なところですが、それぞれを組み合わせての使い方について勉強させていただきました。

最初は本やネットの講座、先生の説明でしたが、やっぱり基本的なことを勉強した後時間をかけて自分でtitleをつけて書いて動かしての添削が効果的だったと思います。先生と一緒に書いたり本のどおりやっているときに「わー!できた。面白い!」と言っても翌日、勉強したことの応用の課題が与えられたら「ああ、私なんかアホやな、、、」と落ち込むことがかなりあったからです。もちろん自分ができそうな機能ばかりいれてしまってそれ以上の勉強進行にはよくないのでないかと悩みましたが、まず自分ができることもなかったらこれ以上のことを聞いても実際使えないと思ったので新しいものを勉強させてもらいながら時間を取って自分なりのものを作っています。少しずづ新しいものをいれながら(もちろん、見た目的にも機能的にも人に見せれるものではありませんが...)楽しんでいます。

3月やってみたいこと

  1. 上記のプログラム以外にも最近JavaScriptを始めようとしています。
    書き方としてPythonと違いどちらにも慣れないのが一番心配ではありますが(フランス語とドイツ語を同時に勉強したときの感覚です。)、やっぱり単独で使うよりシナージ効果が出るのではないかと楽しみです。

  2. 今まで勉強してきたものを全部混ぜて自分なりで書いてみているものが2つあります。こちらをもうちょっと実用的に使えることができるようになったら知り合いに使わせてもらいたいです。

  3. 可能な状況が来るかどうかは知りませんが、私がこちらの勉強を始める前に模型製作作業の中でレーザカッターをつかったり3D模型を作ったりAutoCADで設計図を書いたりすることが多かったです。これを使ってラズベリーパイのケースだったりこういう回路などのケースも作ってみたいと思います!

ETC.

始めったばかりものの記事を読んでいただきありがとうございます。
新しい道へと挑戦するところですが、楽しみながら難しいところも乗り越えていきたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonでスクレイピング ①BeautifulSoup

はじめに

今回が初投稿になるので、至らない部分も多いかと思いますがご容赦ください。間違いなどありましたらご指導いただけると幸いです。

環境

macOS Mojave 10.14
python 3.6.4

準備

BeautifulSoupとrequestsをインストール

$ pip install beautifulsoup4
$ pip install requests
  • BeautifulSoup4
    HTMLやXMLを解析してデータを取り出すためのライブラリ

  • requests
    Webブラウザの代わりにHTTPでデータの送受信を行う

Webページの情報を取得

まず、requestsを使ってWebページの情報を取得する。
今回は例として、livedoorNEWSのランキングの情報を取得する。
get関数は、取得したいURLを指定するとその情報を格納したResponseオブジェクトを生成して返す。

import requests

response = requests.get('http://news.livedoor.com/ranking/')

Webページから要素を抜き出す

BeautifulSoup4を使ってHTMLを構文解析してタグなどの任意の要素を取得する。

from bs4 import BeautifulSoup

soup = BeautifulSoup(response.text, 'html.parser')

要素を見つけるには以下のようにする。

soup.a  # 先頭のa要素を一つ取得
soup.find('a')  # soup.aと同じ
soup.find_all('a')  # 全てのa要素を取り出す。リストのように扱える。
soup.find('div', id='main')  # divタグでidがmainのものを取得する
soup.a.get('href')  # href属性を取得する
soup.a.text  # aタグの中身を取得する

実践

プログラムを書き始める前に、HTMLの構造を確認することが必要。ここでは、ニュースのタイトル・日時・URLを取得してみる。
Chrmoeの検証機能を使うとどのタグの中に欲しい情報があるのか簡単に分かる。Chromeの検証機能についてはまた詳しく書こうと思います。

news.py
# -*- coding: utf-8 -*-

import requests
from bs4 import BeautifulSoup
import pandas as pd

response = requests.get('http://news.livedoor.com/ranking/')
soup = BeautifulSoup(response.text, 'html.parser')
newslist = soup.find('div', class_='mainBody')
tags = newslist.find_all('li')

articles = []
for tag in tags:
    url = tag.a.get('href')
    title = tag.a.h3.text
    time = tag.time.text

    article = {
        'title': title,
        'url': url,
        'datetime': time
    }

    articles.append(article)

df = pd.DataFrame(articles)  # 辞書をDataFrameに変換
print(df)
df.to_csv('news.csv')

おわりに

これからは学んだことをきちんと残していきたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GridSearchCVの評価指標にユーザ定義関数を使用する方法

はじめに

関連の記事が少なく、公式の説明も自分には分かり辛かったので書いてみました。
公式: https://scikit-learn.org/stable/modules/model_evaluation.html#scoring

手順概要

  1. ユーザ定義関数を定義する。
  2. sklearn.metrics.scorer.make_scorerにユーザ定義関数を渡してスコアラーを生成する(評価関数として使えるようにする)。
  3. 2.のmake_scorerをGridSearchCVのパラメータ「scoring」に設定する。

(ユーザ定義関数の内容に関して、今回は私のコードをそのまま貼りましたが、当然個々に寄ると思うので本記事のユーザ定義関数の内容を熟読してもあまり参考にはならないと思います。上記2点を満たしていれば問題ないです。)

ユーザ定義関数に関する注意点

下記2点を満たすように定義・実装すること。

  1. y_test(正解データ)とy_pred(推論結果データ)を引数として渡すことができる。
  2. 戻り値としてLoss(もしくは評価値)を返す。

make_scorerの設定に関する注意点

make_scorerのパラメータ「greater_is_better」の設定

  • ユーザ定義関数の戻り値を評価値にする場合: True
  • ユーザ定義関数の戻り値をLossにする場合: False

実装

「手順概要」の1.

ユーザ定義関数
def calc_score(y_train: np.array, y_pred: np.array):

  threshold = 1
  ignore = 10

  # 比較結果格納用配列の作成
  flg = np.zeros((y_train.shape[0],1))

  y_train = y_train.reshape([y_train.shape[0], 1])
  y_pred = y_pred.reshape([y_train.shape[0], 1])

  # 正解値と予測値の差分データを作成
  y_diff = y_train - y_pred

  for cnt_row in range(y_diff.shape[0]-DIFF):
      # 差分データの絶対値が閾値を超えていなければTrue
      if abs(y_diff[cnt_row]) < threshold:
        flg[cnt_row] = True
      else:
        flg[cnt_row] = False

  # 正解率を計算
  cnt_true = 0
  for cnt_row in range(flg.shape[0]):
    if flg[cnt_row] == 1:
      cnt_true += 1
  score = cnt_true / flg.shape[0]

  return score
main()
...

# 例
params = {'hidden_layer_sizes': [(100,), (100, 10), (100, 100, 10), (100, 100, 100, 10), (100, 100, 100, 100, 10),  (100, 100, 100, 100, 100, 10)],
             'max_iter': [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000], 
             'learning_rate_init': [0.001, 0.0001, 0.00001], 
             'early_stopping': [True, False], 
             'tol': [0.0001, 0.00001], 
             'batch_size': [100, 200, 300], 
             'verbose': [True], 
             'random_state': [42]}

# 例
mlpr = MLPRegressor()

from sklearn.metrics.scorer import make_scorer
# 「手順概要」の2.
my_scorer = make_scorer(calc_score, greater_is_better=True)
# 「手順概要」の3.
gs = GridSearchCV(mlpr, param_grid=params, cv=10, scoring=my_scorer)

...
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Deep LearningでバーチャルYouTuber作ってみた

概要

  • GANを使ってVTuber作ってみた
  • 人間と猫のモデルを作った
  • リアルタイムで動物のモデルを動かす試みはまだあまりないと思う

※注意
背景では、バーチャルYouTuberについて熱く語っているので、興味のない方は飛ばして下さい。
GANについて軽く技術の紹介をしていますが、すでにご存じの方はDeep Leaning based Virtual YouTuberまで飛んで下さい。

背景

バーチャルYouTuberをご存知でしょうか?バーチャルYouTuberとは、モーションキャプチャを用いてキャラクターモデルの操作を行い、YouTubeやMirrativ等のプラットフォームで配信を行う、言わばYouTuberをキャラクターにしたエンターテイメントの1つです。

バーチャルYouTuberランキングを運営する株式会社ユーザーローカル様の調査によれば1 、2018/1/31時点で活動しているのは181名でしたが、同年12月には6000人以上に増加、そして2019/2/21には7000人を突破したとの報告もあり2、バーチャルYouTuber市場が今後も拡大していくことが予想されます。かく言う私も沼にはまったファンの1人で、最推しの樋口楓さんとニコニコ町会議でお話しをしたり、18時間かけて東北から大阪までライブを見に行く程のハマり具合です。

これだけの人数が活動している中で、「YouTubeの収益化」をクリアするのは大きな問題の1つだと私は考えています。様々な基準がありますが、大きく分けて①チャンネル登録者数1000人以上、②過去12ヶ月の総再生時間が4000時間以上という2つを満たす必要があります。多くの方が活動し、企業も参戦する中、この基準を満たすのは容易ではありません。

そこで、これまでキャラクターベースのモデルではなく、GANを使った「Deep Learning系Vtuber」という新しい形態でのモデルを提供することができれば、話題性を生み、チャンネル登録者数増加に繋げられるのではないかと考えました。以降、大学の講義のPBLとして取り組んだことについて説明をしていきたいと思います。

(という、背景や問題提起は後付です。ただ単純に、GANでVtuberできんじゃね?と思ったのが始まりです。)

GAN

機械学習を用いて作るモデルは、Discriminative modelとGenerative modelという2つに分類されます。それぞれの詳細な説明は省略しますが、今回使用するGAN3はGenerative modelに属する手法です。(一部構造にDiscriminative modelを使用していますが)

下図がGANのネットワーク構造です。

GANはDiscriminatorとGeneratorと呼ばれる2つのネットワークから構成されます。それぞれの目的は以下のとおりです。

Network 目的
Generator 画像の生成
Discriminator 本物の画像と偽物の画像の識別

minimax gameを想像して頂ければ分かりやすいかもしれませんが、GANは2つのネットワークを競わせる形で学習を行っていきます。Generatorは本物に近い画像を生成できるように(Discriminatorを欺けるように)学習をします。Discriminatorでは生成された画像と本物の画像を正しく識別できるように学習をしていきます。これを繰り返し、最終的にDiscriminatorで識別することができなくなるまで学習を行ったGeneratorを用いてFake imagesを作成するのがGANの目的です。

数式等や詳細なアルゴリズムはこちらを見て頂ければ分かりやすいかと思います。
はじめてのGAN
Pokemon_GAN

Pix2Pix

今回使用した手法がPix2Pix4と呼ばれる、GANの拡張手法です。

Pix2Pixではある入力をされた画像を、本物っぽい画像に変換することが可能です。例えば上図の場合、カバンの線画を入力として与えた場合、それに着色を行い本物のカバンのような画像を出力します。

GANと異なる点としては、2つの画像のペアを用いて学習するということです。例として、線画のキティちゃんの着色を考えます。下図のように、線画をGeneratorに入力し、出力として色付きキティちゃんを得るのが目的です。

Discriminatorでは、「入力 + 正しい色のキティちゃん」と「入力 + 生成された色付きキティちゃん」の識別を行います。

ペア画像に対しこれらを繰り返し学習していくことで、片方の入力を得た際に、もう一方の画像を出力するのがPix2Pixです。

Deep Leaning based Virtual YouTuber

ここからが本題です。今回のプロジェクトでは、先に紹介したPix2Pixを用いています。「Face landmark + 実際の画像」をペアとして学習を行い、作成したモデルに、リアルタイムで取得されたlandmarkを入力し、あたかもベースとなった人間が動いているかのような出力をすることで、Vtuberのような形式を目指します。

今回は以下のリポジトリをForkし開発を行いました。Dat Tran様に感謝致します。
Thank you, datitran (Dat Tran) ! I really appreciate it.
datitran/face2face-demo

とりあえず色々調整して学習して動かしてみた

結果がこちらです。
mel.gif

左側の線画がリアルタイムで取得した私の動きで、右側が出力となっています。
(本当は一番左に私の顔が写っているのですが、恥ずかしいのでカットしています。)

結構ちゃんと動いてます。
データを変更し学習しても、そこそこの物が出来上がりました。WebカメラとGPUだけでここまでできるなんて凄いなーというのが私の感想です。他人の顔を動かすような研究はたくさん行われていそうなので、こんなものかと思われる方もいるかもしれません。実際、世界初のAIニュースキャスターが中国で誕生するなど、GANの精度は日に日に向上しています。


法律的な問題点

GANを使う以上、元となる人物のデータが必要となります。先ほどの例では、ドイツのメルケル首相を使用しました。また、遊びではじめしゃちょーのモデルも作成しました。ここで、問題になってくるのが法律的な問題です。

実は日本には著作権法には47条の7という、世界的に見ても珍しい条文があります。簡単に言えば「情報解析が目的であれば、著作権者の承諾なしに自由に使用ができる」といった内容です。しかも、非営利目的の利用に限定されていません。我々AI開発者・研究者にとっては天国のような内容です。

しかし、情報解析に機械学習が含まれているのかどうかといった解釈や、他の法律(他国含む)等を考慮すると怪しい気がしてきます。そこで、「動物のデータなら大丈夫ではないか?」と考えました。以降は動物のデータを用いた取り組みについてご紹介していきます。

Animal Model

前処理

人間でも動物でも、Pix2Pixを使う以上ペアの画像を作成する必要があります。前処理の流れは大まかに、このようになっています。

  1. データ(動画)入手
  2. フレーム分解
  3. 分解した画像からLandmarkを取得
  4. フレーム分解した画像とLandmarkをペアとして学習

今回、最も苦戦したのが「3. 分解した画像からLandmarkを取得」です。人間のlandmark検出であれば、OpenCVやdlibといったライブラリを使えば簡単かつ、高精度に検出することが可能です。しかし、動物のlandmark検出となると話しは変わってきます。

Object detectionでは「どこに、何の動物がいるか」の検出は可能です。しかし、それぞれの動物の顔の特徴までは検出できません。調べた限り、動物の顔の特徴抽出器も多くは存在しません。(需要ないだろうし)

Landmark detectorを作成するには、顔がもつ特徴点を画像ごとに記録し学習を行う必要があります。人間であれば、画像のように60個以上ある特徴点の座標を1枚ごとに記録する必要があります。学習には数千枚を超えるデータが必要であるため、これを1から作るのは現実的ではありません。

猫の特徴抽出

そこで、頑張って探し辿り着いたpycatfdを一部改変し、使用することにしました。
marando/pycatfd

抽出された特徴点の座標をもとに、以下のような画像を生成するプログラムを作成しました。

pycatfdですが、猫が少しでも横を向くと検出ができなくなってしまう(または、誤検出がおこる)という問題があります。また、そもそもの検出精度も悪く化物のようなデータになってしまいます。そこで、取得した特徴点から、様々な処理を行ったデータを用意し、実験を行いました。行った処理内容は以下の通りです。

データ(動画) 処理内容
①某CMに登場する猫 無処理
②某CMに登場する猫 データ選定
③某CMに登場する猫 耳なし
④某CMに登場する猫 擬似耳
⑤YouTubeに投稿された猫 データ拡張 反転
⑥YouTubeに投稿された猫 データ拡張 反転 + 縮尺変更
  • ②服を着ていたり、帽子を被っていたりする画像を削除
  • ③耳の検出が不安定なため、耳がないlandmark画像を作成
  • ④耳の検出が不安定なため、座標を指定して擬似的な耳を作成
  • ⑤⑥使いやすそうなデータが見つかったため、データを変更
  • ⑤データ数が少ないため、水平方向に反転した画像を追加
  • ⑥反転に加え、縮尺を変更することでノイズに強くなるのではないかと予想

色んな試行錯誤をした結果

最も悪かった結果 (前処理①)
badneko.gif

最も良かった結果 (前処理⑤)
goodneko.gif

考察

遠くから見れば猫っぽいかな... くらいの精度でした。
原因としては大きく分けて、以下の2つだと考えています。

  1. 特徴の違い
    猫の特徴を学習したモデルに、人間の特徴を入力しているため、精度に影響したと考えられれます。今回は人間の目と顔の輪郭のみを入力としました。(他の特徴も入力すると精度が下がったため)そのため、特徴の変換器みたいなものを作成する必要がありそうです。

  2. データ
    猫の特徴抽出の説明において、検出精度が低いと記述しました。下の画像の耳が垂れている猫のように、ありえない画像を学習に使ってしまったのも原因と考えられます。

終わりに

精度向上の余地はありそうですが、一旦開発はここで終了としています。実は開発メンバーの中にGANを専門に勉強、研究をしている人間はいませんでした。そのため、感想やコメント、アドバイスを頂ければ幸いです。最後まで読んでいただきありがとうございました。

Github

整理中(2019/02/26)
gojirokuji/dtuber


  1. 株式会社ユーザーローカル, バーチャルYouTuber、本日6000人を突破(ユーザーローカル調べ), https://www.userlocal.jp/news/20181219vs/ 

  2. 株式会社ユーザーローカル, バーチャルYouTuber、本日7000人を突破(ユーザーローカル調べ), https://www.userlocal.jp/news/20190221vn/ 

  3. Ian J. Goodfellow, Jean Pouget-Abadie, Mehdi Mirza, Bing Xu, David Warde-Farley, Sherjil Ozair, Aaron Courville, Yoshua Bengio, Generative Adversarial Networks, arXiv:1406.2661, https://arxiv.org/abs/1406.2661 

  4. Phillip Isola, Jun-Yan Zhu, Tinghui Zhou, Alexei A. Efros, Image-to-Image Translation with Conditional Adversarial Networks, arXiv:1611.07004, https://arxiv.org/abs/1611.07004 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nonce2vecで少数データからWord2vecを更新する

nonce2vec1とは、少数のデータを用いて訓練済みWord2vecに新語を加えるなどする手法です。ここでは、その使い方を見てみます。

概要

nonce2vecは3つのフェーズを取ります。

  1. 事前訓練済みWord2vec(skip-gram)の読み込み。
  2. 訓練対象文のボキャブラリー構築。
  3. パラメータを設定し、訓練対象文で対象語を訓練。

訓練対象文は、例えば訓練したい語の「語の定義」などを使います。要するに、新語を少数の定義文から更新する手法です。

インストール

pip install nonce2vec

実行例

from nonce2vec.models.nonce2vec import Nonce2Vec, Nonce2VecTrainables, Nonce2VecVocab
import MeCab
from pprint import pprint
import numpy as np
import copy

if __name__ == "__main__":
    #MODELS
    model = Nonce2Vec.load("word2vec.model")
    model.vocabulary = Nonce2VecVocab.load(model.vocabulary)
    model.trainables = Nonce2VecTrainables.load(model.trainables)
    tagger = MeCab.Tagger("-Owakati -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd/")

    nonces = []
    sentences = []
    #INPUTS
    with open("10.test") as f:
        for line in f:
            tmp = line.split(":::")
            nonce = tmp[0]
            sentence = tagger.parse(tmp[1]).format(nonce).strip().split()
            nonces.append(nonce)
            sentences.append(sentence)

    #PARAMS
    alpha = 1
    sample = 10000
    neg = 3
    window = 15
    iter = 1
    lambda_den = 70
    sample_decay = 1.9
    window_decay = 5

    #PARAM SETTING
    def model_init(m, sentence, nonce, *ps):
        model.alpha=float(ps[0])
        model.sample=int(ps[1])
        model.sample_decay=float(ps[2])
        model.iter=int(ps[3])
        model.negative=int(ps[4])
        model.neg_labels = []
        if model.negative > 0:
            model.neg_labels = np.zeros(model.negative+1)
            model.neg_labels[0] = 1.
        model.vocabulary.nonce=nonce
        model.window=int(ps[5])
        model.window_decay=int(ps[6])
        model.lambda_den=float(ps[7])
        #model.min_count=int(1)
        print(sentence)
        model.build_vocab(sentences=[sentence], update=True)
        model.train([sentence], total_examples=model.corpus_count, epochs=model.iter)
        return model

    #DOIT
    import json
    out = {}
    for nonce, sentence in zip(nonces, sentences):
        model = model_init(model, sentence, nonce, *(alpha, sample, sample_decay, iter, neg, window, window_decay, lambda_den))
        tmp = model.most_similar(nonce, topn=30)
        out[nonce] = tmp
    with open("out.json","w") as f:
        f.write(json.dumps(out, indent=4, sort_keys=True, ensure_ascii=False))

実行例のデータ

11次元超重力理論:::{} とは、一般相対論を超対称化した理論、言い方を変えれば局所超対称性の理論である。量子化した際は、単なる一般相対論より紫外発散が弱くなるため、量子重力理論の文脈において1980年代初頭に精力的に研究された。超対称性のゲージ理論と考えることもできる。対応するゲージ場がグラヴィティーノである。
エンティティリンキング:::{} とは、自然言語処理において、テキスト内の表現を知識ベース内の識別子として認識するタスクである。
カバートアグレッション:::{} とは、評判を傷つけたり、関係を操作することで人に害を及ぼす行為である。
自己顕示バイアス:::{} とは、実験参加者が自分を良く見せようとすることによって生じるバイアスのこと。
INTJ:::{} とは、MBTIの診断結果の1つで、内向的・直感的・思考的・判断的な性格タイ
プのこと。
サイハテ村:::{} とは、熊本の宇土半島にあるエコビレッジ。
オブジェクト図:::{} とは、クラス図などで表現されたクラス構成や相互関係に対して、それをインスタンス化したレベルで表現したUMLの図。
レプティリアン:::{} とは、陰謀論の一つで、地球に隠れて生息するとされる宇宙人の一種。爬虫類に属する。
Metasploit:::{} とは、サイバーセキュリティのツールで、ペネトレーションテストを行うためのフレームワークである。
幾何学的ラングランズ予想:::{} とは、ラングランズプログラムを幾何学的に定式化しなおして、単に既約表現だけを考える以上のものを関連付けようとして生じたものである。単純な場合だと、代数曲線のエタール基本群の l-進表現を、その曲線上のベクトル束の
モジュライスタック上で定義された l-進層の導来圏の対象に関連付ける。

実行結果の一部

{
    "11次元超重力理論": [
        [
            "マイクロ磁気学",
            0.780556857585907
        ],
        [
            "ピカール・レフシェッツ",
            0.7795853614807129
        ],
        [
            "成りたつ",
            0.7746739387512207
        ],
        [
            "オイラー=ハイゼンベルク・ラグランジアン",
            0.7744903564453125
        ],
        [
            "散乱問題",
            0.7708392143249512
        ],
        .
        .
        .

おわりに

このように、少数のデータから、事前訓練済みWord2vecにはない語を学習することができました。

ただし、build_vocabでは、合計ベクトルを新語のベクトルとして採用しているため、新語同士が近くなってしまう問題があります。

補足: gensimのskip-gramモデル

skip-gramモデルを使うには、sg=1を指定します。

import logging
from gensim.models import word2vec
import multiprocessing

if __name__ == "__main__":
    logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
    sentences = word2vec.Text8Corpus('./wiki_fixed.text8')
    model = word2vec.Word2Vec(sentences, size=200, workers=multiprocessing.cpu_count(), sg=1)
    model.save("word2vec.model")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonで部分的なコードの実行時間を測る

Pythonで部分的なコードの実行時間を知りたい時のtipsです。
すぐに忘れるので、メモを兼ねて共有します。

実装

まず、contextmanagerでデコレーターを作っておきます。

from contextlib import contextmanager
import time

@contextmanager
def timer(title):
    start = time.time()
    yield
    print("{} - done in {:.3f}s".format(title, time.time() - start))

使い方

with timer('hello world'):
    # 処理

関数内に関数を定義して、ラッパーを用いることでも実装できるのですが、
contextlibのcontextmanagerを使うことでより簡潔になります。

デコレータ内の「yield」でwithステートメント内の処理が実行されて、時間を計測できるようになっています。
部分的なコードの実行時間を測りたい時に便利なので、使ってみてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

python packaging の editable と develop mode のこと

python パッケージのツールはdistutils, setuptools, pip, pipenv といろいろあって、用語が混乱してきたのでまとめてみた。

easy_install (setuptools)

  • easy_install -e の editable mode はバージョン解決をしてダウンロードするところまで。
  • editable mode での展開ディレクトリは明示的に指定しないといけない。
  • setup.py develop で symlink を使った install が行われる (egg-link)

pip

  • pip install -e の editable mode は setuptools の develop mode に相当
  • git (VCS) 管理の url からもインストールできる(pip install git+https://.... みたいな)
  • --src ディレクトリはデフォルトの位置が用意されている

pipenv

  • pipenv install -e の editable mode は egg-link でインストールを行う
  • editable として展開されている場所は pip 同様規定値が使われる
  • --dev は [dev-packages] に区分けされて Pipfile に入る。egg-link とは関係ない。
  • --dev は他の環境でインストールするときに効く。pipenv install --dev で packages と dev-packages の両方が入る。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ペントミノ「のような」タイル敷き詰め問題を量子コンピュータで解いてみる

はじめに

少し前に、とある東工大の先生から、「ペントミノってアニーリングマシンで解けるのかな?」と聞かれて「やってみます!」と答えてしまいましたので、なんとか解いてみたいと思いました。
ペントミノとは(https://ja.wikipedia.org/wiki/%E3%83%9A%E3%83%B3%E3%83%88%E3%83%9F%E3%83%8E

ただし、ペントミノは5個の正方形を組み合わせたピースが12個あり、数が多くて大変なので、まずは問題を小さくして、3×3のタイルを敷き詰める問題を考えてみます。

問題

下図左のような正方形3つでできたタイル3つを、下図右のような3×3の盤面にピッタリ敷き詰める問題を考えてみます。
左からピースをp1, p2, p3とします。本物のペントミノでは、同じ形のピースはないのですが、3×3への敷き詰めを考えてここでは許容します。
p1.PNG

考え方

まずは、ピースp1の盤面への置き方を考えてみます。下図のように6通りあります。この置き方を、それぞれ「q0, q1, q2, q3, q4, q5」とします。
p4.PNG

さらに、ピースp2, p3についても考えて見ます。
p5.PNG

立式

次に、アニーリングマシンで解けるように立式してみます。

量子ビットが表すものを決める

ピースp1は、q0~q5のどれかの置き方になるはずですので、置き方q0になるときに、q0=1 、q0にならない時 q0=0 とします。
同様にして、q1になるとき、q1=1, ならないときq1=0・・・、ピースp2についても、置き方q6になるときq6=1, ならないときq6=0・・・とします。

各ピースについて、置き方の中から1つだけ選ばれるようにする

まずは、p1の置き方は「q0, q1, q2, q3, q4, q5」の6個がありますが、その中から1つだけがえらばれなければなりません。
そのため、この6個の量子ビットの中から1つだけが選ばれる、という条件を最小値問題の式にしてみます。以下のようになります。

\{1-(q0+q1+q2+q3+q4+q5)\}^2

これで、q0~q5の中で、1のとき最小値の0、それ以外は1以上の値になります。
同様にして、ピースp2, p3についても立式すると

\{1-(q6+q7+q8+q9+q10+q11+q12+q13+q14+q15+q16+q17+q18+q19+q20+q21)\}^2
\{1-(q22+q23+q24+q25+q26+q27+q28+q29+q30+q31+q32+q33+q34+q35+q36+q37)\}^2

盤面の各位置(b1, b2, b3・・・)に置くピースが重ならないようにする

次に、盤面に注目します。
盤面の「b1」の位置に置かれる可能性のあるピースの配置は、図から「q0,q3,q6,q14,q16,q22,q30,q32」であることが分かります。ピースは重なってもだめだし、どれか1つは配置されていないとダメなので、b1上に来る可能性のあるピースの中から、1つだけを選ぶ必要があります。先ほどと同様に立式すると、

\{1-(q0+q3+q6+q14+q16+q22+q30+q32)\}^2

とすれれば、盤面の位置b1に置かれるピースの配置が1つのみに絞られます。
盤面の位置b2, b3, b4, b5・・・についても同様に立式します。

式全体

ちょっと面倒ですが、全部のピース・盤面の位置についての条件を列挙して足し合わせると、以下の式になります。

\{1-(q0+q1+q2+q3+q4+q5)\}^2 \\
+\{1-(q6+q7+q8+q9+q10+q11+q12+q13+q14+q15+q16+q17+q18+q19+q20+q21)\}^2 \\
+\{1-(q22+q23+q24+q25+q26+q27+q28+q29+q30+q31+q32+q33+q34+q35+q36+q37)\}^2 \\
+\{1-(q0+q3+q6+q14+q16+q22+q30+q32)\}^2 \\
+\{1-(q1+q3+q7+q8+q14+q15+q16+q17+q23+q24+q30+q31+q32+q33)\}^2 \\
+\{1-(q2+q3+q9+q15+q17+q25+q31+q33)\}^2 \\
+\{1-(q0+q4+q6+q8+q10+q16+q18+q20+q22+q24+q26+q32+q34+q36)\}^2 \\
+\{1-(q1+q4+q6+q7+q8+q9+q11+q12+q14+q17+q18+q19+q20+q21+q22+q23+q24+q25+q27+q28+q30+q33+q34+q35+q36+q37)\}^2 \\
+\{1-(q2+q4+q7+q9+q13+q15+q19+q21+q23+q25+q29+q31+q35+q37)\}^2 \\
+\{1-(q0+q5+q10+q12+q20+q26+q28+q36)\}^2 \\
+\{1-(q1+q5+q10+q11+q12+q13+q18+q21+q26+q27+q28+q29+q34+q37)\}^2 \\
+\{1-(q2+q5+q11+q13+q19+q27+q29+q35)\}^2

シミュレータblueqatで解いてみる

式はできたので、シミュレータblueqatで解いてみます。コードは以下の通り。

a = opt.opt()
a = opt.opt()
a.qubo = opt.optm("(1-(q0+q1+q2+q3+q4+q5))^2 \
    +(1-(q6+q7+q8+q9+q10+q11+q12+q13+q14+q15+q16+q17+q18+q19+q20+q21))^2 \
    +(1-(q22+q23+q24+q25+q26+q27+q28+q29+q30+q31+q32+q33+q34+q35+q36+q37))^2 \
    +(1-(q0+q3+q6+q14+q16+q22+q30+q32))^2 \
    +(1-(q1+q3+q7+q8+q14+q15+q16+q17+q23+q24+q30+q31+q32+q33))^2 \
    +(1-(q2+q3+q9+q15+q17+q25+q31+q33))^2 \
    +(1-(q0+q4+q6+q8+q10+q16+q18+q20+q22+q24+q26+q32+q34+q36))^2 \
    +(1-(q1+q4+q6+q7+q8+q9+q11+q12+q14+q17+q18+q19+q20+q21+q22+q23+q24+q25+q27+q28+q30+q33+q34+q35+q36+q37))^2 \
    +(1-(q2+q4+q7+q9+q13+q15+q19+q21+q23+q25+q29+q31+q35+q37))^2 \
    +(1-(q0+q5+q10+q12+q20+q26+q28+q36))^2 \
    +(1-(q1+q5+q10+q11+q12+q13+q18+q21+q26+q27+q28+q29+q34+q37))^2 \
    +(1-(q2+q5+q11+q13+q19+q27+q29+q35))^2 "
    ,38)
res = a.sa()
print(res)
print(np.where(np.array(res)==1)[0])

結果

以下のような結果が得られました

[0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[ 5  6 31]

q5, q6, q31が選ばれていますので、組み合わせてみると・・・
q7.PNG
このように、ちゃんと敷き詰めできています!

何回か実行すると、下図のようないくつかの結果が得られました。いずれも敷き詰めができました。
p8.PNG

まとめ

3×3のタイルの敷き詰めはできました。
ペントミノの場合、ピースも12に増え、さらに「裏返す」と形が異なるピースもあることから置き方が一気に増えますが、「1つのピースの置き方」については古典で十分洗い出し可能だと思いますので、古典のプログラミングで立式はできそうです。量子ビット数が多くなるので、イジングで解けるかどうか分かりませんが、やってみたいと思います。

利用したシミュレータblueqatは以下から利用できます。
https://github.com/Blueqat/Blueqat

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

特異値分解を詳しく解説

はじめに

特異値分解は機械学習ではよく使われるテクニックだが、大学の教養過程で使うような線形代数の教科書には載っていなかったりする。

書店で色々探した結果、こちらの本に分かりやすい解説があり、理解が深まったのでまとめておく。

線形代数セミナー: 射影,特異値分解,一般逆行列 金谷 健一 (著)

今回は特異値分解の解説のみで、具体的な活用法はまた別の記事に書く(予定)。

定義

${\rm rank}(A)=r$ の $m \times n$ 行列 $A$ を考える。 ただし、$r < m < n$とする。
$\rm rank$って何?という方はあまり気にしなくても大丈夫ですが、気になる方はこちらの記事を参照。
このとき、$A$の特異値分解は下記のように表される。

$$A = U \Gamma V^T$$

ここで、$U, V$は直交行列であり、$\Gamma$は対角行列である。$\Gamma$の対角成分$\sigma_1,..., \sigma_r$が行列$A$の特異値と呼ばれる。特異値は0より大きい値である(0も特異値とする場合もある)。

$U, V$の列ベクトルをそれぞれ左特異ベクトル、右特異ベクトルと呼ぶ。$U, V$がそれぞれ$\Gamma$の左、右に来るためだと覚えておけばよい。

特異ベクトルの定義は下記のようにも書ける。固有値・固有ベクトルの定義($A \boldsymbol v = \lambda \boldsymbol v$)に似ているが、左辺と右辺に含まれるベクトルがそれぞれ $\boldsymbol u, \boldsymbol v$ と異なるベクトルになっていることに注意。

A \boldsymbol v = \sigma \boldsymbol u \\
A^T \boldsymbol u = \sigma \boldsymbol v

ここで、これらの式にそれぞれ、$A^T, A$を左からかけると、

A^T A \boldsymbol v = \sigma  A^T \boldsymbol u = \sigma^2 \boldsymbol v \\
AA^T \boldsymbol u = \sigma A \boldsymbol v = \sigma^2 \boldsymbol u

上式の最左辺と最右辺を比べると、前述した固有ベクトルの定義と同じ形になっている。
よって、$\boldsymbol u, \boldsymbol v$ はそれぞれ、$AA^T, A^T A$ の固有ベクトルであり、固有値はいずれも$\sigma^2$となる。

つまり、

(行列$A$の特異値) $^2=$ (行列 $AA^T, A^TA$ の固有値)

ということが言える。(なぜか中央寄せにならない??)[error]()

特異値分解のイメージとしては、対称行列(行と列の数が等しい行列)で定義される固有値を、一般の行列に拡張したものだと考えると良さそう。実際、対称行列の場合は固有値と特異値は一致する。

表記法

特異値分解の表記方法はいくつかあって、自分はちょっと混乱した。

まず、0を特異値に含めて、$\Gamma$を $m \times m$ の行列とする場合もある(下図(2))。ただし、 $\boldsymbol u, \boldsymbol v$ は特異値0に対応する左特異ベクトル、右特異ベクトルを並べた行列である。表記(1)から拡張されたグレーの部分は、結局かけ合わせて0になるので、実質的な影響はない。

また、$\Gamma$を対角行列ではなく、$m \times n$の行列とした表記もある(下図(3))。これは、$\Gamma$を 零行列でさらに拡張して$m \times n$に、$V$も$n \times n$に拡張したものだと考えれば良い。やはり、グレーの部分は掛け合わせて0になるので、実質的な影響はない。


Pythonコード

pythonでは、numpyのlinalgモジュールにあるsvdという関数で特異値分解を実行することができる。
この関数が返す $U, V$ はデフォルトでは表記(3)に対応する対称行列である。ただし、full_matrices=Falseとすると、表記(2)に対応する $U, V$ が得られる。
また、$\Gamma$については、行列ではなく(0を含む)特異値の配列が返される。行列Aのランクは2なので、0でない特異値の数は2つとなっている。

特異値分解の$\Gamma$にするためには、np.diagで対角行列にする必要がある。
確認のため、$U, \Gamma, V$の積をとってみると、確かに元の行列$A$と一致することが分かる。

import numpy as np
from numpy.linalg import svd, matrix_rank

# rank=2の 3x4行列を作成
A = np.array([[2, 4, 1, 3], [1, 5, 3, 2], [5, 7, 0, 7]])

print('matrix A\n', A)
print('rank: ', matrix_rank(A))

# singular value decomposition
u, s, vh = svd(A)
print('\nSVD result')
print('shape of u, s, vh:', u.shape, s.shape, vh.shape)
print('singular values:', s.round(2))

# full_matrices=Falseの場合
u, s, vh = svd(A, full_matrices=False)
print('\nSVD result (full_matrices: False)')
print('shape of u, s, vh:', u.shape, s.shape, vh.shape)

# 復元
# A_re = (u @ np.diag(s, -1)[1:] @ vh).round(2)
A_re = (u @ np.diag(s) @ vh).round(2)
print('\nreconstructed A:\n', A_re)
実行結果
matrix A
 [[2 4 1 3]
 [1 5 3 2]
 [5 7 0 7]]
rank:  2

SVD result
shape of u, s, vh: (3, 3) (3,) (4, 4)
singular values: [13.39  3.58  0.  ]

SVD result (full_matrices: False)
shape of u, s, vh: (3, 3) (3,) (3, 4)

reconstructed A:
 [[ 2.  4.  1.  3.]
 [ 1.  5.  3.  2.]
 [ 5.  7. -0.  7.]]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GANを学びたいけれど、価値関数の数式に困惑している人へ

GANの価値関数(目的関数)

image.png

本記事ではGANを学び始めたら見かけてしまう、一見複雑そうな上記の式を解説していく

GANのモデル

まずはGANのモデルと学習の流れを軽く見てみる
image.png

順伝播(Discriminatorに判定させてみる)

・Generatorがノイズ(例えば100次元のベクトル)から画像っぽいものを生成する
もちろん最初はでたらめな画像しか生成できない

・Discriminatorには本物の画像、もしくはGeneratorが生成した画像のどちらかをランダムに入れる

・Discriminatorがスコアを出すときはシグモイド関数を使うため、
本物だと思ったら1を出力、Generatorが生成した画像(偽物)だと思ったら0を出力する

正確にいうと「Discriminatorに来た画像が本物である確率」

逆伝播(Discriminatorの重みを更新するとき)

Discriminatorの理想は本物が来たら1を出力して、偽物が来たら0を出力

・ここはシンプルに画像分類をしたときのCNNの重みの更新と同じ
GANだからと言って新しい何かがあるわけではない
正しく判定(本物が来たら1を出力して、偽物が来たら0を出力)できるように重みを更新する

逆伝播(Generatorの重みを更新するとき)

Generatorの理想はDiscriminatorが間違って判定(偽物の画像に対して1を出力)すること

・これは実装上のポイントにもなるが
Generatorの重みを更新するときは、誤差がDiscriminatorを通ってくるため
Discriminatorの重みの更新を止めなければならない

もしDiscriminatorの重みの更新を止めなかったら、Discriminatorの重みが偽物に対して1を出力するようになってしまう(今はGeneratorの理想に近づくような更新がされているため)

本題へ

GANの価値関数(再掲)
image.png

右辺について

$E$:期待値
$x$~$p_{data}(x) $:本物の画像がDiscriminatorに来たとき
$D(x)$:Discriminatorに本物の画像が来たときのスコア

$x$~$p_z(x)$:Generatorが生成した画像(偽物)がDiscriminatorに来たとき
$G(z)$:Generatorがノイズzから生成した偽物画像
$D(G(z))$:Discriminatorに(Generatorが生成した)偽物の画像が来たときのスコア

logのグラフ

log(x)のxの値が大きいほどlog(x)は大きくなる
image.png

Discriminatorを評価するとき

・Discriminatorの理想は本物が来たら1、偽物が来たら0を出力すること

右辺第一項

image.png
上記の式を言語化すると、本物の画像がDiscriminatorに来たときのDiscriminatorのスコアである

本物の画像のため、シグモイド関数の出力は0~1の内、を出力してほしい

理想的な出力である$D(x)=1$を出力できれば、結果的に上記の式(右辺第一項)を最大化できる

右辺第二項

image.png
上記の式を言語化すると
Generatorが生成した画像(偽物)がDiscriminatorに来たときのDiscriminatorのスコアである

偽物の画像のため、シグモイド関数の出力は0~1の内、を出力してほしい

理想的な出力である$D(G(z)))=0$を出力できれば、$log(1-0)$になり
結果的に上記の式(右辺第二項)を最大化できる

Discriminatorまとめ

上述のようにDiscriminatorの理想通り(本物の画像には1を出力、偽物の画像には0を出力)になれば、
第一項と第二項はどちらも最大になる(大きい値と大きい値を足し合わせているので右辺トータルも最大)

このことを表しているのが、価値関数の左辺にある$max_D$である

Generatorを評価するとき

・Generatorの理想はDiscriminatorが間違って判定(偽物の画像に対して1を出力)すること

・右辺第一項はGeneratorに関係ないので無視する

右辺第一項

image.png
本物の画像がDiscriminatorに来たときのDiscriminatorのスコアを表している

これはGeneratorとは関係がないのでGeneratorを評価するときは無視する

右辺第二項

image.png
Generatorが生成した画像(偽物)がDiscriminatorに来たときのDiscriminatorのスコアを表している

GeneratorはDiscriminatorが間違ってほしい
Generatorにとっては、偽物画像に対してDiscriminatorが1を出力するのが理想

理想的な出力である$D(G(z))=1$を出力できれば、$log(1-1)$になり
結果的に右辺第二項を最小化できる

Generatorまとめ

上述のようにGeneratorの理想通り(Generatorの生成した画像に対してDiscriminatorが1を出力)になれば、第二項は最小になる(第一項は無視、第二項最小化で右辺トータルは最小)

このことを表しているのが、価値関数の左辺にある$min_G$である

全体まとめ

文字が多くて圧倒されてしまいがちな式だが、
「GeneratorとDiscriminatorのそれぞれの理想の状況ってどうなんだっけ?」と落ち着いて考えていけば、「そんな複雑なことを表している式ではないんだな」ということが理解できると思う

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonを使ってDECTRISの二次元検出器のHDF5データを読み込む

はじめに

スイスの国立研究所PSIのスピンオフベンチャーDECTRISの1ピクセル1円1とも言われる二次元高分解能X線検出器は、手軽に買えない価格にもかかわらずいまや世界中の大学や放射光実験施設に導入されています。実験室系X線の回折装置や小角散乱装置にも採用されており日常的に使っている方もいるでしょう。

高分解能ということはデータ量が増えることを意味します。ビーム強度が強く測定時間の短い放射光実験では、メガピクセルサイズの32ビット二次元配列が世界中の装置で数秒ごとに生成されています。これらの膨大なデータは、放射光施設自体が仕様策定に関わったHDF5ファイルにバイナリとして保存されています。バイナリデータだけに扱いにはそれなりの道具立てが必須です。数百枚の連続測定データを持ち帰ることがざらにある放射光実験のユーザーには、測定データの多さやファイルサイズに加えてデータそのものの扱いにくさに参っている方もいるでしょう。もちろん、必要なデータを厳選してテキストファイルや扱い慣れたフォーマットに変換し、従来のワークフローに乗せるということも可能です。しかし、PythonとJupyter notebookの組み合わせにより科学データの取り扱い方に新しい潮流が生まれつつある中で、それらを活用して大量のデータを一括で扱うソフトウェア技術を身につけることは、ハードウェアの革命により生まれた新しいサイエンスの可能性を探るのに不可欠な足場とも言えます2。この記事では、X線回折やX線小角散乱という裾野の広い実験手法に起きた超高速な高分解能二次元データ取得というハードウェアによる革命に自力で対応したい方のために、解析の第一歩であるデータの読み取りの方法を述べます。

目的

従来の解析ソフトで扱えるフォーマットに変換するツールをすでに導入しているBLもあると思いますが3、ここでは装置や測定条件に関するメタ情報とカウントデータを、大量データに対する自己流の解析・可視化ワークフローを適用しやすいPythonを使って読み取ることを目的にします4。BLスタッフが用意したデータ処理ソフトウェアを使って扱いやすい形式にすることが多いのか、日本語に限らず英語でも執筆時点ではDECTRISのHDF5ファイル読み取りに関する解説はまだウェブにはないようです。

HDFファイルを扱う際の注意点

DECTRISのデータ(ここではEIGER 4M)を扱うにあたって、知っておくべき点がいくつかあります。詳しくは理研放射光科学研究センターの山下さんのGitHubに書いてありますが、ここでは読み取りに関わるHDF5の圧縮機能と外部リンク機能についてだけ述べます。

圧縮フィルター機能

データ圧縮はHDF5の透過的(transparent)な機能の一つです。透過的というのはユーザーがあまり意識せずとも自動的に機能してくれるという意味です。HDF5関連ドキュメントでは、圧縮機能は透過であることをフィルターに例えて圧縮フィルター(compression filter)とも呼ばれています。DECTRISのHDF5データの圧縮にはbitshuffle+lz4(bslz4)という形式が使われています5。bitshuffleもlz4もHDF5標準の圧縮フィルターではないのでプラグインとしてユーザーが追加する必要があります。Pythonのh5pyパッケージを使ってHDF5を読み取る場合は、ESRFのソフトウェアチームの方が用意したhdf5pluginというパッケージをインストールすれば簡単に両者を導入できます。

外部リンク機能

HDF5の規格には大量の実験データが日々生成される放射光実験施設の提案によるものもあります。外部リンク(External link)機能はその中の一つから発展した機能のようです6。外部リンク機能は、通常のパス表記を使って異なるHDF5ファイルのDatasetにアクセスできる機能です。例えば、連続測定によって大量に得られたデータを扱う際に、全データ共通のメタ情報のみを含むHDF5ファイル(通称マスターファイル)に設定してある各測定結果への外部リンクを使うと、マスターファイルを読み込むだけで別ファイルに保存してある全測定データにシームレスにアクセスできます。I/Oパフォーマンスに関する良し悪しは検証していませんが、コードがかなり簡潔になるのは確かです。

準備

hdf5pluginはpipで、ほかはcondaからインストールできます。

%matplotlib inline
import hdf5plugin # 環境変数のパスを設定をしているので必ずh5pyより先にインポート
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
import h5py

from matplotlib import __version__ as mplv

print('Numpy:', np.__version__)
print('matplotlib:', mplv)
print('h5py:', h5py.__version__)

plt.rcParams['image.origin'] = 'lower' # imshowの原点を左下に

# 明示的に読み込むのはマスターファイルのみ
masterhdf = '/dummy/path/to/data/EIGER_4M_test_master.h5'

この記事ではマスターファイルのあるフォルダには以下のような測定データあるとします。マスターファイルと測定ファイルの名前の共通部分は外部リンクが正しく機能するために必要です。

> ls /dummy/path/to/data
EIGER_4M_test_data_000001.h5
EIGER_4M_test_data_000002.h5
EIGER_4M_test_data_000003.h5
EIGER_4M_test_data_000004.h5
EIGER_4M_test_master.h5

HDFファイルの中身を確認する

この記事に書いてある方法を使って、データ構造とdatasetの中身を確認します。ただし、外部リンクのデータはこの方法では表示されません。

def PrintOnlyDataset(name, obj):
    if isinstance(obj, h5py.Dataset):
        print(name)
        print(obj.value)

with h5py.File(masterhdf,'r') as f:
    f.visititems(PrintOnlyDataset)

bslz4フィルターが機能していれば以下のような内容が出力されます。マスターファイルの内容は全測定に共通な検出器情報が主であることがわかります。

entry/instrument/beam/incident_wavelength
0.7208383
entry/instrument/detector/beam_center_x
0.0
entry/instrument/detector/beam_center_y
0.0
entry/instrument/detector/bit_depth_image
32
entry/instrument/detector/bit_depth_readout
12
entry/instrument/detector/count_time
0.48999998
entry/instrument/detector/countrate_correction_applied
1
entry/instrument/detector/description
b'Dectris Eiger 4M'
...
...

データ読み込み後のワークフローで波長や検出器距離などが必要になったときは、ここでパスを確認しておくと必要な時に簡単に取得できます。

測定データとマスクの読み込み

マスターデータのentry/data以下にdata_00****という形で1-2000までの番号が振られた2000個の外部リンクがあらかじめ用意されています。例えば、マスターファイルと同じ場所に4個の連番測定ファイル(000001-000004)が置いてある私の環境で以下のスクリプトを実行してみます。

with h5py.File(masterhdf,'r') as f:
    # {i:04}でゼロ埋めした整数4桁というフォーマットを指定
    for p in [f'entry/data/data_00{i:04}' for i in [0, 1, 4, 2000, 2001]]:
        try:
            f[p] # 外部リンク先にファイルが存在するかチェック。
            print(p)
        except KeyError as e: # ファイルまた外部リンク自体がなければKeyError
            print(e)
printの結果
"Unable to open object (object 'data_000000' doesn't exist)"
entry/data/data_000001
entry/data/data_000004
"Unable to open object (unable to open file: name = '/dummy/path/to/data/EIGER_4M_test_002000.h5', errno = 2, error message = 'No such file or directory', flags = 0, o_flags = 0)"
"Unable to open object (object 'data_002001' doesn't exist)"

五つのprintの結果が意味するところは以下の通りです。

  1. 外部リンクにdata_000000は存在しない、つまり連番は1始まり
  2. 1番目のデータのマスターファイル上の外部リンクパス(OS上のファイル名はEIGER_4M_test_data_000001.h5
  3. 4番目のデータのマスターファイル上の外部リンクパス(OS上のファイル名はEIGER_4M_test_data_000004.h5
  4. マスターファイルに外部リンクdata_002000は設定されているが、マスターファイルと同じ場所にEIGER_4M_test_data_002000.h5が存在しない
  5. 外部リンクは1-2000なのでdata_002001は存在しない

これはGUIソフトのHDFViewでマスターファイルを開いても確認できます。実際に開いて下までスクロールすれば、実際のファイルが存在しないことを表す"?"がdata_002000まで並んでいることがわかります。
Screen Shot 2019-02-25 at 16.17.08.png

測定データの数はマスターファイルと同じ場所にあるEIGER_4M_test_data_******.h5の数を見ればわかります。ここでは4Mピクセルのデータが500枚格納された測定結果ファイルを二つ指定して500枚の和を読み込みます。可視化で必要なマスクも読み込んでおきます。

imgdatasets = ['entry/data/data_000001', 'entry/data/data_000002'] # 外部リンク
imgs = {} # 読み込み済みデータ格納先

with h5py.File(masterhdf, mode='r') as f:
    # 測定ファイル二つからそれぞれ500枚のデータの和をとる
    for imgdataset in imgdatasets:
        numimg = f[imgdataset].shape[0]
        temp = np.zeros_like(mask)
        # EIGER 4Mのデータx500が大きすぎるのかnp.sumが異常に遅い
        # 通常は遅くてご法度とされるNumpy arrayのforループで代用
        for n in tqdm(range(numimg)):
            temp += f[imgdataset][n]

        imgs[imgdataset] = temp

    # マスクデータ
    mask = f['entry/instrument/detector/detectorSpecific/pixel_mask'].value

二次元データ表示

Pythonで測定データを読み込めたらまずやりたいのは可視化です7。ここではもっとも基本的な二次元画像としての可視化をしてみます。

nrow, ncol = len(imgs), 2
fig, axes = plt.subplots(nrow, ncol, figsize=(8, 4*nrow))
vmax = 1e7
for (k, v), ax in zip(imgs.items(), axes):
    temp = v.copy()
    ax[0].imshow(temp, norm=LogNorm(), vmax=vmax)
    ax[0].set_title(f'{k}\nnot masked')
    ax[0].axis('off')

    # 検出器モジュール間の隙間や異常ピクセルをマスク
    # 整数型のarrayにnp.nanは代入できないので弱い強度として1を代入
    temp[mask != 0] = 1
    ax[1].imshow(temp, norm=LogNorm(), vmax=vmax)
    ax[1].set_title('masked')
    ax[1].axis('off')

download-2.png

マスク済みのほうを見ると、両データに共通する位置にマスクしきれていない異常ピクセルに見える点がありますが、これは画像の解像度の問題のようで、PDFにして拡大すると何も異常はありません。しかし、全体が妙に暗いのでどこかに周囲に比べて異常に強いピクセルが残ってるようです。マスク済みの最後のtempを一次元プロットして見ると、予想通り一定の強度の異常ピクセルが残っていることがわかるので、この部分を追加でマスク(実際は弱い強度として1を代入)します。

plt.semilogy(temp.ravel(), '.')

download-1.png

先ほどのマスク部分を以下のようにして再度同じことをしてみます。

    temp[mask != 0] = 1
    temp[temp > 1e9] = 1

download-3.png
download-4.png

異常ピクセルに$10^0$が代入され、全体の色合いも正しそうな感じになりました。

この先のワークフロー

ここで紹介したデータの読み込みの次はPONIファイルを使った歪み補正やPyFAIによる一次元化、さらには測定やテーマごとの各種解析という具合に進んでいきます。温度などの測定条件を変えた連続実験の場合はpandasのDataFrameを使った測定条件管理が役立つかもしれません。


  1. 噂で耳にする値段を画素数で割ると、確かにこれくらいのオーダーはこれくらいになります。 

  2. ハードウェアとソフトウェアのどちらが足場であるかという議論はここではしません。 

  3. 競争が激しいタンパク質構造解析関連のBLはやはりこの手の対応が早いようで、例えば名前がおもしろい理研のKAMOやケンブリッジの会社のautoPROCなどがあります。 

  4. DECTRIS公式のALBULAというソフトウェア(要ユーザー登録)には測定データの可視化機能に加えてPython APIも用意されていますが、使い方の説明がまだ貧弱です。おそらくこの記事で使っているh5pyのラッパーだとは思いますが、現状では使うにあたって自分でh5pyを使うのと同じ程度の手探りが必要な状況です。むしろラッパーであるがゆえにわかりにくくなっている部分が増えている可能性も高いです。 

  5. EIGERの公式ドキュメント参照 

  6. イギリスの放射光実験施設Diamondの文書にある"VIRTUAL DATA SETS"がsoft link機能として導入され、external linkはその発展形として後のバージョンで導入されたそうです。 

  7. ちなみに、可視化だけであればALBULAでも可能です。画面サンプルはEIGERのマニュアルにあります。試しに使って見ましたが、EIGER 4Mの連続測定データ数百回分のアニメーション再生が非常に軽快でした。ただ、測定中にその場でデータ確認する分には非常に有用だと思いますが、まだできることが少なくシンプルな可視化機能しかありません。また、漏れなくアップデートを通知するためかユーザー登録も必須です。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】PyPIエラー対応 400 Client Error: User '(username)' has no verified email addressesの対処法

発生したエラー

twineを使って、PythonパッケージをPyPIに登録しようとしたところ、

HTTPError: 400 Client Error: User (username) has no verified email addresses

のエラーとなる。

$ twine upload --repository pypi dist/*
Enter your username: (username)
Enter your password: 
Uploading distributions to https://upload.pypi.org/legacy/
Uploading (packagename)-1.0.0-py3-none-any.whl
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 11.4k/11.4k [00:01<00:00, 9.14kB/s]
NOTE: Try --verbose to see response content.
HTTPError: 400 Client Error: User '(username)' has no verified email addresses, please verify at least one address before registering a new project on PyPI.See https://pypi.org/help/#verified-email for more information. for url: https://upload.pypi.org/legacy/
$

対処方法

原因は、PyPIアカウント登録時のメール認証実施漏れ。

PyPIアカウント登録時に登録したメールアドレスに、PyPIからのメールが届いているはずなので、そのメール本文のclick this link to verify your email addressをクリックしてください。

このメール認証を行わなくてもPyPIのサイトへのログイン等はできるのですが、パッケージを登録しようとすると上記のエラーになってしまいますので、忘れずにメール認証しておいてください。

環境

  • Python 3.6.6
  • twine 1.13.0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】PyPIエラー対応 400 Client Error: User (username) has no verified email addressesの対処法

発生したエラー

twineを使って、PythonパッケージをPyPIに登録しようとしたところ、

HTTPError: 400 Client Error: User '(username)' has no verified email addresses

のエラーとなる。

$ twine upload --repository pypi dist/*
Enter your username: (username)
Enter your password: 
Uploading distributions to https://upload.pypi.org/legacy/
Uploading (packagename)-1.0.0-py3-none-any.whl
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 11.4k/11.4k [00:01<00:00, 9.14kB/s]
NOTE: Try --verbose to see response content.
HTTPError: 400 Client Error: User '(username)' has no verified email addresses, please verify at least one address before registering a new project on PyPI.See https://pypi.org/help/#verified-email for more information. for url: https://upload.pypi.org/legacy/
$

対処方法

原因は、PyPIアカウント登録時のメール認証実施漏れ。

PyPIアカウント登録時に登録したメールアドレスに、PyPIからのメールが届いているはずなので、そのメール本文のclick this link to verify your email addressをクリックしてください。

このメール認証を行わなくてもPyPIのサイトへのログイン等はできるのですが、パッケージを登録しようとすると上記のエラーになってしまいますので、忘れずにメール認証しておいてください。

環境

  • Python 3.6.6
  • twine 1.13.0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

djangoで画像処理アプリケーションを作った

はじめに

djangoで画像処理アプリケーションを作成しました。
とりあえずそれらしく動いたので現状をメモ。

サンプルコード

https://github.com/takuto412/web_app.git

環境

Python 3.6.7
django 2.1.2

グレースケールに変換するアプリ

主な構成

gray_app
│ manage.py
│ db.sqlite3
├ app1
│   │ models.py
│   │ forms.py
│   │ urls.py
│   │ views.py
│   └ templates
│         └ app1
│             └ index.html
├ media
│   │ documents
│   └ output  
└ myapp
    │ settings.py
    └ urls.py

主なコード

models.py
from django.db import models

class Document(models.Model):
    description = models.CharField(max_length=255, blank=True)
    photo = models.ImageField(upload_to='documents/', default='defo')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    output = models.ImageField(default = 'output/output.jpg')

forms.py
from django import forms
from .models import Document

class DocumentForm(forms.ModelForm):
    class Meta:
        model = Document
        fields = ('description', 'photo',)
  • 一番下の関数を書き換えることによって様々な画像処理が可能です。
views.py
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .forms import DocumentForm
from .models import Document
import cv2
from django.conf import settings

def index(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('index')
    else:
        form = DocumentForm()
        max_id = Document.objects.latest('id').id
        obj = Document.objects.get(id = max_id)
        input_path = settings.BASE_DIR + obj.photo.url
        output_path = settings.BASE_DIR + "/media/output/output.jpg"
        gray(input_path,output_path)

    return render(request, 'app1/index.html', {
        'form': form,
        'obj':obj,
    })


###########ここをカスタマイズ############

def gray(input_path,output_path):
    img = cv2.imread(input_path)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    cv2.imwrite(output_path, img_gray)

######################################
index.html
<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Upload</title>
    </head>
    <body>

        <form method="post" enctype="multipart/form-data">
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit">Upload</button>
        </form>

        <td>{{ obj.description }}</td>
        <!--<td>{{ obj.gray_photo.url }}</td>-->
        <td><img src="{{ obj.output.url }}" width="100" height="100"/></td>
        <td>{{ obj.uploaded_at }}</td>
    </body>
</html>

画面イメージ

スクリーンショット 2019-02-26 1.50.20.png

超解像画像に変換するアプリ

主な構成

super_resolve_app
│ manage.py
│ db.sqlite3
├ app1
│   │ models.py
│   │ forms.py
│   │ urls.py
│   │ views.py *変更点
│   │ super_resolve.py *変更点
│   │ model.py *変更点
│   │ model_epoch_30.pth *変更点
│   └ templates
│         └ app1
│             └ index.html  
├ media
│   │ documents
│   └ output   
└ myapp
    │ settings.py
    └ urls.py

主なコード

超解像の部分は、ほぼこれのパクリです。
https://github.com/pytorch/examples/tree/master/super_resolution

views.py
from __future__ import print_function
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .forms import DocumentForm
from .models import Document
import cv2
from django.conf import settings
import torch
from PIL import Image
from torchvision.transforms import ToTensor
import numpy as np
from .super_resolve import super_resolve


def index(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('index')
    else:
        form = DocumentForm()
        max_id = Document.objects.latest('id').id
        obj = Document.objects.get(id = max_id)

        input = settings.BASE_DIR + obj.photo.url
        output = settings.BASE_DIR + "/media/output/output.jpg"
        super_resolve(input, output)

    return render(request, 'app1/index.html', {
        'form': form,
        'obj':obj,
    })
super_resolve.py
from __future__ import print_function
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .forms import DocumentForm
from .models import Document
import cv2
from django.conf import settings
import torch
from PIL import Image
from torchvision.transforms import ToTensor
import numpy as np
from .super_resolve import super_resolve


def index(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('index')
    else:
        form = DocumentForm()
        max_id = Document.objects.latest('id').id
        obj = Document.objects.get(id = max_id)

        input_path = settings.BASE_DIR + obj.photo.url
        output_path = settings.BASE_DIR + "/media/output/output.jpg"
        super_resolve(input_path, output_path)

    return render(request, 'app1/index.html', {
        'form': form,
        'obj':obj,
    })

画面イメージ

スクリーンショット 2019-02-26 1.49.19.png

実行方法

python manage.py makemigrations
python manage.py migrate
python manage.py runserver (IPアドレス:ポート番号)

注意事項

IPアドレスを指定する場合

ALLOWED_HOSTS = ['IPアドレス']

参考記事

https://ymgsapo.com/show-image-imagefield/
https://ymgsapo.com/gray-scale-app/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Djangoで画像処理アプリケーションを作った

はじめに

  • djangoで画像処理アプリケーションを作成しました。
  • とりあえずそれらしく動いたので現状をメモ。

サンプルコード

https://github.com/takuto412/web_app.git

環境

Python 3.6.7
django 2.1.2
OpenCv 4.0.0
PyTorch 1.0.0

グレースケールに変換するアプリ

主な構成

gray_app
│ manage.py
│ db.sqlite3
├ app1
│   │ models.py
│   │ forms.py
│   │ urls.py
│   │ views.py
│   └ templates
│         └ app1
│             └ index.html
├ media
│   │ documents
│   └ output  
└ myapp
    │ settings.py
    └ urls.py

主なコード

models.py
from django.db import models

class Document(models.Model):
    description = models.CharField(max_length=255, blank=True)
    photo = models.ImageField(upload_to='documents/', default='defo')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    output = models.ImageField(default = 'output/output.jpg')

forms.py
from django import forms
from .models import Document

class DocumentForm(forms.ModelForm):
    class Meta:
        model = Document
        fields = ('description', 'photo',)
  • 一番下の関数を書き換えることによって様々な画像処理が可能です。
views.py
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .forms import DocumentForm
from .models import Document
import cv2
from django.conf import settings

def index(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('index')
    else:
        form = DocumentForm()
        max_id = Document.objects.latest('id').id
        obj = Document.objects.get(id = max_id)
        input_path = settings.BASE_DIR + obj.photo.url
        output_path = settings.BASE_DIR + "/media/output/output.jpg"
        gray(input_path,output_path)

    return render(request, 'app1/index.html', {
        'form': form,
        'obj':obj,
    })


###########ここをカスタマイズ############

def gray(input_path,output_path):
    img = cv2.imread(input_path)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    cv2.imwrite(output_path, img_gray)

######################################
index.html
<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Upload</title>
    </head>
    <body>

        <form method="post" enctype="multipart/form-data">
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit">Upload</button>
        </form>

        <td>{{ obj.description }}</td>
        <!--<td>{{ obj.gray_photo.url }}</td>-->
        <td><img src="{{ obj.output.url }}" width="100" height="100"/></td>
        <td>{{ obj.uploaded_at }}</td>
    </body>
</html>

画面イメージ

スクリーンショット 2019-02-26 1.50.20.png

超解像画像に変換するアプリ

主な構成

super_resolve_app
│ manage.py
│ db.sqlite3
├ app1
│   │ models.py
│   │ forms.py
│   │ urls.py
│   │ views.py *変更点
│   │ super_resolve.py *変更点
│   │ model.py *変更点
│   │ model_epoch_30.pth *変更点
│   └ templates
│         └ app1
│             └ index.html  
├ media
│   │ documents
│   └ output   
└ myapp
    │ settings.py
    └ urls.py

主なコード

超解像の部分は、以下を参考にしました。
https://github.com/pytorch/examples/tree/master/super_resolution

views.py
from __future__ import print_function
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .forms import DocumentForm
from .models import Document
import cv2
from django.conf import settings
import torch
from PIL import Image
from torchvision.transforms import ToTensor
import numpy as np
from .super_resolve import super_resolve


def index(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('index')
    else:
        form = DocumentForm()
        max_id = Document.objects.latest('id').id
        obj = Document.objects.get(id = max_id)

        input = settings.BASE_DIR + obj.photo.url
        output = settings.BASE_DIR + "/media/output/output.jpg"
        super_resolve(input, output)

    return render(request, 'app1/index.html', {
        'form': form,
        'obj':obj,
    })
super_resolve.py
import torch
from PIL import Image
from torchvision.transforms import ToTensor
import numpy as np
from django.conf import settings
from .model import Net


def super_resolve(input_url, output_url):
    # Training settings

    input_image = input_url

    img = Image.open(input_image).convert('YCbCr')
    y, cb, cr = img.split()

    model_path = settings.BASE_DIR + '/app1/model_epoch_30.pth'

    the_model = Net(3)
    the_model.load_state_dict(torch.load(model_path))

    img_to_tensor = ToTensor()
    input = img_to_tensor(y).view(1, -1, y.size[1], y.size[0])

    out = the_model(input)
    out = out.cpu()
    out_img_y = out[0].detach().numpy()
    out_img_y *= 255.0
    out_img_y = out_img_y.clip(0, 255)
    out_img_y = Image.fromarray(np.uint8(out_img_y[0]), mode='L')

    out_img_cb = cb.resize(out_img_y.size, Image.BICUBIC)
    out_img_cr = cr.resize(out_img_y.size, Image.BICUBIC)
    out_img = Image.merge('YCbCr', [out_img_y, out_img_cb, out_img_cr]).convert('RGB')

    out_img.save(output_url)
    print('output image saved to ', output_url)

画面イメージ

スクリーンショット 2019-02-26 1.49.19.png

実行方法

python manage.py makemigrations
python manage.py migrate
python manage.py runserver (IPアドレス:ポート番号)

注意事項

IPアドレスを指定する場合

settings.py
ALLOWED_HOSTS = ['IPアドレス']

参考記事

https://ymgsapo.com/show-image-imagefield/
https://ymgsapo.com/gray-scale-app/
https://qiita.com/hiroyuki_mrp/items/8b2b78e066f35edbfbfd

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python unittest】mockでリストを返してもらうときの注意

概要

Pythonでmock使ってテスト書いてたら、リスト返してもらうところでちょっとはまったのでメモ

mock.return_valueは参照を返す

Mockにreturn_valueとしてリストを設定

#from unittest.mock import Mock を省略しています
>>> mc = Mock()
>>> mc.return_value = [0,1,2]
>>> mc()
[0, 1, 2]

Mockを呼び出して、返り値を編集する

>>> test = mc()
>>> test
[0, 1, 2]
>>> test[0]=9
>>> test
[9, 1, 2]

もう一回モックを呼び出すと

>>> test = mc()
>>> test
[9, 1, 2]
#[0,1,2]がほしかった

うーん
ちなみにこういうことをしてもだめ

>>> import copy
>>> mc.return_value = copy.deepcopy([0,1,2]) #ついでにlambda:[0,1,2]もだめ
>>> test = mc()
>>> test
[0, 1, 2]
>>> test[0] = 99
>>> test
[99, 1, 2]
>>> test=mc()
>>> test
[99, 1, 2]

side_effectに関数を設定しましょう

>>> mc = Mock()
>>> mc.side_effect = lambda:[0,1,2]
>>> test = mc()
>>> test
[0, 1, 2]
>>> test[0]=9
>>> test
[9, 1, 2]
>>> test = mc()
>>> test
[0, 1, 2]

とりあえずよかった。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pybind11入門(3) NumPy連携その1

その1 https://qiita.com/lucidfrontier45/items/872c38b5eec08e3800d7
その2 https://qiita.com/lucidfrontier45/items/c7cc409a3af962d100a3

pybind11を使ってNumPyと連携する方法を試した。まずは直接ndarrayを触る方法。

pybind11::array

pybind11にはpybind11::bufferpybind11::arrayのに種類のクラスが定義されており、これらを介してndarrayを扱うことができる。前者はndarrayに限らない一般的なPythonのbufferプロトコルと連携できるものであり、ここではndarray専用のarray型を試してみる。なお、array_t<T>というtemplateも用意されており、実際にはこちらを用いる。いつもどおり、cmakeを用いる。

CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(pybind_test VERSION 0.1.0)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_subdirectory(pybind11)
add_subdirectory(fmt)
pybind11_add_module(mymodule module.cpp)
target_link_libraries(mymodule PRIVATE fmt::fmt)

fmtという書式フォーマットのライブラリも使用する。
https://github.com/fmtlib/fmt

ndarrayへのReadOnlyアクセス

2次元配列の各要素を表示するだけのプログラムで動作を確認してみる。

module.cpp
#include <iostream>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <fmt/core.h>

namespace py = pybind11;

template <typename T>
void print_array(py::array_t<T> x)
{
    const auto &buff_info = x.request();
    const auto &shape = buff_info.shape;
    std::cout << "C++" << std::endl;
    for (auto i = 0; i < shape[0]; i++)
    {
        for (auto j = 0; j < shape[1]; j++)
        {
            auto v = *x.data(i, j);
            std::cout << fmt::format("x[{}, {}] = {}", i, j, v) << std::endl;
        }
    }
}

PYBIND11_MODULE(mymodule, m)
{
    m.doc() = "my test module";
    m.def("print_array", &print_array<int32_t>, "");
    m.def("print_array", &print_array<double>, "");
}

ndarrayを扱う場合にはpybind11/numpy.hをincludeする。requestメソッドでbuffer_info型の変数を得ることがでる。buffer_infoは以下のような構造になっており

struct buffer_info {
    void *ptr;
    ssize_t itemsize;
    std::string format;
    ssize_t ndim;
    std::vector<ssize_t> shape;
    std::vector<ssize_t> strides;
};

ndarrayでおなじみのshapeなどが得られるのでこれを用いでfor loopを回せます。データにアクセスする際にはx.data(i, j)のようにするとその要素へのポインタが得られる。なお、dataメソッドはReadonlyのアクセスなので得られるポインタにはconstがついている。

最後に、この関数はtemplateを使用しているのでpybind11に登録する際には実体化する必要がる。ここでは整数用のint32_tと実数用のdoubleの2種類を作る。

Pythonで実行して確認する。

import numpy as np
import mymodule

x = np.arange(2*3).reshape((2, 3)).astype(np.int32)
print("python")
for i in range(x.shape[0]):
    for j in range(x.shape[1]):
        print("x[{}, {}] = {}".format(i, j, x[i, j]))
>>>
python
x[0, 0] = 0
x[0, 1] = 1
x[0, 2] = 2
x[1, 0] = 3
x[1, 1] = 4
x[1, 2] = 5
C++
x[0, 0] = 0
x[0, 1] = 1
x[0, 2] = 2
x[1, 0] = 3
x[1, 1] = 4
x[1, 2] = 5

ちゃんと同じ内容が表示できた!

配列の変更

.data(i, j)の代わりに.mutable_data(i, j)を用いることでconstでないポインタが得られ、内容を書き換えることができる。以下のプログラムは全配列の要素に定数を足す例である。

template <typename T>
void modify_array_inplace(py::array_t<T> x, T a)
{
    const auto &buff_info = x.request();
    const auto &shape = buff_info.shape;
    for (auto i = 0; i < shape[0]; i++)
    {
        for (auto j = 0; j < shape[1]; j++)
        {
            *x.mutable_data(i, j) += a;
        }
    }
}

PYBIND11_MODULE(mymodule, m)
{
    m.doc() = "my test module";
    m.def("modify_array_inplace", &modify_array_inplace<int32_t>, "");
    m.def("modify_array_inplace", &modify_array_inplace<double>, "");
}

Pythonで試してみる。

x = np.random.randn(2, 3).astype(np.float64)
print("before")
for i in range(x.shape[0]):
    for j in range(x.shape[1]):
        print("x[{}, {}] = {:.6f}".format(i, j, x[i, j]))

mymodule.modify_array_inplace(x, 10.0)
print("after")
for i in range(x.shape[0]):
    for j in range(x.shape[1]):
        print("x[{}, {}] = {:.6f}".format(i, j, x[i, j]))

>> 
before
x[0, 0] = 1.307738
x[0, 1] = -1.625780
x[0, 2] = 0.196201
x[1, 0] = 0.614617
x[1, 1] = -0.175023
x[1, 2] = 1.490781
after
x[0, 0] = 11.307738
x[0, 1] = 8.374220
x[0, 2] = 10.196201
x[1, 0] = 10.614617
x[1, 1] = 9.824977
x[1, 2] = 11.490781

配列の各要素に一律に10.0が足されたのが分かる。

なお、

mymodule.modify_array_inplace(x, 10)

のようにするとxがdoubleの配列なのにintを足していてmodify_array_inplace<int32_t>のほうが呼ばれたらしく、xは型が異なるのでコピーが渡されて配列の中身は変更されなかった。渡す引数がintなのか、floatなのかは注意したほうが良さそう。

array_tを返す関数

array_t型の変数をを新規に作成し、戻り値にすることでPython側に新しいndarrayを返すことができる。

template <typename T>
auto modify_array(py::array_t<T> x, T a)
{   
    const auto &buff_info = x.request();
    const auto &shape = buff_info.shape;
    py::array_t<T> y{shape};
    for (auto i = 0; i < shape[0]; i++)
    {
        for (auto j = 0; j < shape[1]; j++)
        {
            *y.mutable_data(i, j) = *x.data(i, j) + a;
        }
    }
    return y;
}

array_t型のコンストラクタは色々あるが、shapeを渡すものが最も簡単に使用できると思う。Pythonで利用する場合は以下の通り。

x = np.arange(2*3).reshape((2, 3)).astype(np.int32)
x2 = mymodule.modify_array(x, 10)

direct access

余計なチェックを無くしてよりオーバーヘッドが少ないアクセスの仕方もある。@cython.boundscheck(False)的なものだと思う1

template <typename T>
void modify_array_direct(py::array_t<T> x, T a)
{
    auto r = x.template mutable_unchecked<2>();
    for (auto i = 0; i < r.shape(0); i++)
    {
        for (auto j = 0; j < r.shape(1); j++)
        {
            r(i, j) += a;
        }
    }
}

公式docではx.mutable_unchecked<2>();となっているがこれだとコンパイルエラー。githubのissueに同様のものがあってx.template mutable_unchecked<2>();とすれば良いらしい2。ちなみにtemplateを使用せず、

void modify_array_direct(py::array_t<double> x, double a){
    auto r = x.mutable_unchecked<2>();
    ...
}

のような場合は問題なかった。

参考

いつもの公式doc: https://pybind11.readthedocs.io/en/stable/advanced/pycpp/numpy.html
uncheckedとtemplateを組み合わせる黒魔術: https://github.com/pybind/pybind11/issues/1412


  1. uncheckedを使用しない方法だとindexの範囲外にアクセスするとPythonのIndexErrorが出たが、uncheckedの場合は特にエラーが出ずにそのまま上書きできた。おそろしやー。 

  2. 自分のC++力が低すぎてなぜそれで良いのかよくわからない。。。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む