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

Python detailEnhanceFilter(詳細強化フィルタ)を用いた靄(かすみ)除去

背景

撮影した写真などが意図せず霞む場合があります。そのため、霞画像に対して画像処理を用いて霞を除去したいというニーズがあります。

実際に下記のサイトを拝見するとAdobeの製品にも霞除去機能があります。
site: https://blogs.adobe.com/japan/cc-adobe-stock-contributor-j-curbon-lightroom-how-to-goto-2/

今回はPythonとOpenCVを用いて簡易な靄除去方法をご紹介します。

detailEnhanceFilter

今回はOpenCVのNon-Photorealistic Renderingに実装されているdetailEnhanceFilterを使用します。

ライブラリの詳細は下記サイトにてご確認ください。
https://docs.opencv.org/master/df/dac/group__photo__render.html

実装

image_processing.py
from PIL import Image
import numpy as np
import cv2

def main():
    img = np.array(Image.open('images/input.jpg'))
    dst = cv2.detailEnhance(img, sigma_s=10, sigma_r=0.15)
    Image.fromarray(dst).save('images/result.jpg')

if __name__ == '__main__':
    main()

実行結果

入力は先ほどご紹介したサイトの画像をお借りしました。
site: https://blogs.adobe.com/japan/cc-adobe-stock-contributor-j-curbon-lightroom-how-to-goto-2/

入力画像

input.jpg

出力画像

result.jpg

Adobe様の霞除去

ado.jpg

所感

怪しくないか...
詳細強化フィルタという名前の通りでエッジが強化されているのが分かります!
しかしエッジ周辺画素が白い印象がありますね。
ただ1行の関数でこの変換能力!OpenCVは素晴らしいですね。
今回はdetailEnhanceフィルタのみの効果を試したかったので前処理は一切していません。
前処理を増やすとより良くなる印象です。
パラメータも未調整です。
ご興味のあるお方はぜひお試しください。
最後にライブラリのバージョンは下記の通りとなります。

ライブラリ

version
Python 3.7.6
opencv-python 4.1.2.30
numpy 1.18.1
pillow 7.0.0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】Qiita 週間いいね数ランキング【タグ別】

他のタグ

集計期間

01月18日 ~ 01月25日

いいね数ランキング

1位: 0.1は浮動小数点数で正確に表せないのに、printしたときに0.1と表示されるのはなぜか

Python float double 浮動小数点数 計算機
366いいね
@yucatioさん(01月21日 13時30分の投稿)

2位: 【#1】PythonでMinecraftを作る。~下調べと設計~

Java Python minecraft ゲーム制作 LWJGL
211いいね
@kkent030315さん(01月21日 02時33分の投稿)

3位: init.py を省略してはいけない

Python
188いいね
@methaneさん(01月20日 07時31分の投稿)

4位: 英語論文を読みたくない大学生(python)

Python LSTM LexRank 文章生成 colaboratory
153いいね
@7vvXiさん(01月21日 03時08分の投稿)

5位: 自動で背景を削除 remove.bgを再現してみた

Python 画像処理 OpenCV MachineLearning DeepLearning
127いいね
@i708さん(01月20日 08時55分の投稿)

6位: 【ハーレム】多すぎて選べない!Pythonで円周率πを計算する13の方法

Python 数値計算 Python3 円周率
124いいね
@POPPIN_FRIENDSさん(01月19日 07時44分の投稿)

7位: Pytorchでモデル構築するとき、torchsummaryがマジ使える件について

Python model MachineLearning CNN PyTorch
87いいね
@tatsuya11bbsさん(01月21日 07時26分の投稿)

8位: opencv-python画像処理入門

Python OpenCV
75いいね
@studio_haneyaさん(01月22日 15時54分の投稿)

9位: Pythonゴルフテク(AtCoder)

Python AtCoder コードゴルフ
67いいね
@c_r_5さん(01月20日 07時53分の投稿)

10位: ゼロから作るDeep Learningで素人がつまずいたことメモ:5章

Python 機械学習 DeepLearning
42いいね
@segavvyさん(01月19日 01時34分の投稿)

11位: MCMCとFiltering実践(視覚的理解と、ターゲット分布の形状に合わせた使い分け)

Python MCMC Finance ParticleFilter bayesian
36いいね
@Spring24さん(01月23日 02時17分の投稿)

12位: Pythonで読み込んだ画像にフィルタをかけるモジュールをC言語で作った

Python C 画像処理
22いいね
@soramimi_jpさん(01月24日 07時44分の投稿)

13位: 3次元の回転をクラスタリングする

Python Quaternion Rotation EulerAngle
18いいね
@yu4uさん(01月23日 13時36分の投稿)

14位: 2020年の開発者が知っておくべき11の必須技能→回答編 → 並べ替え→項目合併(8項目)→内容追記

Python Git Docker 自己評価
13いいね
@kaizen_nagoyaさん(01月22日 02時33分の投稿)

15位: 再帰関数

Python 決定木
12いいね
@hirokuyuさん(01月21日 06時32分の投稿)

16位: ポアソン分布を丁寧に理解してPythonで描画する

Python scipy 統計学 ポアソン分布
10いいね
@g-kさん(01月20日 11時05分の投稿)

17位: 【スターターキット】Scrapy&MariaDB&Django&Dockerでデータ自動収集ボットシステムを構築する

Python Django mariadb Docker Scrapy
9いいね
@Makotunesさん(01月20日 16時17分の投稿)

18位: 画像位置合わせ:SIFTから深層学習まで

Python 画像処理 OpenCV DeepLearning レジストレーション
8いいね
@suuungwooさん(01月22日 05時05分の投稿)

19位: 強化学習 今日から学習

Python
8いいね
@maskot1977さん(01月20日 00時18分の投稿)

20位: RPA、VBA、プログラム言語で行うべき自動化は?

Python VBA 自動化 RPA SikuliX
8いいね
@Okura_さん(01月19日 17時02分の投稿)

21位: blenderのpythonスクリプト入門してみた_その02

Python Blender
7いいね
@muripo_lifeさん(01月24日 16時41分の投稿)

22位: GCP初心者がGCEでマイクラサーバを建ててみた話

Python Linux minecraft gcp discord
7いいね
@rodotanさん(01月20日 09時19分の投稿)

23位: Jetson NanoでRealsenseのPythonラッパーPyRealsenseを使用する方法

Python RealSense JetsonNano pyrealsense2
7いいね
@karaage0703さん(01月19日 17時41分の投稿)

24位: PYTHON環境構築するなら絶対に理解しておかないといけない注意点

Python install Python3
6いいね
@oxlunaxoさん(01月22日 00時32分の投稿)

25位: オンライン周波数解析アプリを作ってみた

Python Django scipy numpy
5いいね
@apple-yagiさん(01月21日 09時15分の投稿)

26位: matplotlibの点の大きさについて

Python matplotlib
5いいね
@maskot1977さん(01月21日 05時10分の投稿)

27位: 『フカシギの数え方』 おねえさんといっしょ:組み合わせ爆発の凄さ

Python Docker graphillion 数え上げ 組み合わせ爆発
5いいね
@kaizen_nagoyaさん(01月21日 02時23分の投稿)

28位: ケモインフォマティクスで学ぶPandas

Python pandas bioinformatics chemoinformatics drugdiscovery
5いいね
@yukiya285さん(01月19日 08時02分の投稿)

29位: pythonによる統計学

Python scipy numpy
4いいね
@kanamae879123さん(01月25日 07時45分の投稿)

30位: 【#2】PythonでMinecraftを作る。~モデル描画とプレイヤー実装~

Python minecraft ゲーム制作 pyglet Panda3D
4いいね
@kkent030315さん(01月24日 10時28分の投稿)

31位: 【Python】ノーヒットノーランを成し遂げたピッチャーの分析をしてみた

Python matplotlib Python3 baseball
4いいね
@yuuuusuke1997さん(01月23日 18時05分の投稿)

32位: DjangoアプリをDocker上に構築しAWS Fargateにデプロイする

Python Django AWS Docker Fargate
4いいね
@keita_gawaharaさん(01月23日 13時05分の投稿)

33位: AI Gaming はじめてみた

Python AI
4いいね
@noyaさん(01月22日 09時23分の投稿)

34位: 2020年 ITカンファレンスまとめ

Ruby Python PHP JavaScript Conference
4いいね
@TaitoAjikiさん(01月20日 15時28分の投稿)

35位: OpenCVでRGBとHSVのヒストグラムを取得する方法

Python OpenCV histogram feature-engineering
4いいね
@tatsuya11bbsさん(01月20日 00時18分の投稿)

36位: pythonでのグラフ描画

Python numpy matplotlib seaborn
3いいね
@kanamae879123さん(01月25日 06時35分の投稿)

37位: Matplotlibでマウスオーバーすると対応する画像を表示させる

Python matplotlib
3いいね
@sage-gitさん(01月24日 14時45分の投稿)

38位: Pythonを使ってインストルメントとボーカルを分けてカラオケ音源をつくりたい

Python DTM DAW
3いいね
@torahikoshinodaさん(01月24日 10時11分の投稿)

39位: いらすとやの画像をドット絵にしたった。(part1)

Python 画像処理 OpenCV いらすとや
3いいね
@satsukiyaさん(01月24日 05時36分の投稿)

40位: 【Django】Django+MySQL+Vue.jsな環境を作るメモ【Python】

Python Django MySQL Vue.js
3いいね
@osakashoさん(01月24日 02時34分の投稿)

41位: # ウイイレのデータ集計自動化してみた!

Python データ解析 エンジニア eスポーツ ウイイレ
3いいね
@junya0001000さん(01月23日 12時44分の投稿)

42位: Pythonで、デザインパターン「Flyweight」を学ぶ

Python デザインパターン GoF
3いいね
@ttsuboさん(01月23日 00時05分の投稿)

43位: Python3でLeap Motion

Python LeapMotion Python3
3いいね
@issakussさん(01月22日 02時55分の投稿)

44位: Python命名規則(PEP8より)

Python Python3 命名規則 PEP8
3いいね
@shiracamusさん(01月21日 07時05分の投稿)

45位: スマートロック「SESAME mini」とRaspberry Pi Zero WHを使ってWeWorkのオフィスの鍵をICカードで解錠/施錠できるようにした

Python NFC RaspberryPi SESAME
3いいね
@hadatunaさん(01月20日 14時53分の投稿)

46位: 新しいData Augmentation? 【GridMix】

Python DeepLearning dataaugmentation CutMix
3いいね
@Kmat67916008さん(01月20日 10時20分の投稿)

47位: Python 3 エンジニア認定基礎試験を受験した感想

Python Python3 資格
3いいね
@tsubamerさん(01月19日 14時07分の投稿)

48位: Kaggle Facial Keypoints Detection

Python 機械学習 データ分析 Kaggle TensorFlow
3いいね
@payaさん(01月19日 06時01分の投稿)

49位: よく使うtmuxコマンド

Python tmux
2いいね
@okamoto441さん(01月25日 09時49分の投稿)

50位: Django--INSTALLED_APPSに関してのソース解析

Python Django
2いいね
@Syoituさん(01月25日 08時20分の投稿)

51位: 10分で分かるpandasその1

Python pandas
2いいね
@eda3さん(01月25日 07時59分の投稿)

52位: Pythonで、デザインパターン「Proxy」を学ぶ

Python デザインパターン GoF
2いいね
@ttsuboさん(01月25日 01時12分の投稿)

53位: パーセプトロンを使って論理演算を実行する

Python numpy
2いいね
@meklickさん(01月24日 04時58分の投稿)

54位: PythonでDiscord

Python discord
2いいね
@yasudaakさん(01月24日 01時31分の投稿)

55位: 畳み込みニューラルネットワーク (CNN)に対する画像の回転・拡大・色などの影響

Python scikit-learn PyTorch
2いいね
@maskot1977さん(01月23日 04時40分の投稿)

56位: 反比例っぽいグラフはどのようにして生まれるのか?

Python DataScience
2いいね
@ground0stateさん(01月22日 16時56分の投稿)

57位: Googleの事前学習済みモデルを利用した一般物体検出(TensorFlow Hub経由)

Python ディープラーニング 画像認識 TensorFlow TensorFlowHub
2いいね
@code0327さん(01月22日 12時26分の投稿)

58位: Flask + LINE Messaging APIでの人工知能LINEボットの作り方

Python Flask 人工知能 GoogleVisionAPI linebot
2いいね
@atomyahさん(01月22日 10時29分の投稿)

59位: 自動でVtuberの配信予定を更新するカレンダーを作ってみた

Python YouTubeAPI Vtuber
2いいね
@shun_1218さん(01月22日 10時24分の投稿)

60位: 精度をちょっぴり落としたら、重みパラメータが信じられない程減らせた 〜 CNNの驚きの結果 〜

Python 深層学習 CNN MLP
2いいね
@jun40vnさん(01月22日 09時16分の投稿)

61位: 字幕から文字抽出してみた(OpenCV:GoogleCloudVisionAPI編)

Python 画像処理 OpenCV 画像認識 OCR
2いいね
@satsukiyaさん(01月22日 09時15分の投稿)

62位: Pythonを用いた基盤地図情報 数値標高データのgeotiff変換

Python GIS 基盤地図情報 DEM
2いいね
@HidKamiyaさん(01月21日 18時22分の投稿)

63位: GCSのファイルをBigQueryにロードするジョブをPythonで実装したメモ

Python BigQuery
2いいね
@munaita_さん(01月21日 09時18分の投稿)

64位: PowershellからPythonの関数を実行(引数の渡し方)

Python PowerShell 初心者
2いいね
@eternさん(01月21日 07時21分の投稿)

65位: numpy 1次元化の処理速度を調べてみた

Python numpy
2いいね
@Takayoshi_Makabeさん(01月21日 06時27分の投稿)

66位: teratailのダウンローダーを作った

Python lxml Python3 teratail Requests
2いいね
@yoshigeさん(01月21日 05時22分の投稿)

67位: pip3ベースでデータサイエンス環境を作るためのDockerfile

Python pip Docker dockerfile pip3
2いいね
@hanonさん(01月20日 16時02分の投稿)

68位: 【Python】周辺化ギブスサンプリングを実装してみた

Python 機械学習 クラスタリング ベイズ推定
2いいね
@isuyaさん(01月20日 15時41分の投稿)

69位: numpyを使って数独を爆速で解いてみる

Python numpy 数独
2いいね
@apissさん(01月20日 15時05分の投稿)

70位: 機械学習でひさ子のギターを自分のギターに持ち替えてもらう -準備編-

Python AWS PyTorch CycleGAN
2いいね
@nozomi254さん(01月20日 11時56分の投稿)

71位: PythonとBigQueryを使って社内向けピアボーナスツール(集計のみ)を作った

Python GoogleAppsScript BigQuery slackbot
2いいね
@hkanamaruさん(01月20日 09時30分の投稿)

72位: OpenCVのSIFTで特徴抽出してみた

Python OpenCV sift feature-engineering
2いいね
@tatsuya11bbsさん(01月20日 05時11分の投稿)

73位: Docker x 可視化がうまくいかずハマったのでまとめてみた!

Python Linux Ubuntu OpenCV Docker
2いいね
@oreyutaroverさん(01月19日 23時55分の投稿)

74位: [Python3 入門 12日目]6章 オブジェクトとクラス(6.3〜6.15)

Python オブジェクト指向 クラス 入門 Python3
2いいね
@Taka20200105さん(01月19日 15時04分の投稿)

75位: 約束された勝利(『趣味 × 機械学習』)

Python Selenium scikit-learn BeautifulSoup randomForest
2いいね
@idenposさん(01月19日 14時25分の投稿)

76位: Flaskアプリをherokuにデプロイ(苦苦々)

Python Heroku Flask エラー
2いいね
@atomyahさん(01月19日 08時46分の投稿)

77位: 66日目 【Kaggle入門】一番カンタンなTitanic予想

Python 初心者 Kaggle
2いいね
@robamimimさん(01月19日 08時22分の投稿)

78位: 【Kaggle】Baseline modelの構築、Pipeline処理

Python scikit-learn Kaggle Pipeline
2いいね
@yuki_edyさん(01月19日 08時21分の投稿)

79位: 【Python】初級者がDjangoのWebアプリケーションを勉強中にトラブルシューティングしたこと

Python Django Python3 トラブルシューティング
2いいね
@dede-20191130さん(01月19日 07時34分の投稿)

80位: 【#3】PythonでMinecraftを作る。~プレイヤーの動きの改善(慣性の概念)と衝突判定~

Python minecraft Python3 ゲーム制作 pyglet
1いいね
@kkent030315さん(01月25日 07時22分の投稿)

81位: ROC曲線とは?なぜ不均衡データ時には使うべきでない? 分かりやすく説明

Python 機械学習 データサイエンス
1いいね
@Hatomugiさん(01月25日 03時57分の投稿)

82位: pd.concat関数におけるsortのwarning

Python pandas
1いいね
@greenteabiscuitさん(01月24日 15時37分の投稿)

83位: [イメージ図付]Nginx+gunicorn+FlaskをDocker化[前編]

Python nginx Flask Docker dockerfile
1いいね
@mintak21さん(01月24日 13時26分の投稿)

84位: 【Python】beautifulsoup4の備忘録

Python Python3 BeautifulSoup beautifulsoup4
1いいね
@c6towerさん(01月24日 10時36分の投稿)

85位: 画像から人物の性別、年齢を推測するLine botを作ってみた

Python AWS lambda ReKognition linebot
1いいね
@ve_sonoさん(01月24日 01時17分の投稿)

86位: Dockerを使って数分でOpenCV&Python環境を構築して試す

Python OpenCV Docker Python3
1いいね
@hashitoさん(01月24日 00時08分の投稿)

87位: 言語処理100本ノック-97(scikit-learn使用):k-meansクラスタリング

Python NLP K-means 言語処理100本ノック クラスタリング
1いいね
@FukuharaYoheiさん(01月23日 20時58分の投稿)

88位: 機械学習③ 活性化関数の紹介・実装

Python numpy 機械学習 ニューラルネットワーク パーセプトロン
1いいね
@squarekzmlviyさん(01月23日 17時34分の投稿)

89位: matplotlibの散布図で連続的に色付けをする

Python 機械学習 matplotlib データサイエンス
1いいね
@hyt-sasakiさん(01月23日 15時11分の投稿)

90位: 時系列データから取り出せる特徴量

Python 時系列解析
1いいね
@ground0stateさん(01月23日 15時04分の投稿)

91位: DockerでHello,World

Python Docker
1いいね
@keita_gawaharaさん(01月23日 11時50分の投稿)

92位: PyKNPでJUMAN++を使ったらValueErrorが出た

Python NLP JUMAN PyKNP
1いいね
@tomoharr24さん(01月23日 09時24分の投稿)

93位: 【備忘録】ExcelからPythonのコードを実行する(xlwings)

Python Excel xlwings
1いいね
@0yanさん(01月23日 09時02分の投稿)

94位: 【Python】 1行でbool値反転 

Python
1いいね
@1_kkikkiさん(01月23日 01時33分の投稿)

95位: RDSとIAMでパスワードレス認証(Python)

Python MySQL AWS RDS AWSLambda
1いいね
@ChaseSanさん(01月23日 00時41分の投稿)

96位: [Python3 入門 14日目]7章 文字列(7.1.1.1〜7.1.1.4)

Python 入門 Python3
1いいね
@Taka20200105さん(01月22日 23時16分の投稿)

97位: numpy.ndarrayとlistの違い(次元,サイズ編)

Python numpy
1いいね
@Malaguenoさん(01月22日 20時04分の投稿)

98位: Jupyter学習ノート_008

Python プログレスバー
1いいね
@dmkd3006さん(01月22日 15時51分の投稿)

99位: SciPy KDTree vs 総当たりベンチマーク

Python scipy KDTree
1いいね
@sitar-harmonicsさん(01月22日 12時12分の投稿)

100位: MacOS Catalina(10.15.2) で、旧OSからアップデートした環境でpython pipがOpenSSLのエラーになる問題の解決法

Python Mac Catalina
1いいね
@ykmnsさん(01月22日 11時24分の投稿)

101位: Reduced Rank Ridge Regression(縮小ランクリッジ回帰)とは?

Python statistics 統計学 線形回帰
1いいね
@sn42さん(01月22日 05時46分の投稿)

102位: 【物体認識2020最前線】Windows10 に Pytorch をインストールして CornerNet-Lite を動かすまでのログ。

Python 物体検出 物体認識 PyTorch CornerNet
1いいね
@goodboy_maxさん(01月22日 04時07分の投稿)

103位: 機械学習① パーセプトロン基礎の基礎

Python numpy 機械学習 パーセプトロン
1いいね
@squarekzmlviyさん(01月22日 03時45分の投稿)

104位: YouTubeAPIを利用して動画をアップロードする

Python YouTube YouTubeAPI
1いいね
@ny7760さん(01月21日 16時25分の投稿)

105位: Python ImageDataGeneratorで画像の水増し

Python 画像処理 ImageProcessing ImageDataGenerator 水増し
1いいね
@seamcarvingさん(01月21日 12時02分の投稿)

106位: 書籍「15Stepで踏破 自然言語処理アプリケーション開発入門」をやってみる - 2章Step04メモ

Python 自然言語処理
1いいね
@meritamaさん(01月21日 09時45分の投稿)

107位: 文字を画像化してslackに投稿 (python slackbot)

Python slackbot
1いいね
@ponchiさん(01月21日 09時25分の投稿)

108位: [Python]メモ帳Twitterを作る(タイムライン表示編)

Python Twitter Python3 Tkinter メモ帳
1いいね
@higuratuさん(01月21日 09時13分の投稿)

109位: MeCabのコスト計算について

Python Windows mecab 自然言語処理
1いいね
@Taka_inputさん(01月21日 08時13分の投稿)

110位: Docker上のFlask + Nginxでコンソールにログを出力する

Python nginx Flask uwsgi Docker
1いいね
@shin1103@githubさん(01月21日 07時20分の投稿)

111位: 今日のpython error: invalid keyword argument for this function

Python error
1いいね
@kaizen_nagoyaさん(01月21日 04時43分の投稿)

112位: 今日のpython error:ModuleNotFoundError: No module named

Python error pip
1いいね
@kaizen_nagoyaさん(01月21日 04時17分の投稿)

113位: 【その設定値をゼロにするなんてとんでもない!】SQSで同じメッセージを複数件受信してしまう

Python AWS Python3 sqs
1いいね
@skokadoさん(01月21日 03時25分の投稿)

114位: pyenvでcondaを入れてActivateできない問題の解決法

Python
1いいね
@osorezugoingさん(01月21日 01時18分の投稿)

115位: 機械学習でひさ子のギターを自分のギターに持ち替えてもらう -実行編-

Python AWS PyTorch CycleGAN
1いいね
@nozomi254さん(01月20日 18時05分の投稿)

116位: 68日目 【Kaggle入門】ランダムフォレストは単純なやつでした。

Python 初心者 Kaggle
1いいね
@robamimimさん(01月20日 14時53分の投稿)

117位: [Python3 入門 13日目]7章 文字列(7.1〜7.1.1.1)

Python 入門 Python3
1いいね
@Taka20200105さん(01月20日 14時43分の投稿)

118位: 学習記録 その25(29日目)

Python 初心者 機械学習
1いいね
@SHUNMTさん(01月20日 12時20分の投稿)

119位: Cythonを使用して、複数ファイルにまたがったPythonコードから実行ファイルを生成(Mac:成功、Linux:失敗、Windows:成功)

Python Cython
1いいね
@kanedaqさん(01月20日 08時35分の投稿)

120位: 【初心者向け】Pythonによる簡単な文書作成

Python ファイル操作
1いいね
@78910jqkさん(01月20日 07時03分の投稿)

121位: C++ で Python を実行 on Visual Studio 2017

Python C++ VisualStudio2017
1いいね
@yusa0827さん(01月20日 06時01分の投稿)

122位: [Rust/Python] 周期境界条件

Python Rust
1いいね
@osanshouoさん(01月20日 03時56分の投稿)

123位: python学習 アウトプット

Python
1いいね
@uuu_kazさん(01月19日 15時25分の投稿)

124位: Windows10 HomeでのDockerを使ったpython環境構築手順メモ

Python Windows 環境構築 Docker
1いいね
@feketerigo210さん(01月19日 14時04分の投稿)

125位: Python学習メモ

Python Python3
1いいね
@Momomo_aiさん(01月19日 11時22分の投稿)

126位: 言語処理100本ノックでPythonに入門

Python 入門 言語処理100本ノック
1いいね
@hi-asanoさん(01月19日 10時00分の投稿)

127位: Pythonで、デザインパターン「Decorator」を学ぶ

Python デザインパターン GoF
1いいね
@ttsuboさん(01月19日 07時54分の投稿)

128位: matplotlib 基礎 / fig と axes の違い

Python matplotlib
1いいね
@wariichiさん(01月19日 07時44分の投稿)

129位: pip環境のdockerでjupyter notebookを使いたかった(opticspy)

Python pip Docker Python3 Jupyter
1いいね
@YamKentaさん(01月19日 06時28分の投稿)

130位: [Pythonでweb開発] queryもredirect

Python HTML
1いいね
@MH-SSCさん(01月19日 05時08分の投稿)

131位: PythonでPDFをラスタライズする

Python PDF pillow
1いいね
@tomboyboyさん(01月19日 03時31分の投稿)

132位: Pythonのsmtplibでメールを送信せずにSMTPのMAIL FROMコマンド、RCPT TOコマンドだけ使いたい

Python smtplib
1いいね
@igarashi_54さん(01月19日 02時50分の投稿)

133位: pandasのピボットテーブル機能を試してみた

Python pandas pivot_table cross_tab
1いいね
@takuya66520126さん(01月19日 02時02分の投稿)

134位: Jupyter Notebook で音声データを HTML の表の中に埋め込んで再生できるようにする

Python Jupyter 音声 Jupyter-notebook
1いいね
@mzmttksさん(01月19日 02時00分の投稿)

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

【Python】Qiita 週間いいね数ランキング【自動更新】

他のタグ

集計期間

01月19日 ~ 01月26日

いいね数ランキング

1位: 0.1は浮動小数点数で正確に表せないのに、printしたときに0.1と表示されるのはなぜか

Python float double 浮動小数点数 計算機
371いいね
@yucatioさん(01月21日 13時30分の投稿)

2位: 【#1】PythonでMinecraftを作る。~下調べと設計~

Java Python minecraft ゲーム制作 LWJGL
211いいね
@kkent030315さん(01月21日 02時33分の投稿)

3位: init.py を省略してはいけない

Python
189いいね
@methaneさん(01月20日 07時31分の投稿)

4位: 英語論文を読みたくない大学生(python)

Python LSTM LexRank 文章生成 colaboratory
153いいね
@7vvXiさん(01月21日 03時08分の投稿)

5位: 自動で背景を削除 remove.bgを再現してみた

Python 画像処理 OpenCV MachineLearning DeepLearning
127いいね
@i708さん(01月20日 08時55分の投稿)

6位: Pytorchでモデル構築するとき、torchsummaryがマジ使える件について

Python model MachineLearning CNN PyTorch
87いいね
@tatsuya11bbsさん(01月21日 07時26分の投稿)

7位: opencv-python画像処理入門

Python OpenCV
80いいね
@studio_haneyaさん(01月22日 15時54分の投稿)

8位: Pythonゴルフテク(AtCoder)

Python AtCoder コードゴルフ
67いいね
@c_r_5さん(01月20日 07時53分の投稿)

9位: MCMCとFiltering実践(視覚的理解と、ターゲット分布の形状に合わせた使い分け)

Python MCMC Finance ParticleFilter bayesian
37いいね
@Spring24さん(01月23日 02時17分の投稿)

10位: Pythonで読み込んだ画像にフィルタをかけるモジュールをC言語で作った

Python C 画像処理
25いいね
@soramimi_jpさん(01月24日 07時44分の投稿)

11位: 3次元の回転をクラスタリングする

Python Quaternion Rotation EulerAngle
18いいね
@yu4uさん(01月23日 13時36分の投稿)

12位: 2020年の開発者が知っておくべき11の必須技能→回答編 → 並べ替え→項目合併(8項目)→内容追記

Python Git Docker 自己評価
13いいね
@kaizen_nagoyaさん(01月22日 02時33分の投稿)

13位: 再帰関数

Python 決定木
12いいね
@hirokuyuさん(01月21日 06時32分の投稿)

14位: ポアソン分布を丁寧に理解してPythonで描画する

Python scipy 統計学 ポアソン分布
10いいね
@g-kさん(01月20日 11時05分の投稿)

15位: blenderのpythonスクリプト入門してみた_その02

Python Blender
9いいね
@muripo_lifeさん(01月24日 16時41分の投稿)

16位: 画像位置合わせ:SIFTから深層学習まで

Python 画像処理 OpenCV DeepLearning レジストレーション
9いいね
@suuungwooさん(01月22日 05時05分の投稿)

17位: 【スターターキット】Scrapy&MariaDB&Django&Dockerでデータ自動収集ボットシステムを構築する

Python Django mariadb Docker Scrapy
9いいね
@Makotunesさん(01月20日 16時17分の投稿)

18位: 太陽系の運動をシミュレーションしてみる

Python rsp 宇宙開発 アドベントカレンダー2020 軌道計算
8いいね
@akatuki97さん(01月25日 11時19分の投稿)

19位: 強化学習 今日から学習

Python
8いいね
@maskot1977さん(01月20日 00時18分の投稿)

20位: GCP初心者がGCEでマイクラサーバを建ててみた話

Python Linux minecraft gcp discord
7いいね
@rodotanさん(01月20日 09時19分の投稿)

21位: pythonによる統計学

Python scipy numpy
6いいね
@kanamae879123さん(01月25日 07時45分の投稿)

22位: PYTHON環境構築するなら絶対に理解しておかないといけない注意点

Python install Python3
6いいね
@oxlunaxoさん(01月22日 00時32分の投稿)

23位: 【#2】PythonでMinecraftを作る。~モデル描画とプレイヤー実装~

Python minecraft ゲーム制作 pyglet Panda3D
5いいね
@kkent030315さん(01月24日 10時28分の投稿)

24位: オンライン周波数解析アプリを作ってみた

Python Django scipy numpy
5いいね
@apple-yagiさん(01月21日 09時15分の投稿)

25位: matplotlibの点の大きさについて

Python matplotlib
5いいね
@maskot1977さん(01月21日 05時10分の投稿)

26位: 『フカシギの数え方』 おねえさんといっしょ:組み合わせ爆発の凄さ

Python Docker graphillion 数え上げ 組み合わせ爆発
5いいね
@kaizen_nagoyaさん(01月21日 02時23分の投稿)

27位: 【Python】ノーヒットノーランを成し遂げたピッチャーの分析をしてみた

Python matplotlib Python3 baseball
4いいね
@yuuuusuke1997さん(01月23日 18時05分の投稿)

28位: DjangoアプリをDocker上に構築しAWS Fargateにデプロイする

Python Django AWS Docker Fargate
4いいね
@keita_gawaharaさん(01月23日 13時05分の投稿)

29位: AI Gaming はじめてみた

Python AI
4いいね
@noyaさん(01月22日 09時23分の投稿)

30位: 2020年 ITカンファレンスまとめ

Ruby Python PHP JavaScript Conference
4いいね
@TaitoAjikiさん(01月20日 15時28分の投稿)

31位: OpenCVでRGBとHSVのヒストグラムを取得する方法

Python OpenCV histogram feature-engineering
4いいね
@tatsuya11bbsさん(01月20日 00時18分の投稿)

32位: pythonでのグラフ描画

Python numpy matplotlib seaborn
3いいね
@kanamae879123さん(01月25日 06時35分の投稿)

33位: Matplotlibでマウスオーバーすると対応する画像を表示させる

Python matplotlib
3いいね
@sage-gitさん(01月24日 14時45分の投稿)

34位: Pythonを使ってインストルメントとボーカルを分けてカラオケ音源をつくりたい

Python DTM DAW
3いいね
@torahikoshinodaさん(01月24日 10時11分の投稿)

35位: いらすとやの画像をドット絵にしたった。(part1)

Python 画像処理 OpenCV いらすとや
3いいね
@satsukiyaさん(01月24日 05時36分の投稿)

36位: 【Django】Django+MySQL+Vue.jsな環境を作るメモ【Python】

Python Django MySQL Vue.js
3いいね
@osakashoさん(01月24日 02時34分の投稿)

37位: # ウイイレのデータ集計自動化してみた!

Python データ解析 エンジニア eスポーツ ウイイレ
3いいね
@junya0001000さん(01月23日 12時44分の投稿)

38位: Pythonで、デザインパターン「Flyweight」を学ぶ

Python デザインパターン GoF
3いいね
@ttsuboさん(01月23日 00時05分の投稿)

39位: Python3でLeap Motion

Python LeapMotion Python3
3いいね
@issakussさん(01月22日 02時55分の投稿)

40位: Python命名規則(PEP8より)

Python Python3 命名規則 PEP8
3いいね
@shiracamusさん(01月21日 07時05分の投稿)

41位: スマートロック「SESAME mini」とRaspberry Pi Zero WHを使ってWeWorkのオフィスの鍵をICカードで解錠/施錠できるようにした

Python NFC RaspberryPi SESAME
3いいね
@hadatunaさん(01月20日 14時53分の投稿)

42位: 新しいData Augmentation? 【GridMix】

Python DeepLearning dataaugmentation CutMix
3いいね
@Kmat67916008さん(01月20日 10時20分の投稿)

43位: pyqtdeployでPythonコンパイル

Python PyQt5 PyInstaller Nuitka pyqtdeploy
2いいね
@dinosauria123さん(01月25日 17時28分の投稿)

44位: Re:ゼロから始める競技プログラミング生活 第1章1『C++しか使えない』

Python C++ 初心者 競技プログラミング 未経験エンジニア
2いいね
@t-o2mtさん(01月25日 16時32分の投稿)

45位: よく使うtmuxコマンド

Python tmux
2いいね
@okamoto441さん(01月25日 09時49分の投稿)

46位: Django--INSTALLED_APPSに関してのソース解析

Python Django
2いいね
@Syoituさん(01月25日 08時20分の投稿)

47位: 10分で分かるpandasその1

Python pandas
2いいね
@eda3さん(01月25日 07時59分の投稿)

48位: Pythonで、デザインパターン「Proxy」を学ぶ

Python デザインパターン GoF
2いいね
@ttsuboさん(01月25日 01時12分の投稿)

49位: パーセプトロンを使って論理演算を実行する

Python numpy
2いいね
@meklickさん(01月24日 04時58分の投稿)

50位: PythonでDiscord

Python discord
2いいね
@yasudaakさん(01月24日 01時31分の投稿)

51位: 畳み込みニューラルネットワーク (CNN)に対する画像の回転・拡大・色などの影響

Python scikit-learn PyTorch
2いいね
@maskot1977さん(01月23日 04時40分の投稿)

52位: 反比例っぽいグラフはどのようにして生まれるのか?

Python DataScience
2いいね
@ground0stateさん(01月22日 16時56分の投稿)

53位: Googleの事前学習済みモデルを利用した一般物体検出(TensorFlow Hub経由)

Python ディープラーニング 画像認識 TensorFlow TensorFlowHub
2いいね
@code0327さん(01月22日 12時26分の投稿)

54位: Flask + LINE Messaging APIでの人工知能LINEボットの作り方

Python Flask 人工知能 GoogleVisionAPI linebot
2いいね
@atomyahさん(01月22日 10時29分の投稿)

55位: 自動でVtuberの配信予定を更新するカレンダーを作ってみた

Python YouTubeAPI Vtuber
2いいね
@shun_1218さん(01月22日 10時24分の投稿)

56位: 精度をちょっぴり落としたら、重みパラメータが信じられない程減らせた 〜 CNNの驚きの結果 〜

Python 深層学習 CNN MLP
2いいね
@jun40vnさん(01月22日 09時16分の投稿)

57位: 字幕から文字抽出してみた(OpenCV:GoogleCloudVisionAPI編)

Python 画像処理 OpenCV 画像認識 OCR
2いいね
@satsukiyaさん(01月22日 09時15分の投稿)

58位: Pythonを用いた基盤地図情報 数値標高データのgeotiff変換

Python GIS 基盤地図情報 DEM
2いいね
@HidKamiyaさん(01月21日 18時22分の投稿)

59位: GCSのファイルをBigQueryにロードするジョブをPythonで実装したメモ

Python BigQuery
2いいね
@munaita_さん(01月21日 09時18分の投稿)

60位: PowershellからPythonの関数を実行(引数の渡し方)

Python PowerShell 初心者
2いいね
@eternさん(01月21日 07時21分の投稿)

61位: numpy 1次元化の処理速度を調べてみた

Python numpy
2いいね
@Takayoshi_Makabeさん(01月21日 06時27分の投稿)

62位: teratailのダウンローダーを作った

Python lxml Python3 teratail Requests
2いいね
@yoshigeさん(01月21日 05時22分の投稿)

63位: pip3ベースでデータサイエンス環境を作るためのDockerfile

Python pip Docker dockerfile pip3
2いいね
@hanonさん(01月20日 16時02分の投稿)

64位: 【Python】周辺化ギブスサンプリングを実装してみた

Python 機械学習 クラスタリング ベイズ推定
2いいね
@isuyaさん(01月20日 15時41分の投稿)

65位: numpyを使って数独を爆速で解いてみる

Python numpy 数独
2いいね
@apissさん(01月20日 15時05分の投稿)

66位: 機械学習でひさ子のギターを自分のギターに持ち替えてもらう -準備編-

Python AWS PyTorch CycleGAN
2いいね
@nozomi254さん(01月20日 11時56分の投稿)

67位: PythonとBigQueryを使って社内向けピアボーナスツール(集計のみ)を作った

Python GoogleAppsScript BigQuery slackbot
2いいね
@hkanamaruさん(01月20日 09時30分の投稿)

68位: OpenCVのSIFTで特徴抽出してみた

Python OpenCV sift feature-engineering
2いいね
@tatsuya11bbsさん(01月20日 05時11分の投稿)

69位: 自分を大蛇丸と信じて止まない一般男性が、ウマになる関数を作って優勝する投稿です。

Python
1いいね
@schrosisさん(01月25日 16時58分の投稿)

70位: HerokuにFlaskアプリをデプロイする

Python Heroku Flask
1いいね
@redpandaさん(01月25日 15時14分の投稿)

71位: 【Python】Qiita 週間いいね数ランキング【自動更新】

Python
1いいね
@kou_pg_0131さん(01月25日 14時07分の投稿)

72位: 【#3】PythonでMinecraftを作る。~プレイヤーの動きの改善(慣性の概念)と衝突判定~

Python minecraft Python3 ゲーム制作 pyglet
1いいね
@kkent030315さん(01月25日 07時22分の投稿)

73位: PyTorchでDatasetの読み込みを実装してみた

Python 機械学習 DeepLearning PyTorch
1いいね
@kumonkさん(01月25日 06時30分の投稿)

74位: ROC曲線とは?なぜ不均衡データ時には使うべきでない? 分かりやすく説明

Python 機械学習 データサイエンス
1いいね
@Hatomugiさん(01月25日 03時57分の投稿)

75位: pd.concat関数におけるsortのwarning

Python pandas
1いいね
@greenteabiscuitさん(01月24日 15時37分の投稿)

76位: [イメージ図付]Nginx+gunicorn+FlaskをDocker化[前編]

Python nginx Flask Docker dockerfile
1いいね
@mintak21さん(01月24日 13時26分の投稿)

77位: 【Python】beautifulsoup4の備忘録

Python Python3 BeautifulSoup beautifulsoup4
1いいね
@c6towerさん(01月24日 10時36分の投稿)

78位: 画像から人物の性別、年齢を推測するLine botを作ってみた

Python AWS lambda ReKognition linebot
1いいね
@ve_sonoさん(01月24日 01時17分の投稿)

79位: Dockerを使って数分でOpenCV&Python環境を構築して試す

Python OpenCV Docker Python3
1いいね
@hashitoさん(01月24日 00時08分の投稿)

80位: 言語処理100本ノック-97(scikit-learn使用):k-meansクラスタリング

Python NLP K-means 言語処理100本ノック クラスタリング
1いいね
@FukuharaYoheiさん(01月23日 20時58分の投稿)

81位: 機械学習③ 活性化関数の紹介・実装

Python numpy 機械学習 ニューラルネットワーク パーセプトロン
1いいね
@squarekzmlviyさん(01月23日 17時34分の投稿)

82位: matplotlibの散布図で連続的に色付けをする

Python 機械学習 matplotlib データサイエンス
1いいね
@hyt-sasakiさん(01月23日 15時11分の投稿)

83位: 時系列データから取り出せる特徴量

Python 時系列解析
1いいね
@ground0stateさん(01月23日 15時04分の投稿)

84位: DockerでHello,World

Python Docker
1いいね
@keita_gawaharaさん(01月23日 11時50分の投稿)

85位: PyKNPでJUMAN++を使ったらValueErrorが出た

Python NLP JUMAN PyKNP
1いいね
@tomoharr24さん(01月23日 09時24分の投稿)

86位: 【備忘録】ExcelからPythonのコードを実行する(xlwings)

Python Excel xlwings
1いいね
@0yanさん(01月23日 09時02分の投稿)

87位: 【Python】 1行でbool値反転 

Python
1いいね
@1_kkikkiさん(01月23日 01時33分の投稿)

88位: RDSとIAMでパスワードレス認証(Python)

Python MySQL AWS RDS AWSLambda
1いいね
@ChaseSanさん(01月23日 00時41分の投稿)

89位: [Python3 入門 14日目]7章 文字列(7.1.1.1〜7.1.1.4)

Python 入門 Python3
1いいね
@Taka20200105さん(01月22日 23時16分の投稿)

90位: numpy.ndarrayとlistの違い(次元,サイズ編)

Python numpy
1いいね
@Malaguenoさん(01月22日 20時04分の投稿)

91位: Jupyter学習ノート_008

Python プログレスバー
1いいね
@dmkd3006さん(01月22日 15時51分の投稿)

92位: SciPy KDTree vs 総当たりベンチマーク

Python scipy KDTree
1いいね
@sitar-harmonicsさん(01月22日 12時12分の投稿)

93位: MacOS Catalina(10.15.2) で、旧OSからアップデートした環境でpython pipがOpenSSLのエラーになる問題の解決法

Python Mac Catalina
1いいね
@ykmnsさん(01月22日 11時24分の投稿)

94位: Reduced Rank Ridge Regression(縮小ランクリッジ回帰)とは?

Python statistics 統計学 線形回帰
1いいね
@sn42さん(01月22日 05時46分の投稿)

95位: 【物体認識2020最前線】Windows10 に Pytorch をインストールして CornerNet-Lite を動かすまでのログ。

Python 物体検出 物体認識 PyTorch CornerNet
1いいね
@goodboy_maxさん(01月22日 04時07分の投稿)

96位: 機械学習① パーセプトロン基礎の基礎

Python numpy 機械学習 パーセプトロン
1いいね
@squarekzmlviyさん(01月22日 03時45分の投稿)

97位: YouTubeAPIを利用して動画をアップロードする

Python YouTube YouTubeAPI
1いいね
@ny7760さん(01月21日 16時25分の投稿)

98位: Python 画像水増し入門 ImageDataGeneratorを用いた画像水増し

Python 画像処理 ImageProcessing ImageDataGenerator 水増し
1いいね
@seamcarvingさん(01月21日 12時02分の投稿)

99位: 書籍「15Stepで踏破 自然言語処理アプリケーション開発入門」をやってみる - 2章Step04メモ

Python 自然言語処理
1いいね
@meritamaさん(01月21日 09時45分の投稿)

100位: 文字を画像化してslackに投稿 (python slackbot)

Python slackbot
1いいね
@ponchiさん(01月21日 09時25分の投稿)

101位: [Python]メモ帳Twitterを作る(タイムライン表示編)

Python Twitter Python3 Tkinter メモ帳
1いいね
@higuratuさん(01月21日 09時13分の投稿)

102位: MeCabのコスト計算について

Python Windows mecab 自然言語処理
1いいね
@Taka_inputさん(01月21日 08時13分の投稿)

103位: Docker上のFlask + Nginxでコンソールにログを出力する

Python nginx Flask uwsgi Docker
1いいね
@shin1103@githubさん(01月21日 07時20分の投稿)

104位: 今日のpython error: invalid keyword argument for this function

Python error
1いいね
@kaizen_nagoyaさん(01月21日 04時43分の投稿)

105位: 今日のpython error:ModuleNotFoundError: No module named

Python error pip
1いいね
@kaizen_nagoyaさん(01月21日 04時17分の投稿)

106位: 【その設定値をゼロにするなんてとんでもない!】SQSで同じメッセージを複数件受信してしまう

Python AWS Python3 sqs
1いいね
@skokadoさん(01月21日 03時25分の投稿)

107位: pyenvでcondaを入れてActivateできない問題の解決法

Python
1いいね
@osorezugoingさん(01月21日 01時18分の投稿)

108位: 機械学習でひさ子のギターを自分のギターに持ち替えてもらう -実行編-

Python AWS PyTorch CycleGAN
1いいね
@nozomi254さん(01月20日 18時05分の投稿)

109位: 68日目 【Kaggle入門】ランダムフォレストは単純なやつでした。

Python 初心者 Kaggle
1いいね
@robamimimさん(01月20日 14時53分の投稿)

110位: [Python3 入門 13日目]7章 文字列(7.1〜7.1.1.1)

Python 入門 Python3
1いいね
@Taka20200105さん(01月20日 14時43分の投稿)

111位: 学習記録 その25(29日目)

Python 初心者 機械学習
1いいね
@SHUNMTさん(01月20日 12時20分の投稿)

112位: Cythonを使用して、複数ファイルにまたがったPythonコードから実行ファイルを生成(Mac:成功、Linux:失敗、Windows:成功)

Python Cython
1いいね
@kanedaqさん(01月20日 08時35分の投稿)

113位: 【初心者向け】Pythonによる簡単な文書作成

Python ファイル操作
1いいね
@78910jqkさん(01月20日 07時03分の投稿)

114位: C++ で Python を実行 on Visual Studio 2017

Python C++ VisualStudio2017
1いいね
@yusa0827さん(01月20日 06時01分の投稿)

115位: [Rust/Python] 周期境界条件

Python Rust
1いいね
@osanshouoさん(01月20日 03時56分の投稿)

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

[Python3 入門 15日目]7章 文字列(7.1.2〜7.1.2.2)

7.1.2 書式指定

7.1.2.1 %を使ったスタイル

  • 古いスタイルの書式設定は string % dataという形式を使う。
  • %と型指定子の間には、幅の上限、文字数の上限、配置、パディングを指定できる。
#文字列
>>> "%s" % 42
`42`
#10進整数
>>> "%d" % 42
`42`
#16進整数
>>> "%x" % 42
`2a`
#8進整数
>>> "%o" % 42
`52`

#10進float
>>> "%f" % 7.03
`7.030000`
#指数形式float
>>> "%e" % 7.03
`7.030000e+00`
#桁の大きさによって変わる%g (10進floatまたは指数形式float)
>>> "%g" % 7.03
`7.03`
#整数とリテラルの%
>>> "%d%%" % 100
`100%`

>>> actor = "Richard Gere"
>>> cat="Chester"
>>> weight=28
#文字列の挿入
>>> "My wife is favorite actor is %s" % actor
`My wife is favorite actor is Richard Gere`
#複数の文字列挿入時は(cat,weight)のようにタプルにまとめなければならない。
>>> "Our cat %s weights %s pounds" % (cat,weight)
'Our cat Chester weights 28 pounds'

>>> n = 42
>>> f=7.03
>>> s="string cheese"
#デフォルト幅で表示。
>>> "%s %f %s" %(n,f,s)
'42 7.030000 string cheese'
#各変数について最小限の幅10を設定し、右揃えにした。
>>> "%10s %10f %10s" %(n,f,s)
'        42   7.030000 string cheese'
#同じ幅を使って左揃えにした。
>>> "%-10s %-10f %-10s" %(n,f,s)
'42         7.030000   string cheese'
#フィールドの幅は同じで文字数の上限を4にして右揃えにする。こうすると文字列が一部切り捨てられ、小数点以下が4桁になる。
>>> "%10.4d %10.4f %10.4s" %(n,f,s)
'      0042     7.0300       stri'
#フィールド幅の下限を指定せず、字数制限を行う。
>>> "%.4d %.4f %.4s" %(n,f,s)
'0042 7.0300 stri'
#フィールド幅と文字数の*による引数化
>>> "%*.*d %*.*f %*.*s" %(10,4,n,10,4,f,10,4,s)
'      0042     7.0300       stri'

7.1.2.2 {}と書式指定を使った新しいスタイル

>>> "{} {} {}".format(n,f,s)
`42 7.03 string cheese`

#{}の中の数字はformatの中のインデックスを示している。
>>> "{2} {0} {1}".format(n,f,s)
`string cheese 42 7.03`

#引数は辞書やキーワード引数でも良い。そして、書式指定にキー、名前を入れることも可能。
>>> "{n} {f} {s}".format(n=42,f=7.03,s="string cheese")
`42 7.03 string cheese`


>>> d={"n":42,"f":7.03,"s":"string cheese"}
#{0}はformat()の中の引数dという辞書を指す。
#{2}はformat()の中の引数otherという文字列を指す。
>>> "{0[n]} {0[f]} {0[s]} {1}".format(d,"other")
`42 7.03 string cheese other`

#%の代わりに:を使える。
>>> "{0:d} {1:f} {2:s}".format(n,f,s)
`42 7.030000 string cheese`
#キーワード引数で指定
>>> "{n:d} {f:f} {s:s}".format(n=42,f=7.03,s="string cheese")
`42 7.030000 string cheese`
#フィールド幅の下限を10としてデフォルトの右揃え。
>>> "{0:10d} {1:10f} {2:10s}".format(n,f,s)
`        42   7.030000 string cheese`
#上と同じ右揃えだが、>を使う分わかりやすくなっている。
>>> "{0:>10d} {1:>10f} {2:>10s}".format(n,f,s)
`        42   7.030000 string cheese`
#左揃え
>>> "{0:<10d} {1:<10f} {2:<10s}".format(n,f,s)
`42         7.030000   string cheese`

#中央揃え
>>> "{0:^10d} {1:^10f} {2:^10s}".format(n,f,s)
`    42      7.030000  string cheese`

#古いスタイルと異なり、小数点の後ろで指定する精度はfloatなら小数点以下の桁数、文字列なら文字数の上限を指定するが整数では使えなくなった。
>>> "{0:>10.4d} {1:>10.4f} {2:>10.4s}".format(n,f,s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Precision not allowed in integer format specifier
>>> "{0:>10d} {1:>10.4f} {2:>10.4s}".format(n,f,s)
`        42     7.0300       stri`

#:の直後、位置揃えや幅の指定の前に指定することで出力フィールドの隙間部分をスペース以外の文字で埋めることができる。
>>> "{0:!^20s}".format("BIG SALE")
`!!!!!!BIG SALE!!!!!!`

感想

最近更新頻度が空いてきましたね。
投稿サボり気味でした。。。

勉強の方ですが、8章のデータベース関連にかなり苦戦しております。データベースの話が抽象的でなかなか頭に入ってこないは、本通りに進めているのにエラー出るわでめげそうでしたね。
明日はもう一度時間をかけて8章やってみます。
7章の続きは明日投稿する。

参考文献

「Bill Lubanovic著 『入門 Python3』(オライリージャパン発行)」

「Pythonチュートリアル 3.8.1ドキュメント」
https://docs.python.org/ja/3/howto/unicode.html

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

書籍「15Stepで踏破 自然言語処理アプリケーション開発入門」をやってみる - 2章Step07メモ

内容

15stepで踏破 自然言語処理アプリケーション入門 を読み進めていくにあたっての自分用のメモです。
今回は2章Step07で、自分なりのポイントをメモります。

準備

  • 個人用MacPC:MacOS Mojave バージョン10.14.6
  • docker version:Client, Server共にバージョン19.03.2

章の概要

  • 機械学習システムの予測精度を様々な指標で定量評価する
    • 既存のシステムに改良を加える場合に、かえって性能低下を起こしていないことを評価によって保証し、安心してシステムをアップデートできる
  • 過学習について理解し、発生を防ぐ

07.1 学習データとテストデータ、そして過学習と汎化

学習によって、識別器が学習データに対して過剰に適合してしまうことを過学習と呼ぶ。

学習データに含まれる特徴ベクトルを100%識別できるようにすると、無視しても良いノイズまでも正しく識別できるように細かい識別面になってしまう。
学習データ以外に対しても安定して予測が行えるようになることを汎化と呼ぶ。

学習と評価で同じデータを使うと、過学習したシステムを高く評価してしまうことになるので、評価用のテストデータは学習データと違うものを使って評価しなければならない
(いくら学習データで良い精度が出てもあまり意味がないし、過学習していないことも確認しなければいけない)

07.2 評価指標

項目 内容
Accuracy(正解率) 全テストデータに対する正解テストデータの割合
Precision(適合率) 対象クラスに予測したテストデータのうち、正解テストデータの割合
Recall(再現率) 対象クラスのテストデータを正しく予測できた割合
F値 PrecisionとRecallのバランスを表した指標

実装

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

accuracy_score(y_true, y_pred)
precision_score(y_true, y_pred)
recall_score(y_true, y_pred)
f1_score(y_true, y_pred, average='macro')
  • averageを指定することで、マクロ平均='macro'やマイクロ平均='micro'を算出できる
  • precisionとrecallはトレードオフの関係

07.3 評価の際の注意点

項目 内容
精度の下限 精度の下限は当てずっぽうに予測した場合である
分類クラスの数 2クラス分類より多クラス分類の方が難易度は当然高いので、評価指標はアプリケーションによって値は異なる
テストデータの種類 色々なシステムを相対評価する場合、同一のテストデータで実施すべきである
データ数の偏り テストデータには各クラスのデータがなるべく均等に含まれるようにするのが望ましい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【質問】Pythonでのエクセルシートの印刷枚数について

こんばんは。私は製造業で働いているノンプログロマで、Pythonに関しては入門書を一冊読んだレベルです。

現在、手書きの作業を自動化するプログラムをpythonで組もうとしています。

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

テスト投稿

こんばんは。私は製造業で働いているノンプログロマで、Pythonに関しては入門書を一冊読んだレベルです。

現在、手書きの作業を自動化するプログラムをpythonで組もうとしています。

pythonで作成途中ですが、印刷過程で意図せぬ枚数が印刷されます。

この問題が解決できない時はVBA等他選択肢も視野に入れようと思います。

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

初めて全力で取り組んだ機械学習コンペを振り返る

はじめに

先日、とある機械学習コンペに参加した。週末を何度もつぶす程全力でやってみた。その結果、入賞には至らなかったものの上位3%に入ることができ、自信につながった。まだまだコンペ経験が少ないため、今後考えが変わるかもしれないが、まずは現時点でこの経験を振り返り、メモとして残しておく。

参加の動機

機械学習については本を読んだり動画を見たりして勉強はしているものの、自分のスキルがどの程度か客観的に知りたいと思ったため。

前提

コンペの内容は詳しくは言えないが、テーブルコンペである。以下の戦闘環境で戦った。

ハードウェア(1台)

  • CPU i7-8700 3.70GHz
  • メモリ 16GB
  • GPU NVIDIA GetForce GTX 1060 6G

ソフトウェア

  • Windows 10
  • Python 3.6
  • scikit-learn 0.21.2
  • tensorflow 1.13.2
  • keras 2.3.1
  • xgboost 0.9
  • lightgbm, catboost etc..
  • PyCharm(開発環境)

振り返り

機械学習手法については素晴らしい本がたくさんあるため、ここでは実際に自分がコンペに取り込んでみて感じた泥臭いことを列挙してみたい。

作成したスクリプト

コンペを戦うにあたり特徴選択と予測モデル作成の2つの作業については、汎用性の高いコマンドラインスクリプトを作成し、他(可視化やちょっとした前処理など)は使い捨てのコマンドで対応した。例えば予測モデル作成については、学習アルゴリズムの選択、乱数シード、クロスバリデーション数など可能な限り、引数で指定できるようにした。また、新しいアルゴリズムが追加になっても最小限の修正で追加できる作りとした。これにより、自分のやりたいことをコマンドの引数を変えるだけで変更できたり、バッチでまとめて流したりすることができ、生産性を高めることができたと考えている。

再現性

コンペでは入賞して賞金等をもらう場合に、モデルの作成や予測について再現できるスクリプトを提供が義務づけられていることが多い(と思う)。スコアがあがって入賞が見えてきたときに初めて再現方法を調べるようでは、かなりの手戻りになる可能性がある。このため、できるだけ早い段階で再現性を担保する方法を確立しておく必要がある。結果にランダム性が入るアルゴリズムには、"random_state" のようなパラメータがあることが多いので、それを調べて指定する等心掛けた。もっともGPUで計算した場合、固定させることが難しいようだ(今回、GPUはKerasだけの利用だったため、あまり深く調べなかった)。

乱数シードを固定させる対象は以下が考えられる。

  • Boruta等の各特徴選択アルゴリズム
  • Random ForestやXGBoost等の各機械学習アルゴリズム
  • クロスバリデーション時の分割処理

ログ

ある特徴選択手法の結果を使って、そこそこよい結果が得られたのだが、最初の特徴選択をどうやって作成したか分からなくなり、結局1からやり直したことがあった。こんなことがないよう、各スクリプトではログを残しておくことが重要になる。

以下全てを実装したわけではないが、今振り返ってみると、ログに残すべきものとして以下が考えられる。

  • 実行したスクリプトそのもの(これはスクリプトの修正が頻繁にあるため)
  • スクリプトへの入力情報。例えば予測モデル作成の場合、以下のものが考えられる。
    • 入力ファイルパス
    • 出力ファイルパス
    • 予測アルゴリズム
    • クロスバリデーションの手法、分割数、評価指標
    • ハイパーパラメータの探索手法、探索範囲など
    • 乱数シード
  • スクリプトの実行状況。例えば予測モデル作成の場合、グリッドサーチの途中経過等になる。これは途中でやめてパラメータ探索範囲を見直すかどうか等の判断にも非常に役に立つ。

特徴選択等、他のスクリプトも同様である。なお、ログは1つのファイルである必要はなく、1つの実行あたり1つの出力フォルダ作成し、その下に予測結果も含め、複数の種類のログファイルを出力すれば十分である。

時間を有効に使う

特徴選択のBorutaは、コンペのデータでは500イテレーションで丸1日かかった。結果によっては何度かやり直すこともあった。Borutaを何も指定せずに実行するとCPUを占有してしまい他の作業が一切できなくなることがある。このようにCPUを占有する処理の場合、引数が用意されている場合、CPU数を明示的に指定することで、他の作業の余地を残しておく。こうすることでBoruta実行中にも、他の作業(例えば別の特徴選択結果でハイパーパラメータの探索を行うなど)ができ、時間を有効に活用することができる。

予測アルゴリズムの実行速度を考慮する

今回は複数の予測アルゴリズムの出力結果を組み合わせて、最終的な予測モデルを作成するというアンサンブル学習で精度をあげることができた。アンサンブル学習では、組み合わせるものの多様性が高い程、精度があがるとされている。今回はスクリプトを汎用的に作成し、様々な予測アルゴリズムを追加することができたため、可能な限りのアルゴリズムを組み合わせた。各アルゴリズムの速度について、感覚になるが以下の通りだった。

  • LightGBM, DeepLearng(Kearas)はかなり高速であり、他手法が苦戦する中、特徴選択しないデータでもかなり高速であった。
  • XGB、CatBoostやExtra Treeもまずまずの速度であった。
  • 線形手法(PLSやExtraNet等)は単純なアルゴリズムなためか、比較的速い。
  • Support Vector Machine, Random Forestは非常に遅かった。

時間がかかるということは、パラメータ探索の組み合わせが多いと、その組み合わせの分さらに時間を要するということである。このようなことから、特徴選択をせずに使うアルゴリズム、特徴選択をした上で使うアルゴリズムを使い分けた。これによって各予測アルゴリズムの高精度のモデルを効率よく探すことができたと考えている。

クロスバリデーションを信じる

コンペの終盤、クロスバリデーションのスコアは上がるにもかかわらず、パブリックテストのスコアが上がらないという状態に見舞われた。色々悩んだが、コンペ終了時に公表される全データによるパブリックテストでは、クロスバリデーションとほぼ同じ結果になった。結局のところ、信頼できると思える評価方法を見つけたら、それを信じて精度を上げることに専念することが大切なのだと分かった。

見切りをつける

コンペ中は、色々頑張った割に効果がないこともある。例えば今回遺伝的プログラミングによる特徴量生成は全く効果がなかった(やり方の問題かもしれないが)。原因も全く思いつかなかった。こんな時はさっさと見切りをつけて、それまでに効果があったこと(今回でいえばアンサンブル学習)をつきつめてやることも重要だと思う。

おわりに

振り返ってみると当たり前のことしか書いてない気がするが、これが現在の自分のレベルということだろう。

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

PC環境でInference Engine Python APIを使ったOpenVINO

概要

こちらのサイトにRaspberry Pi と Neural Compute Stick を使ったOpenVINOでのPython APIコードのチュートリアルが書いてありますが、PCのみの環境で行う場合には少し変更や追加が必要なので、そのメモを書きます。
image.png
画像引用元:OpenVINO™ でゼロから学ぶディープラーニング推論

必要なのは以下3つの項目です

  • ターゲットデバイスの変更
  • FP16をFP32へ変更
  • ライブラリ読込みの追加

ターゲットデバイスの変更

Neural Compute Stickを意味する MYRAID から CPU に変更するだけ。これは簡単。

# 変更前
plugin = IEPlugin(device="MYRIAD")
# 変更後
plugin = IEPlugin(device="CPU")

FP16をFP32へ変更

学習済みモデル(xmlファイルとbinファイル)をFP16からFP32に変更します
例えば、OpenVINO 2019_R3.1用のface-detection-retail-0004であれば、以下のサイトのFP32からダウンロードすればOK
Intel Open Source Technology Center

ちなみに、FP16のままでも動作する場合がありますが、FP32が推奨なので変更した方が良いでしょう
image.png
画像引用元:Intel OpenVINO™ TOOLKIT公式サイト

ライブラリ読込み追加

使用する学習済みモデルにもよりますが、以下のようなエラーが発生する場合があります(顔認識など)

Traceback (most recent call last):
  File "XXXXXXXX.py", line XXX, in <module>
    exec_net = plugin.load(network=net)
  File "ie_api.pyx", line 547, in openvino.inference_engine.ie_api.IEPlugin.load
  File "ie_api.pyx", line 557, in openvino.inference_engine.ie_api.IEPlugin.load
RuntimeError: Unsupported primitive of type: PriorBoxClustered name: fc7_mbox_priorbox

対応としてCPU Extensionsライブラリ読込みの追加が必要です。
OSやCPUでパスやファイル名が異なるので、色々試してみて下さい。

Windows10(Intel Coreプロセッサ)の例

# ターゲットデバイス指定の下に追加
plugin.add_cpu_extension("C:/Program Files (x86)/IntelSWTools/openvino/deployment_tools/inference_engine/bin/intel64/Release/cpu_extension_avx2.dll")

※上記でダメな場合は cpu_extension.dll を検索してフルパスで指定してみてください

Linux(Intel Atomプロセッサ)の例

# ターゲットデバイス指定の下に追加
plugin.add_cpu_extension('/opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension_sse4.so')

※Intel Coreプロセッサの場合は libcpu_extension_avx2.so に置き換えてみて下さい

Macの例

# ターゲットデバイス指定の下に追加
plugin.add_cpu_extension('/opt/intel/openvino/deployment_tools/inference_engine/lib/intel64/libcpu_extension.dylib')

これでPCさえあれば、無料でディープラーニング推論が出来ますね! では、また。

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

Tkinter事始め

はじめに

  • tkinterの使い方を調べた備忘録です。

経緯

a-simple-hello-world-program.py
import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.pack()
        self.create_widgets()

    def create_widgets(self):
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Hello World\n(click me)"
        self.hi_there["command"] = self.say_hi
        self.hi_there.pack(side="top")

        self.quit = tk.Button(self, text="QUIT", fg="red",
                              command=self.master.destroy)
        self.quit.pack(side="bottom")

    def say_hi(self):
        print("hi there, everyone!")

root = tk.Tk()
app = Application(master=root)
app.mainloop()

環境

  • Windows10
  • python3.8.0

最初の一歩

  • ウィンドウが開くだけの最小プログラム
main.py
import tkinter as tk

root = tk.Tk()
root.mainloop()

実行結果

tk1.png

疑問に思った点

Q. 何故 root なのでしょうか?

_root()
import tkinter as tk

root = tk.Tk()
print(root._root()) # .(ドット)が表示される
print(type(root.master), type(root)) # Class: NoneType, tkinter.Tk

Q. tk.Tk() は必要なのでしょうか?

Hello World!?

  • ウィンドウのタイトルを変更
main.py
import tkinter as tk

root = tk.Tk()
root.title('Hello World!')
root.mainloop()

実行結果

tk2.png

Hello World!

  • ウィンドウのサイズを変更
main.py
import tkinter as tk

root = tk.Tk()
root.title('Hello World!')
root.geometry('400x200')
root.mainloop()

実行結果

tk3.png

tkinter.Frameを継承したクラスでアプリを生成

  • ラベルを第一引数を変えて生成
    • self.master
    • self
    • 引数なし
App.py
import tkinter as tk

class App(tk.Frame):
    def __init__(self, title="tk", *, width="300", height="200"):
        super().__init__()
        self.master.title(title)
        self.master.geometry(f'{width}x{height}')
        self.master.maxsize(self.master.winfo_screenwidth()-100, self.master.winfo_screenheight()-100)
        self.create_widgets()
        self.pack()

    def create_widgets(self):
        self.l1 = tk.Label(self.master, text='Hello World1!', fg='red', bg='pink') # .!label
        self.l1.pack()

        self.l2 = tk.Label(self, text='Hello World2!', fg='green', bg='greenyellow') # .!app.!label
        self.l2.pack()

        self.l3 = tk.Label(text='Hello World3!', fg='blue', bg='aqua') # .!label2
        self.l3.pack()


if __name__ == '__main__':
    myapp = App("Hello WM")
    myapp.mainloop()

実行結果

tk4.png

なるほどな点

  • ラベルの生える場所が変わっている
  • Tkクラス=土台,App(Frame)クラス=枠
    • こんな感じのイメージ

tk5.png

まとめ

  • tk.Tk()は明示的に書かなくても良かった。
  • 公式のチュートリアルが、何故rootを渡すのか意図はわからず仕舞い。
App.py
import tkinter as tk

class App(tk.Frame):
    def __init__(self, title='tk', *, width='300', height='200'):
        super().__init__()
        self.master.title(title)
        self.master.geometry(f'{width}x{height}')
        self.master.maxsize(self.master.winfo_screenwidth()-100, self.master.winfo_screenheight()-100)
        self.create_widgets()
        self.pack()

    def create_widgets(self):
        self.l1 = tk.Label(self.master, text='Hello World1!', fg='red', bg='pink')
        self.l1.pack()

        self.l2 = tk.Label(self, text='Hello World2!', fg='green', bg='greenyellow')
        self.l2.pack()

        self.l3 = tk.Label(text='Hello World3!', fg='blue', bg='aqua')
        self.l3.pack()

        self.btn1 = tk.Button(self)
        self.btn1['text'] = 'Click(hello)'
        self.btn1['command'] = self.hello
        self.btn1.pack(side='top')

        self.quit = tk.Button(self, text='Quit', fg='red', command=self.master.destroy)
        self.quit.pack(side='bottom')

    def hello(self):
        print('Hello World!')


if __name__ == '__main__':
    myapp = App("Hello WM")
    myapp.mainloop()

参考情報

tkinter


__init__.pyソースコード
__init__.py
import enum
import sys

import _tkinter # If this fails your Python may not be configured for Tk
TclError = _tkinter.TclError
from tkinter.constants import *
import re


wantobjects = 1

TkVersion = float(_tkinter.TK_VERSION)
TclVersion = float(_tkinter.TCL_VERSION)

READABLE = _tkinter.READABLE
WRITABLE = _tkinter.WRITABLE
EXCEPTION = _tkinter.EXCEPTION


_magic_re = re.compile(r'([\\{}])')
_space_re = re.compile(r'([\s])', re.ASCII)


def _join(value):
    return ' '.join(map(_stringify, value))


def _stringify(value):
    if isinstance(value, (list, tuple)):
        if len(value) == 1:
            value = _stringify(value[0])
            if _magic_re.search(value):
                value = '{%s}' % value
        else:
            value = '{%s}' % _join(value)
    else:
        value = str(value)
        if not value:
            value = '{}'
        elif _magic_re.search(value):
            # add '\' before special characters and spaces
            value = _magic_re.sub(r'\\\1', value)
            value = value.replace('\n', r'\n')
            value = _space_re.sub(r'\\\1', value)
            if value[0] == '"':
                value = '\\' + value
        elif value[0] == '"' or _space_re.search(value):
            value = '{%s}' % value
    return value


def _flatten(seq):
    res = ()
    for item in seq:
        if isinstance(item, (tuple, list)):
            res = res + _flatten(item)
        elif item is not None:
            res = res + (item,)
    return res


try: _flatten = _tkinter._flatten
except AttributeError: pass


def _cnfmerge(cnfs):
    if isinstance(cnfs, dict):
        return cnfs
    elif isinstance(cnfs, (type(None), str)):
        return cnfs
    else:
        cnf = {}
        for c in _flatten(cnfs):
            try:
                cnf.update(c)
            except (AttributeError, TypeError) as msg:
                print("_cnfmerge: fallback due to:", msg)
                for k, v in c.items():
                    cnf[k] = v
        return cnf


try: _cnfmerge = _tkinter._cnfmerge
except AttributeError: pass


def _splitdict(tk, v, cut_minus=True, conv=None):
    t = tk.splitlist(v)
    if len(t) % 2:
        raise RuntimeError('Tcl list representing a dict is expected '
                           'to contain an even number of elements')
    it = iter(t)
    dict = {}
    for key, value in zip(it, it):
        key = str(key)
        if cut_minus and key[0] == '-':
            key = key[1:]
        if conv:
            value = conv(value)
        dict[key] = value
    return dict


class EventType(str, enum.Enum):
    KeyPress = '2'
    Key = KeyPress,
    KeyRelease = '3'
    ButtonPress = '4'
    Button = ButtonPress,
    ButtonRelease = '5'
    Motion = '6'
    Enter = '7'
    Leave = '8'
    FocusIn = '9'
    FocusOut = '10'
    Keymap = '11'           # undocumented
    Expose = '12'
    GraphicsExpose = '13'   # undocumented
    NoExpose = '14'         # undocumented
    Visibility = '15'
    Create = '16'
    Destroy = '17'
    Unmap = '18'
    Map = '19'
    MapRequest = '20'
    Reparent = '21'
    Configure = '22'
    ConfigureRequest = '23'
    Gravity = '24'
    ResizeRequest = '25'
    Circulate = '26'
    CirculateRequest = '27'
    Property = '28'
    SelectionClear = '29'   # undocumented
    SelectionRequest = '30' # undocumented
    Selection = '31'        # undocumented
    Colormap = '32'
    ClientMessage = '33'    # undocumented
    Mapping = '34'          # undocumented
    VirtualEvent = '35',    # undocumented
    Activate = '36',
    Deactivate = '37',
    MouseWheel = '38',

    def __str__(self):
        return self.name


class Event:
    def __repr__(self):
        attrs = {k: v for k, v in self.__dict__.items() if v != '??'}
        if not self.char:
            del attrs['char']
        elif self.char != '??':
            attrs['char'] = repr(self.char)
        if not getattr(self, 'send_event', True):
            del attrs['send_event']
        if self.state == 0:
            del attrs['state']
        elif isinstance(self.state, int):
            state = self.state
            mods = ('Shift', 'Lock', 'Control',
                    'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5',
                    'Button1', 'Button2', 'Button3', 'Button4', 'Button5')
            s = []
            for i, n in enumerate(mods):
                if state & (1 << i):
                    s.append(n)
            state = state & ~((1<< len(mods)) - 1)
            if state or not s:
                s.append(hex(state))
            attrs['state'] = '|'.join(s)
        if self.delta == 0:
            del attrs['delta']
        keys = ('send_event',
                'state', 'keysym', 'keycode', 'char',
                'num', 'delta', 'focus',
                'x', 'y', 'width', 'height')
        return '<%s event%s>' % (
            self.type,
            ''.join(' %s=%s' % (k, attrs[k]) for k in keys if k in attrs)
        )


_support_default_root = 1
_default_root = None


def NoDefaultRoot():
    global _support_default_root
    _support_default_root = 0
    global _default_root
    _default_root = None
    del _default_root


def _tkerror(err):
    pass


def _exit(code=0):
    try:
        code = int(code)
    except ValueError:
        pass
    raise SystemExit(code)


_varnum = 0


class Variable:
    _default = ""
    _tk = None
    _tclCommands = None

    def __init__(self, master=None, value=None, name=None):
        if name is not None and not isinstance(name, str):
            raise TypeError("name must be a string")
        global _varnum
        if not master:
            master = _default_root
        self._root = master._root()
        self._tk = master.tk
        if name:
            self._name = name
        else:
            self._name = 'PY_VAR' + repr(_varnum)
            _varnum += 1
        if value is not None:
            self.initialize(value)
        elif not self._tk.getboolean(self._tk.call("info", "exists", self._name)):
            self.initialize(self._default)

    def __del__(self):
        if self._tk is None:
            return
        if self._tk.getboolean(self._tk.call("info", "exists", self._name)):
            self._tk.globalunsetvar(self._name)
        if self._tclCommands is not None:
            for name in self._tclCommands:
                #print '- Tkinter: deleted command', name
                self._tk.deletecommand(name)
            self._tclCommands = None

    def __str__(self):
        return self._name

    def set(self, value):
        return self._tk.globalsetvar(self._name, value)

    initialize = set

    def get(self):
        """Return value of variable."""
        return self._tk.globalgetvar(self._name)

    def _register(self, callback):
        f = CallWrapper(callback, None, self._root).__call__
        cbname = repr(id(f))
        try:
            callback = callback.__func__
        except AttributeError:
            pass
        try:
            cbname = cbname + callback.__name__
        except AttributeError:
            pass
        self._tk.createcommand(cbname, f)
        if self._tclCommands is None:
            self._tclCommands = []
        self._tclCommands.append(cbname)
        return cbname

    def trace_add(self, mode, callback):
        cbname = self._register(callback)
        self._tk.call('trace', 'add', 'variable',
                      self._name, mode, (cbname,))
        return cbname

    def trace_remove(self, mode, cbname):
        self._tk.call('trace', 'remove', 'variable',
                      self._name, mode, cbname)
        for m, ca in self.trace_info():
            if self._tk.splitlist(ca)[0] == cbname:
                break
        else:
            self._tk.deletecommand(cbname)
            try:
                self._tclCommands.remove(cbname)
            except ValueError:
                pass

    def trace_info(self):
        splitlist = self._tk.splitlist
        return [(splitlist(k), v) for k, v in map(splitlist,
            splitlist(self._tk.call('trace', 'info', 'variable', self._name)))]

    def trace_variable(self, mode, callback):
        cbname = self._register(callback)
        self._tk.call("trace", "variable", self._name, mode, cbname)
        return cbname

    trace = trace_variable

    def trace_vdelete(self, mode, cbname):
        self._tk.call("trace", "vdelete", self._name, mode, cbname)
        cbname = self._tk.splitlist(cbname)[0]
        for m, ca in self.trace_info():
            if self._tk.splitlist(ca)[0] == cbname:
                break
        else:
            self._tk.deletecommand(cbname)
            try:
                self._tclCommands.remove(cbname)
            except ValueError:
                pass

    def trace_vinfo(self):
        return [self._tk.splitlist(x) for x in self._tk.splitlist(
            self._tk.call("trace", "vinfo", self._name))]

    def __eq__(self, other):
        return self.__class__.__name__ == other.__class__.__name__ \
            and self._name == other._name


class StringVar(Variable):
    _default = ""

    def __init__(self, master=None, value=None, name=None):
        Variable.__init__(self, master, value, name)

    def get(self):
        value = self._tk.globalgetvar(self._name)
        if isinstance(value, str):
            return value
        return str(value)


class IntVar(Variable):
    _default = 0

    def __init__(self, master=None, value=None, name=None):
        Variable.__init__(self, master, value, name)

    def get(self):
        value = self._tk.globalgetvar(self._name)
        try:
            return self._tk.getint(value)
        except (TypeError, TclError):
            return int(self._tk.getdouble(value))


class DoubleVar(Variable):
    _default = 0.0

    def __init__(self, master=None, value=None, name=None):
        Variable.__init__(self, master, value, name)

    def get(self):
        return self._tk.getdouble(self._tk.globalgetvar(self._name))


class BooleanVar(Variable):
    _default = False

    def __init__(self, master=None, value=None, name=None):
        Variable.__init__(self, master, value, name)

    def set(self, value):
        return self._tk.globalsetvar(self._name, self._tk.getboolean(value))

    initialize = set

    def get(self):
        try:
            return self._tk.getboolean(self._tk.globalgetvar(self._name))
        except TclError:
            raise ValueError("invalid literal for getboolean()")


def mainloop(n=0):
    _default_root.tk.mainloop(n)


getint = int

getdouble = float


def getboolean(s):
    try:
        return _default_root.tk.getboolean(s)
    except TclError:
        raise ValueError("invalid literal for getboolean()")


class Misc:
    _last_child_ids = None

    _tclCommands = None

    def destroy(self):
        if self._tclCommands is not None:
            for name in self._tclCommands:
                #print '- Tkinter: deleted command', name
                self.tk.deletecommand(name)
            self._tclCommands = None

    def deletecommand(self, name):
        self.tk.deletecommand(name)
        try:
            self._tclCommands.remove(name)
        except ValueError:
            pass

    def tk_strictMotif(self, boolean=None):
        return self.tk.getboolean(self.tk.call(
            'set', 'tk_strictMotif', boolean))

    def tk_bisque(self):
        self.tk.call('tk_bisque')

    def tk_setPalette(self, *args, **kw):
        self.tk.call(('tk_setPalette',)
              + _flatten(args) + _flatten(list(kw.items())))

    def wait_variable(self, name='PY_VAR'):
        self.tk.call('tkwait', 'variable', name)
    waitvar = wait_variable # XXX b/w compat

    def wait_window(self, window=None):
        if window is None:
            window = self
        self.tk.call('tkwait', 'window', window._w)

    def wait_visibility(self, window=None):
        if window is None:
            window = self
        self.tk.call('tkwait', 'visibility', window._w)

    def setvar(self, name='PY_VAR', value='1'):
        self.tk.setvar(name, value)

    def getvar(self, name='PY_VAR'):
        return self.tk.getvar(name)

    def getint(self, s):
        try:
            return self.tk.getint(s)
        except TclError as exc:
            raise ValueError(str(exc))

    def getdouble(self, s):
        try:
            return self.tk.getdouble(s)
        except TclError as exc:
            raise ValueError(str(exc))

    def getboolean(self, s):
        try:
            return self.tk.getboolean(s)
        except TclError:
            raise ValueError("invalid literal for getboolean()")

    def focus_set(self):
        self.tk.call('focus', self._w)
    focus = focus_set # XXX b/w compat?

    def focus_force(self):
        self.tk.call('focus', '-force', self._w)

    def focus_get(self):
        name = self.tk.call('focus')
        if name == 'none' or not name: return None
        return self._nametowidget(name)

    def focus_displayof(self):
        name = self.tk.call('focus', '-displayof', self._w)
        if name == 'none' or not name: return None
        return self._nametowidget(name)

    def focus_lastfor(self):
        name = self.tk.call('focus', '-lastfor', self._w)
        if name == 'none' or not name: return None
        return self._nametowidget(name)

    def tk_focusFollowsMouse(self):
        self.tk.call('tk_focusFollowsMouse')

    def tk_focusNext(self):
        name = self.tk.call('tk_focusNext', self._w)
        if not name: return None
        return self._nametowidget(name)

    def tk_focusPrev(self):
        name = self.tk.call('tk_focusPrev', self._w)
        if not name: return None
        return self._nametowidget(name)

    def after(self, ms, func=None, *args):
        if not func:
            self.tk.call('after', ms)
            return None
        else:
            def callit():
                try:
                    func(*args)
                finally:
                    try:
                        self.deletecommand(name)
                    except TclError:
                        pass
            callit.__name__ = func.__name__
            name = self._register(callit)
            return self.tk.call('after', ms, name)

    def after_idle(self, func, *args):
        return self.after('idle', func, *args)

    def after_cancel(self, id):
        if not id:
            raise ValueError('id must be a valid identifier returned from '
                             'after or after_idle')
        try:
            data = self.tk.call('after', 'info', id)
            script = self.tk.splitlist(data)[0]
            self.deletecommand(script)
        except TclError:
            pass
        self.tk.call('after', 'cancel', id)

    def bell(self, displayof=0):
        """Ring a display's bell."""
        self.tk.call(('bell',) + self._displayof(displayof))

    # Clipboard handling:
    def clipboard_get(self, **kw):
        if 'type' not in kw and self._windowingsystem == 'x11':
            try:
                kw['type'] = 'UTF8_STRING'
                return self.tk.call(('clipboard', 'get') + self._options(kw))
            except TclError:
                del kw['type']
        return self.tk.call(('clipboard', 'get') + self._options(kw))

    def clipboard_clear(self, **kw):
        if 'displayof' not in kw: kw['displayof'] = self._w
        self.tk.call(('clipboard', 'clear') + self._options(kw))

    def clipboard_append(self, string, **kw):
        if 'displayof' not in kw: kw['displayof'] = self._w
        self.tk.call(('clipboard', 'append') + self._options(kw)
              + ('--', string))
    # XXX grab current w/o window argument

    def grab_current(self):
        name = self.tk.call('grab', 'current', self._w)
        if not name: return None
        return self._nametowidget(name)

    def grab_release(self):
        self.tk.call('grab', 'release', self._w)

    def grab_set(self):
        self.tk.call('grab', 'set', self._w)

    def grab_set_global(self):
        self.tk.call('grab', 'set', '-global', self._w)

    def grab_status(self):
        status = self.tk.call('grab', 'status', self._w)
        if status == 'none': status = None
        return status

    def option_add(self, pattern, value, priority = None):
        self.tk.call('option', 'add', pattern, value, priority)

    def option_clear(self):
        self.tk.call('option', 'clear')

    def option_get(self, name, className):
        return self.tk.call('option', 'get', self._w, name, className)

    def option_readfile(self, fileName, priority = None):
        self.tk.call('option', 'readfile', fileName, priority)

    def selection_clear(self, **kw):
        if 'displayof' not in kw: kw['displayof'] = self._w
        self.tk.call(('selection', 'clear') + self._options(kw))

    def selection_get(self, **kw):
        if 'displayof' not in kw: kw['displayof'] = self._w
        if 'type' not in kw and self._windowingsystem == 'x11':
            try:
                kw['type'] = 'UTF8_STRING'
                return self.tk.call(('selection', 'get') + self._options(kw))
            except TclError:
                del kw['type']
        return self.tk.call(('selection', 'get') + self._options(kw))

    def selection_handle(self, command, **kw):
        name = self._register(command)
        self.tk.call(('selection', 'handle') + self._options(kw)
              + (self._w, name))

    def selection_own(self, **kw):
        self.tk.call(('selection', 'own') +
                 self._options(kw) + (self._w,))

    def selection_own_get(self, **kw):
        if 'displayof' not in kw: kw['displayof'] = self._w
        name = self.tk.call(('selection', 'own') + self._options(kw))
        if not name: return None
        return self._nametowidget(name)

    def send(self, interp, cmd, *args):
        return self.tk.call(('send', interp, cmd) + args)

    def lower(self, belowThis=None):
        self.tk.call('lower', self._w, belowThis)

    def tkraise(self, aboveThis=None):
        self.tk.call('raise', self._w, aboveThis)

    lift = tkraise

    def winfo_atom(self, name, displayof=0):
        args = ('winfo', 'atom') + self._displayof(displayof) + (name,)
        return self.tk.getint(self.tk.call(args))

    def winfo_atomname(self, id, displayof=0):
        args = ('winfo', 'atomname') \
               + self._displayof(displayof) + (id,)
        return self.tk.call(args)

    def winfo_cells(self):
        return self.tk.getint(
            self.tk.call('winfo', 'cells', self._w))

    def winfo_children(self):
        result = []
        for child in self.tk.splitlist(
            self.tk.call('winfo', 'children', self._w)):
            try:
                # Tcl sometimes returns extra windows, e.g. for
                # menus; those need to be skipped
                result.append(self._nametowidget(child))
            except KeyError:
                pass
        return result

    def winfo_class(self):
        return self.tk.call('winfo', 'class', self._w)

    def winfo_colormapfull(self):
        return self.tk.getboolean(
            self.tk.call('winfo', 'colormapfull', self._w))

    def winfo_containing(self, rootX, rootY, displayof=0):
        args = ('winfo', 'containing') \
               + self._displayof(displayof) + (rootX, rootY)
        name = self.tk.call(args)
        if not name: return None
        return self._nametowidget(name)

    def winfo_depth(self):
        return self.tk.getint(self.tk.call('winfo', 'depth', self._w))

    def winfo_exists(self):
        return self.tk.getint(
            self.tk.call('winfo', 'exists', self._w))

    def winfo_fpixels(self, number):
        return self.tk.getdouble(self.tk.call(
            'winfo', 'fpixels', self._w, number))

    def winfo_geometry(self):
        return self.tk.call('winfo', 'geometry', self._w)

    def winfo_height(self):
        return self.tk.getint(
            self.tk.call('winfo', 'height', self._w))

    def winfo_id(self):
        return int(self.tk.call('winfo', 'id', self._w), 0)

    def winfo_interps(self, displayof=0):
        args = ('winfo', 'interps') + self._displayof(displayof)
        return self.tk.splitlist(self.tk.call(args))

    def winfo_ismapped(self):
        return self.tk.getint(
            self.tk.call('winfo', 'ismapped', self._w))

    def winfo_manager(self):
        return self.tk.call('winfo', 'manager', self._w)

    def winfo_name(self):
        return self.tk.call('winfo', 'name', self._w)

    def winfo_parent(self):
        return self.tk.call('winfo', 'parent', self._w)

    def winfo_pathname(self, id, displayof=0):
        args = ('winfo', 'pathname') \
               + self._displayof(displayof) + (id,)
        return self.tk.call(args)

    def winfo_pixels(self, number):
        return self.tk.getint(
            self.tk.call('winfo', 'pixels', self._w, number))

    def winfo_pointerx(self):
        return self.tk.getint(
            self.tk.call('winfo', 'pointerx', self._w))

    def winfo_pointerxy(self):
        return self._getints(
            self.tk.call('winfo', 'pointerxy', self._w))

    def winfo_pointery(self):
        return self.tk.getint(
            self.tk.call('winfo', 'pointery', self._w))

    def winfo_reqheight(self):
        return self.tk.getint(
            self.tk.call('winfo', 'reqheight', self._w))

    def winfo_reqwidth(self):
        return self.tk.getint(
            self.tk.call('winfo', 'reqwidth', self._w))

    def winfo_rgb(self, color):
        return self._getints(
            self.tk.call('winfo', 'rgb', self._w, color))

    def winfo_rootx(self):
        return self.tk.getint(
            self.tk.call('winfo', 'rootx', self._w))

    def winfo_rooty(self):
        return self.tk.getint(
            self.tk.call('winfo', 'rooty', self._w))

    def winfo_screen(self):
        return self.tk.call('winfo', 'screen', self._w)

    def winfo_screencells(self):
        return self.tk.getint(
            self.tk.call('winfo', 'screencells', self._w))

    def winfo_screendepth(self):
        return self.tk.getint(
            self.tk.call('winfo', 'screendepth', self._w))

    def winfo_screenheight(self):
        return self.tk.getint(
            self.tk.call('winfo', 'screenheight', self._w))

    def winfo_screenmmheight(self):
        return self.tk.getint(
            self.tk.call('winfo', 'screenmmheight', self._w))

    def winfo_screenmmwidth(self):
        return self.tk.getint(
            self.tk.call('winfo', 'screenmmwidth', self._w))

    def winfo_screenvisual(self):
        return self.tk.call('winfo', 'screenvisual', self._w)

    def winfo_screenwidth(self):
        return self.tk.getint(
            self.tk.call('winfo', 'screenwidth', self._w))

    def winfo_server(self):
        return self.tk.call('winfo', 'server', self._w)

    def winfo_toplevel(self):
        return self._nametowidget(self.tk.call(
            'winfo', 'toplevel', self._w))

    def winfo_viewable(self):
        return self.tk.getint(
            self.tk.call('winfo', 'viewable', self._w))

    def winfo_visual(self):
        return self.tk.call('winfo', 'visual', self._w)

    def winfo_visualid(self):
        return self.tk.call('winfo', 'visualid', self._w)

    def winfo_visualsavailable(self, includeids=False):
        data = self.tk.call('winfo', 'visualsavailable', self._w,
                            'includeids' if includeids else None)
        data = [self.tk.splitlist(x) for x in self.tk.splitlist(data)]
        return [self.__winfo_parseitem(x) for x in data]

    def __winfo_parseitem(self, t):
        return t[:1] + tuple(map(self.__winfo_getint, t[1:]))

    def __winfo_getint(self, x):
        return int(x, 0)

    def winfo_vrootheight(self):
        return self.tk.getint(
            self.tk.call('winfo', 'vrootheight', self._w))

    def winfo_vrootwidth(self):
        return self.tk.getint(
            self.tk.call('winfo', 'vrootwidth', self._w))

    def winfo_vrootx(self):
        return self.tk.getint(
            self.tk.call('winfo', 'vrootx', self._w))

    def winfo_vrooty(self):
        return self.tk.getint(
            self.tk.call('winfo', 'vrooty', self._w))

    def winfo_width(self):
        return self.tk.getint(
            self.tk.call('winfo', 'width', self._w))

    def winfo_x(self):
        return self.tk.getint(
            self.tk.call('winfo', 'x', self._w))

    def winfo_y(self):
        return self.tk.getint(
            self.tk.call('winfo', 'y', self._w))

    def update(self):
        self.tk.call('update')

    def update_idletasks(self):
        self.tk.call('update', 'idletasks')

    def bindtags(self, tagList=None):
        if tagList is None:
            return self.tk.splitlist(
                self.tk.call('bindtags', self._w))
        else:
            self.tk.call('bindtags', self._w, tagList)

    def _bind(self, what, sequence, func, add, needcleanup=1):
        if isinstance(func, str):
            self.tk.call(what + (sequence, func))
        elif func:
            funcid = self._register(func, self._substitute,
                        needcleanup)
            cmd = ('%sif {"[%s %s]" == "break"} break\n'
                   %
                   (add and '+' or '',
                funcid, self._subst_format_str))
            self.tk.call(what + (sequence, cmd))
            return funcid
        elif sequence:
            return self.tk.call(what + (sequence,))
        else:
            return self.tk.splitlist(self.tk.call(what))

    def bind(self, sequence=None, func=None, add=None):
        return self._bind(('bind', self._w), sequence, func, add)

    def unbind(self, sequence, funcid=None):
        self.tk.call('bind', self._w, sequence, '')
        if funcid:
            self.deletecommand(funcid)

    def bind_all(self, sequence=None, func=None, add=None):
        return self._bind(('bind', 'all'), sequence, func, add, 0)

    def unbind_all(self, sequence):
        self.tk.call('bind', 'all' , sequence, '')

    def bind_class(self, className, sequence=None, func=None, add=None):
        return self._bind(('bind', className), sequence, func, add, 0)

    def unbind_class(self, className, sequence):
        self.tk.call('bind', className , sequence, '')

    def mainloop(self, n=0):
        self.tk.mainloop(n)

    def quit(self):
        self.tk.quit()

    def _getints(self, string):
        if string:
            return tuple(map(self.tk.getint, self.tk.splitlist(string)))

    def _getdoubles(self, string):
        if string:
            return tuple(map(self.tk.getdouble, self.tk.splitlist(string)))

    def _getboolean(self, string):
        if string:
            return self.tk.getboolean(string)

    def _displayof(self, displayof):
        if displayof:
            return ('-displayof', displayof)
        if displayof is None:
            return ('-displayof', self._w)
        return ()

    @property
    def _windowingsystem(self):
        try:
            return self._root()._windowingsystem_cached
        except AttributeError:
            ws = self._root()._windowingsystem_cached = \
                        self.tk.call('tk', 'windowingsystem')
            return ws

    def _options(self, cnf, kw = None):
        if kw:
            cnf = _cnfmerge((cnf, kw))
        else:
            cnf = _cnfmerge(cnf)
        res = ()
        for k, v in cnf.items():
            if v is not None:
                if k[-1] == '_': k = k[:-1]
                if callable(v):
                    v = self._register(v)
                elif isinstance(v, (tuple, list)):
                    nv = []
                    for item in v:
                        if isinstance(item, int):
                            nv.append(str(item))
                        elif isinstance(item, str):
                            nv.append(_stringify(item))
                        else:
                            break
                    else:
                        v = ' '.join(nv)
                res = res + ('-'+k, v)
        return res

    def nametowidget(self, name):
        name = str(name).split('.')
        w = self

        if not name[0]:
            w = w._root()
            name = name[1:]

        for n in name:
            if not n:
                break
            w = w.children[n]

        return w

    _nametowidget = nametowidget

    def _register(self, func, subst=None, needcleanup=1):
        f = CallWrapper(func, subst, self).__call__
        name = repr(id(f))
        try:
            func = func.__func__
        except AttributeError:
            pass
        try:
            name = name + func.__name__
        except AttributeError:
            pass
        self.tk.createcommand(name, f)
        if needcleanup:
            if self._tclCommands is None:
                self._tclCommands = []
            self._tclCommands.append(name)
        return name

    register = _register

    def _root(self):
        w = self
        while w.master: w = w.master
        return w
    _subst_format = ('%#', '%b', '%f', '%h', '%k',
             '%s', '%t', '%w', '%x', '%y',
             '%A', '%E', '%K', '%N', '%W', '%T', '%X', '%Y', '%D')
    _subst_format_str = " ".join(_subst_format)

    def _substitute(self, *args):
        if len(args) != len(self._subst_format): return args
        getboolean = self.tk.getboolean

        getint = self.tk.getint
        def getint_event(s):
            try:
                return getint(s)
            except (ValueError, TclError):
                return s

        nsign, b, f, h, k, s, t, w, x, y, A, E, K, N, W, T, X, Y, D = args
        e = Event()
        e.serial = getint(nsign)
        e.num = getint_event(b)
        try: e.focus = getboolean(f)
        except TclError: pass
        e.height = getint_event(h)
        e.keycode = getint_event(k)
        e.state = getint_event(s)
        e.time = getint_event(t)
        e.width = getint_event(w)
        e.x = getint_event(x)
        e.y = getint_event(y)
        e.char = A
        try: e.send_event = getboolean(E)
        except TclError: pass
        e.keysym = K
        e.keysym_num = getint_event(N)
        try:
            e.type = EventType(T)
        except ValueError:
            e.type = T
        try:
            e.widget = self._nametowidget(W)
        except KeyError:
            e.widget = W
        e.x_root = getint_event(X)
        e.y_root = getint_event(Y)
        try:
            e.delta = getint(D)
        except (ValueError, TclError):
            e.delta = 0
        return (e,)

    def _report_exception(self):
        exc, val, tb = sys.exc_info()
        root = self._root()
        root.report_callback_exception(exc, val, tb)

    def _getconfigure(self, *args):
        cnf = {}
        for x in self.tk.splitlist(self.tk.call(*args)):
            x = self.tk.splitlist(x)
            cnf[x[0][1:]] = (x[0][1:],) + x[1:]
        return cnf

    def _getconfigure1(self, *args):
        x = self.tk.splitlist(self.tk.call(*args))
        return (x[0][1:],) + x[1:]

    def _configure(self, cmd, cnf, kw):
        if kw:
            cnf = _cnfmerge((cnf, kw))
        elif cnf:
            cnf = _cnfmerge(cnf)
        if cnf is None:
            return self._getconfigure(_flatten((self._w, cmd)))
        if isinstance(cnf, str):
            return self._getconfigure1(_flatten((self._w, cmd, '-'+cnf)))
        self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))

    def configure(self, cnf=None, **kw):
        return self._configure('configure', cnf, kw)

    config = configure

    def cget(self, key):
        return self.tk.call(self._w, 'cget', '-' + key)

    __getitem__ = cget

    def __setitem__(self, key, value):
        self.configure({key: value})

    def keys(self):
        splitlist = self.tk.splitlist
        return [splitlist(x)[0][1:] for x in
                splitlist(self.tk.call(self._w, 'configure'))]

    def __str__(self):
        return self._w

    def __repr__(self):
        return '<%s.%s object %s>' % (
            self.__class__.__module__, self.__class__.__qualname__, self._w)

    _noarg_ = ['_noarg_']

    def pack_propagate(self, flag=_noarg_):
        if flag is Misc._noarg_:
            return self._getboolean(self.tk.call(
                'pack', 'propagate', self._w))
        else:
            self.tk.call('pack', 'propagate', self._w, flag)

    propagate = pack_propagate

    def pack_slaves(self):
        return [self._nametowidget(x) for x in
                self.tk.splitlist(
                   self.tk.call('pack', 'slaves', self._w))]

    slaves = pack_slaves

    def place_slaves(self):
        return [self._nametowidget(x) for x in
                self.tk.splitlist(
                   self.tk.call(
                       'place', 'slaves', self._w))]


    def grid_anchor(self, anchor=None): # new in Tk 8.5
        self.tk.call('grid', 'anchor', self._w, anchor)

    anchor = grid_anchor

    def grid_bbox(self, column=None, row=None, col2=None, row2=None):
        args = ('grid', 'bbox', self._w)
        if column is not None and row is not None:
            args = args + (column, row)
        if col2 is not None and row2 is not None:
            args = args + (col2, row2)
        return self._getints(self.tk.call(*args)) or None

    bbox = grid_bbox

    def _gridconvvalue(self, value):
        if isinstance(value, (str, _tkinter.Tcl_Obj)):
            try:
                svalue = str(value)
                if not svalue:
                    return None
                elif '.' in svalue:
                    return self.tk.getdouble(svalue)
                else:
                    return self.tk.getint(svalue)
            except (ValueError, TclError):
                pass
        return value

    def _grid_configure(self, command, index, cnf, kw):
        if isinstance(cnf, str) and not kw:
            if cnf[-1:] == '_':
                cnf = cnf[:-1]
            if cnf[:1] != '-':
                cnf = '-'+cnf
            options = (cnf,)
        else:
            options = self._options(cnf, kw)
        if not options:
            return _splitdict(
                self.tk,
                self.tk.call('grid', command, self._w, index),
                conv=self._gridconvvalue)
        res = self.tk.call(
                  ('grid', command, self._w, index)
                  + options)
        if len(options) == 1:
            return self._gridconvvalue(res)

    def grid_columnconfigure(self, index, cnf={}, **kw):
        return self._grid_configure('columnconfigure', index, cnf, kw)

    columnconfigure = grid_columnconfigure

    def grid_location(self, x, y):
        return self._getints(
            self.tk.call(
                'grid', 'location', self._w, x, y)) or None

    def grid_propagate(self, flag=_noarg_):
        if flag is Misc._noarg_:
            return self._getboolean(self.tk.call(
                'grid', 'propagate', self._w))
        else:
            self.tk.call('grid', 'propagate', self._w, flag)

    def grid_rowconfigure(self, index, cnf={}, **kw):
        return self._grid_configure('rowconfigure', index, cnf, kw)

    rowconfigure = grid_rowconfigure

    def grid_size(self):
        return self._getints(
            self.tk.call('grid', 'size', self._w)) or None

    size = grid_size

    def grid_slaves(self, row=None, column=None):
        args = ()
        if row is not None:
            args = args + ('-row', row)
        if column is not None:
            args = args + ('-column', column)
        return [self._nametowidget(x) for x in
                self.tk.splitlist(self.tk.call(
                   ('grid', 'slaves', self._w) + args))]


    def event_add(self, virtual, *sequences):
        args = ('event', 'add', virtual) + sequences
        self.tk.call(args)

    def event_delete(self, virtual, *sequences):
        args = ('event', 'delete', virtual) + sequences
        self.tk.call(args)

    def event_generate(self, sequence, **kw):
        args = ('event', 'generate', self._w, sequence)
        for k, v in kw.items():
            args = args + ('-%s' % k, str(v))
        self.tk.call(args)

    def event_info(self, virtual=None):
        return self.tk.splitlist(
            self.tk.call('event', 'info', virtual))


    def image_names(self):
        return self.tk.splitlist(self.tk.call('image', 'names'))

    def image_types(self):
        return self.tk.splitlist(self.tk.call('image', 'types'))


class CallWrapper:
    def __init__(self, func, subst, widget):
        self.func = func
        self.subst = subst
        self.widget = widget

    def __call__(self, *args):
        try:
            if self.subst:
                args = self.subst(*args)
            return self.func(*args)
        except SystemExit:
            raise
        except:
            self.widget._report_exception()


class XView:
    def xview(self, *args):
        res = self.tk.call(self._w, 'xview', *args)
        if not args:
            return self._getdoubles(res)

    def xview_moveto(self, fraction):
        self.tk.call(self._w, 'xview', 'moveto', fraction)

    def xview_scroll(self, number, what):
        self.tk.call(self._w, 'xview', 'scroll', number, what)


class YView:
    def yview(self, *args):
        res = self.tk.call(self._w, 'yview', *args)
        if not args:
            return self._getdoubles(res)

    def yview_moveto(self, fraction):
        self.tk.call(self._w, 'yview', 'moveto', fraction)

    def yview_scroll(self, number, what):
        self.tk.call(self._w, 'yview', 'scroll', number, what)


class Wm:
    def wm_aspect(self,
              minNumer=None, minDenom=None,
              maxNumer=None, maxDenom=None):
        return self._getints(
            self.tk.call('wm', 'aspect', self._w,
                     minNumer, minDenom,
                     maxNumer, maxDenom))

    aspect = wm_aspect

    def wm_attributes(self, *args):
        args = ('wm', 'attributes', self._w) + args
        return self.tk.call(args)

    attributes = wm_attributes

    def wm_client(self, name=None):
        return self.tk.call('wm', 'client', self._w, name)

    client = wm_client

    def wm_colormapwindows(self, *wlist):
        if len(wlist) > 1:
            wlist = (wlist,) # Tk needs a list of windows here
        args = ('wm', 'colormapwindows', self._w) + wlist
        if wlist:
            self.tk.call(args)
        else:
            return [self._nametowidget(x)
                    for x in self.tk.splitlist(self.tk.call(args))]

    colormapwindows = wm_colormapwindows

    def wm_command(self, value=None):
        return self.tk.call('wm', 'command', self._w, value)

    command = wm_command

    def wm_deiconify(self):
        return self.tk.call('wm', 'deiconify', self._w)

    deiconify = wm_deiconify

    def wm_focusmodel(self, model=None):
        return self.tk.call('wm', 'focusmodel', self._w, model)

    focusmodel = wm_focusmodel

    def wm_forget(self, window): # new in Tk 8.5
        self.tk.call('wm', 'forget', window)

    forget = wm_forget

    def wm_frame(self):
        return self.tk.call('wm', 'frame', self._w)

    frame = wm_frame

    def wm_geometry(self, newGeometry=None):
        return self.tk.call('wm', 'geometry', self._w, newGeometry)

    geometry = wm_geometry

    def wm_grid(self,
         baseWidth=None, baseHeight=None,
         widthInc=None, heightInc=None):
        return self._getints(self.tk.call(
            'wm', 'grid', self._w,
            baseWidth, baseHeight, widthInc, heightInc))

    grid = wm_grid

    def wm_group(self, pathName=None):
        return self.tk.call('wm', 'group', self._w, pathName)

    group = wm_group

    def wm_iconbitmap(self, bitmap=None, default=None):
        if default:
            return self.tk.call('wm', 'iconbitmap', self._w, '-default', default)
        else:
            return self.tk.call('wm', 'iconbitmap', self._w, bitmap)

    iconbitmap = wm_iconbitmap

    def wm_iconify(self):
        return self.tk.call('wm', 'iconify', self._w)

    iconify = wm_iconify

    def wm_iconmask(self, bitmap=None):
        return self.tk.call('wm', 'iconmask', self._w, bitmap)

    iconmask = wm_iconmask

    def wm_iconname(self, newName=None):
        return self.tk.call('wm', 'iconname', self._w, newName)

    iconname = wm_iconname

    def wm_iconphoto(self, default=False, *args): # new in Tk 8.5
        if default:
            self.tk.call('wm', 'iconphoto', self._w, "-default", *args)
        else:
            self.tk.call('wm', 'iconphoto', self._w, *args)

    iconphoto = wm_iconphoto

    def wm_iconposition(self, x=None, y=None):
        return self._getints(self.tk.call(
            'wm', 'iconposition', self._w, x, y))

    iconposition = wm_iconposition

    def wm_iconwindow(self, pathName=None):
        return self.tk.call('wm', 'iconwindow', self._w, pathName)

    iconwindow = wm_iconwindow

    def wm_manage(self, widget): # new in Tk 8.5
        self.tk.call('wm', 'manage', widget)

    manage = wm_manage

    def wm_maxsize(self, width=None, height=None):
        return self._getints(self.tk.call(
            'wm', 'maxsize', self._w, width, height))

    maxsize = wm_maxsize

    def wm_minsize(self, width=None, height=None):
        return self._getints(self.tk.call(
            'wm', 'minsize', self._w, width, height))

    minsize = wm_minsize

    def wm_overrideredirect(self, boolean=None):
        return self._getboolean(self.tk.call(
            'wm', 'overrideredirect', self._w, boolean))

    overrideredirect = wm_overrideredirect

    def wm_positionfrom(self, who=None):
        return self.tk.call('wm', 'positionfrom', self._w, who)

    positionfrom = wm_positionfrom

    def wm_protocol(self, name=None, func=None):
        if callable(func):
            command = self._register(func)
        else:
            command = func
        return self.tk.call(
            'wm', 'protocol', self._w, name, command)

    protocol = wm_protocol

    def wm_resizable(self, width=None, height=None):
        return self.tk.call('wm', 'resizable', self._w, width, height)

    resizable = wm_resizable

    def wm_sizefrom(self, who=None):
        return self.tk.call('wm', 'sizefrom', self._w, who)

    sizefrom = wm_sizefrom

    def wm_state(self, newstate=None):
        return self.tk.call('wm', 'state', self._w, newstate)

    state = wm_state

    def wm_title(self, string=None):
        return self.tk.call('wm', 'title', self._w, string)

    title = wm_title

    def wm_transient(self, master=None):
        return self.tk.call('wm', 'transient', self._w, master)

    transient = wm_transient

    def wm_withdraw(self):
        return self.tk.call('wm', 'withdraw', self._w)

    withdraw = wm_withdraw


class Tk(Misc, Wm):
    _w = '.'

    def __init__(self, screenName=None, baseName=None, className='Tk',
                 useTk=1, sync=0, use=None):
        self.master = None
        self.children = {}
        self._tkloaded = 0
        self.tk = None
        if baseName is None:
            import os
            baseName = os.path.basename(sys.argv[0])
            baseName, ext = os.path.splitext(baseName)
            if ext not in ('.py', '.pyc'):
                baseName = baseName + ext
        interactive = 0
        self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
        if useTk:
            self._loadtk()
        if not sys.flags.ignore_environment:
            self.readprofile(baseName, className)

    def loadtk(self):
        if not self._tkloaded:
            self.tk.loadtk()
            self._loadtk()

    def _loadtk(self):
        self._tkloaded = 1
        global _default_root
        tk_version = self.tk.getvar('tk_version')
        if tk_version != _tkinter.TK_VERSION:
            raise RuntimeError("tk.h version (%s) doesn't match libtk.a version (%s)"
                               % (_tkinter.TK_VERSION, tk_version))
        tcl_version = str(self.tk.getvar('tcl_version'))
        if tcl_version != _tkinter.TCL_VERSION:
            raise RuntimeError("tcl.h version (%s) doesn't match libtcl.a version (%s)" \
                               % (_tkinter.TCL_VERSION, tcl_version))
        if self._tclCommands is None:
            self._tclCommands = []
        self.tk.createcommand('tkerror', _tkerror)
        self.tk.createcommand('exit', _exit)
        self._tclCommands.append('tkerror')
        self._tclCommands.append('exit')
        if _support_default_root and not _default_root:
            _default_root = self
        self.protocol("WM_DELETE_WINDOW", self.destroy)

    def destroy(self):
        for c in list(self.children.values()): c.destroy()
        self.tk.call('destroy', self._w)
        Misc.destroy(self)
        global _default_root
        if _support_default_root and _default_root is self:
            _default_root = None

    def readprofile(self, baseName, className):
        import os
        if 'HOME' in os.environ: home = os.environ['HOME']
        else: home = os.curdir
        class_tcl = os.path.join(home, '.%s.tcl' % className)
        class_py = os.path.join(home, '.%s.py' % className)
        base_tcl = os.path.join(home, '.%s.tcl' % baseName)
        base_py = os.path.join(home, '.%s.py' % baseName)
        dir = {'self': self}
        exec('from tkinter import *', dir)
        if os.path.isfile(class_tcl):
            self.tk.call('source', class_tcl)
        if os.path.isfile(class_py):
            exec(open(class_py).read(), dir)
        if os.path.isfile(base_tcl):
            self.tk.call('source', base_tcl)
        if os.path.isfile(base_py):
            exec(open(base_py).read(), dir)

    def report_callback_exception(self, exc, val, tb):
        import traceback
        print("Exception in Tkinter callback", file=sys.stderr)
        sys.last_type = exc
        sys.last_value = val
        sys.last_traceback = tb
        traceback.print_exception(exc, val, tb)

    def __getattr__(self, attr):
        return getattr(self.tk, attr)


def Tcl(screenName=None, baseName=None, className='Tk', useTk=0):
    return Tk(screenName, baseName, className, useTk)


class Pack:
    def pack_configure(self, cnf={}, **kw):
        self.tk.call(
              ('pack', 'configure', self._w)
              + self._options(cnf, kw))

    pack = configure = config = pack_configure

    def pack_forget(self):
        self.tk.call('pack', 'forget', self._w)

    forget = pack_forget

    def pack_info(self):
        d = _splitdict(self.tk, self.tk.call('pack', 'info', self._w))
        if 'in' in d:
            d['in'] = self.nametowidget(d['in'])
        return d

    info = pack_info
    propagate = pack_propagate = Misc.pack_propagate
    slaves = pack_slaves = Misc.pack_slaves


class Place:
    def place_configure(self, cnf={}, **kw):
        self.tk.call(
              ('place', 'configure', self._w)
              + self._options(cnf, kw))

    place = configure = config = place_configure

    def place_forget(self):
        self.tk.call('place', 'forget', self._w)

    forget = place_forget

    def place_info(self):
        d = _splitdict(self.tk, self.tk.call('place', 'info', self._w))
        if 'in' in d:
            d['in'] = self.nametowidget(d['in'])
        return d

    info = place_info
    slaves = place_slaves = Misc.place_slaves


class Grid:
    def grid_configure(self, cnf={}, **kw):
        self.tk.call(
              ('grid', 'configure', self._w)
              + self._options(cnf, kw))

    grid = configure = config = grid_configure
    bbox = grid_bbox = Misc.grid_bbox
    columnconfigure = grid_columnconfigure = Misc.grid_columnconfigure

    def grid_forget(self):
        self.tk.call('grid', 'forget', self._w)

    forget = grid_forget

    def grid_remove(self):
        self.tk.call('grid', 'remove', self._w)

    def grid_info(self):
        d = _splitdict(self.tk, self.tk.call('grid', 'info', self._w))
        if 'in' in d:
            d['in'] = self.nametowidget(d['in'])
        return d

    info = grid_info
    location = grid_location = Misc.grid_location
    propagate = grid_propagate = Misc.grid_propagate
    rowconfigure = grid_rowconfigure = Misc.grid_rowconfigure
    size = grid_size = Misc.grid_size
    slaves = grid_slaves = Misc.grid_slaves


class BaseWidget(Misc):
    def _setup(self, master, cnf):
        if _support_default_root:
            global _default_root
            if not master:
                if not _default_root:
                    _default_root = Tk()
                master = _default_root
        self.master = master
        self.tk = master.tk
        name = None
        if 'name' in cnf:
            name = cnf['name']
            del cnf['name']
        if not name:
            name = self.__class__.__name__.lower()
            if master._last_child_ids is None:
                master._last_child_ids = {}
            count = master._last_child_ids.get(name, 0) + 1
            master._last_child_ids[name] = count
            if count == 1:
                name = '!%s' % (name,)
            else:
                name = '!%s%d' % (name, count)
        self._name = name
        if master._w=='.':
            self._w = '.' + name
        else:
            self._w = master._w + '.' + name
        self.children = {}
        if self._name in self.master.children:
            self.master.children[self._name].destroy()
        self.master.children[self._name] = self

    def __init__(self, master, widgetName, cnf={}, kw={}, extra=()):
        if kw:
            cnf = _cnfmerge((cnf, kw))
        self.widgetName = widgetName
        BaseWidget._setup(self, master, cnf)
        if self._tclCommands is None:
            self._tclCommands = []
        classes = [(k, v) for k, v in cnf.items() if isinstance(k, type)]
        for k, v in classes:
            del cnf[k]
        self.tk.call(
            (widgetName, self._w) + extra + self._options(cnf))
        for k, v in classes:
            k.configure(self, v)

    def destroy(self):
        for c in list(self.children.values()): c.destroy()
        self.tk.call('destroy', self._w)
        if self._name in self.master.children:
            del self.master.children[self._name]
        Misc.destroy(self)

    def _do(self, name, args=()):
        return self.tk.call((self._w, name) + args)


class Widget(BaseWidget, Pack, Place, Grid):
    pass


class Toplevel(BaseWidget, Wm):
    def __init__(self, master=None, cnf={}, **kw):
        if kw:
            cnf = _cnfmerge((cnf, kw))
        extra = ()
        for wmkey in ['screen', 'class_', 'class', 'visual',
                  'colormap']:
            if wmkey in cnf:
                val = cnf[wmkey]
                if wmkey[-1] == '_': opt = '-'+wmkey[:-1]
                else: opt = '-'+wmkey
                extra = extra + (opt, val)
                del cnf[wmkey]
        BaseWidget.__init__(self, master, 'toplevel', cnf, {}, extra)
        root = self._root()
        self.iconname(root.iconname())
        self.title(root.title())
        self.protocol("WM_DELETE_WINDOW", self.destroy)


class Button(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'button', cnf, kw)

    def flash(self):
        self.tk.call(self._w, 'flash')

    def invoke(self):
        return self.tk.call(self._w, 'invoke')


class Canvas(Widget, XView, YView):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'canvas', cnf, kw)

    def addtag(self, *args):
        self.tk.call((self._w, 'addtag') + args)

    def addtag_above(self, newtag, tagOrId):
        self.addtag(newtag, 'above', tagOrId)

    def addtag_all(self, newtag):
        self.addtag(newtag, 'all')

    def addtag_below(self, newtag, tagOrId):
        self.addtag(newtag, 'below', tagOrId)

    def addtag_closest(self, newtag, x, y, halo=None, start=None):
        self.addtag(newtag, 'closest', x, y, halo, start)

    def addtag_enclosed(self, newtag, x1, y1, x2, y2):
        self.addtag(newtag, 'enclosed', x1, y1, x2, y2)

    def addtag_overlapping(self, newtag, x1, y1, x2, y2):
        self.addtag(newtag, 'overlapping', x1, y1, x2, y2)

    def addtag_withtag(self, newtag, tagOrId):
        self.addtag(newtag, 'withtag', tagOrId)

    def bbox(self, *args):
        return self._getints(
            self.tk.call((self._w, 'bbox') + args)) or None

    def tag_unbind(self, tagOrId, sequence, funcid=None):
        self.tk.call(self._w, 'bind', tagOrId, sequence, '')
        if funcid:
            self.deletecommand(funcid)

    def tag_bind(self, tagOrId, sequence=None, func=None, add=None):
        return self._bind((self._w, 'bind', tagOrId),
                  sequence, func, add)

    def canvasx(self, screenx, gridspacing=None):
        return self.tk.getdouble(self.tk.call(
            self._w, 'canvasx', screenx, gridspacing))

    def canvasy(self, screeny, gridspacing=None):
        return self.tk.getdouble(self.tk.call(
            self._w, 'canvasy', screeny, gridspacing))

    def coords(self, *args):
        return [self.tk.getdouble(x) for x in
                           self.tk.splitlist(
                   self.tk.call((self._w, 'coords') + args))]

    def _create(self, itemType, args, kw): # Args: (val, val, ..., cnf={})
        args = _flatten(args)
        cnf = args[-1]
        if isinstance(cnf, (dict, tuple)):
            args = args[:-1]
        else:
            cnf = {}
        return self.tk.getint(self.tk.call(
            self._w, 'create', itemType,
            *(args + self._options(cnf, kw))))

    def create_arc(self, *args, **kw):
        return self._create('arc', args, kw)

    def create_bitmap(self, *args, **kw):
        return self._create('bitmap', args, kw)

    def create_image(self, *args, **kw):
        return self._create('image', args, kw)

    def create_line(self, *args, **kw):
        return self._create('line', args, kw)

    def create_oval(self, *args, **kw):
        return self._create('oval', args, kw)

    def create_polygon(self, *args, **kw):
        return self._create('polygon', args, kw)

    def create_rectangle(self, *args, **kw):
        return self._create('rectangle', args, kw)

    def create_text(self, *args, **kw):
        return self._create('text', args, kw)

    def create_window(self, *args, **kw):
        return self._create('window', args, kw)

    def dchars(self, *args):
        self.tk.call((self._w, 'dchars') + args)

    def delete(self, *args):
        self.tk.call((self._w, 'delete') + args)

    def dtag(self, *args):
        self.tk.call((self._w, 'dtag') + args)

    def find(self, *args):
        return self._getints(
            self.tk.call((self._w, 'find') + args)) or ()

    def find_above(self, tagOrId):
        return self.find('above', tagOrId)

    def find_all(self):
        return self.find('all')

    def find_below(self, tagOrId):
        return self.find('below', tagOrId)

    def find_closest(self, x, y, halo=None, start=None):
        return self.find('closest', x, y, halo, start)

    def find_enclosed(self, x1, y1, x2, y2):
        return self.find('enclosed', x1, y1, x2, y2)

    def find_overlapping(self, x1, y1, x2, y2):
        return self.find('overlapping', x1, y1, x2, y2)

    def find_withtag(self, tagOrId):
        return self.find('withtag', tagOrId)

    def focus(self, *args):
        return self.tk.call((self._w, 'focus') + args)

    def gettags(self, *args):
        return self.tk.splitlist(
            self.tk.call((self._w, 'gettags') + args))

    def icursor(self, *args):
        self.tk.call((self._w, 'icursor') + args)

    def index(self, *args):
        return self.tk.getint(self.tk.call((self._w, 'index') + args))

    def insert(self, *args):
        self.tk.call((self._w, 'insert') + args)

    def itemcget(self, tagOrId, option):
        return self.tk.call(
            (self._w, 'itemcget') + (tagOrId, '-'+option))

    def itemconfigure(self, tagOrId, cnf=None, **kw):
        return self._configure(('itemconfigure', tagOrId), cnf, kw)

    itemconfig = itemconfigure

    def tag_lower(self, *args):
        self.tk.call((self._w, 'lower') + args)

    lower = tag_lower

    def move(self, *args):
        self.tk.call((self._w, 'move') + args)

    def moveto(self, tagOrId, x='', y=''):
        self.tk.call(self._w, 'moveto', tagOrId, x, y)

    def postscript(self, cnf={}, **kw):
        return self.tk.call((self._w, 'postscript') +
                    self._options(cnf, kw))

    def tag_raise(self, *args):
        self.tk.call((self._w, 'raise') + args)

    lift = tkraise = tag_raise

    def scale(self, *args):
        self.tk.call((self._w, 'scale') + args)

    def scan_mark(self, x, y):
        self.tk.call(self._w, 'scan', 'mark', x, y)

    def scan_dragto(self, x, y, gain=10):
        self.tk.call(self._w, 'scan', 'dragto', x, y, gain)

    def select_adjust(self, tagOrId, index):
        self.tk.call(self._w, 'select', 'adjust', tagOrId, index)

    def select_clear(self):
        self.tk.call(self._w, 'select', 'clear')

    def select_from(self, tagOrId, index):
        self.tk.call(self._w, 'select', 'from', tagOrId, index)

    def select_item(self):
        return self.tk.call(self._w, 'select', 'item') or None

    def select_to(self, tagOrId, index):
        self.tk.call(self._w, 'select', 'to', tagOrId, index)

    def type(self, tagOrId):
        return self.tk.call(self._w, 'type', tagOrId) or None


class Checkbutton(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'checkbutton', cnf, kw)

    def deselect(self):
        self.tk.call(self._w, 'deselect')

    def flash(self):
        self.tk.call(self._w, 'flash')

    def invoke(self):
        return self.tk.call(self._w, 'invoke')

    def select(self):
        self.tk.call(self._w, 'select')

    def toggle(self):
        self.tk.call(self._w, 'toggle')


class Entry(Widget, XView):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'entry', cnf, kw)

    def delete(self, first, last=None):
        self.tk.call(self._w, 'delete', first, last)

    def get(self):
        return self.tk.call(self._w, 'get')

    def icursor(self, index):
        self.tk.call(self._w, 'icursor', index)

    def index(self, index):
        return self.tk.getint(self.tk.call(
            self._w, 'index', index))

    def insert(self, index, string):
        self.tk.call(self._w, 'insert', index, string)

    def scan_mark(self, x):
        self.tk.call(self._w, 'scan', 'mark', x)

    def scan_dragto(self, x):
        self.tk.call(self._w, 'scan', 'dragto', x)

    def selection_adjust(self, index):
        self.tk.call(self._w, 'selection', 'adjust', index)

    select_adjust = selection_adjust

    def selection_clear(self):
        self.tk.call(self._w, 'selection', 'clear')

    select_clear = selection_clear

    def selection_from(self, index):
        self.tk.call(self._w, 'selection', 'from', index)

    select_from = selection_from

    def selection_present(self):
        return self.tk.getboolean(
            self.tk.call(self._w, 'selection', 'present'))

    select_present = selection_present

    def selection_range(self, start, end):
        self.tk.call(self._w, 'selection', 'range', start, end)

    select_range = selection_range

    def selection_to(self, index):
        self.tk.call(self._w, 'selection', 'to', index)

    select_to = selection_to


class Frame(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        cnf = _cnfmerge((cnf, kw))
        extra = ()
        if 'class_' in cnf:
            extra = ('-class', cnf['class_'])
            del cnf['class_']
        elif 'class' in cnf:
            extra = ('-class', cnf['class'])
            del cnf['class']
        Widget.__init__(self, master, 'frame', cnf, {}, extra)


class Label(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'label', cnf, kw)


class Listbox(Widget, XView, YView):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'listbox', cnf, kw)

    def activate(self, index):
        self.tk.call(self._w, 'activate', index)

    def bbox(self, index):
        return self._getints(self.tk.call(self._w, 'bbox', index)) or None

    def curselection(self):
        return self._getints(self.tk.call(self._w, 'curselection')) or ()

    def delete(self, first, last=None):
        self.tk.call(self._w, 'delete', first, last)

    def get(self, first, last=None):
        if last is not None:
            return self.tk.splitlist(self.tk.call(
                self._w, 'get', first, last))
        else:
            return self.tk.call(self._w, 'get', first)

    def index(self, index):
        i = self.tk.call(self._w, 'index', index)
        if i == 'none': return None
        return self.tk.getint(i)

    def insert(self, index, *elements):
        self.tk.call((self._w, 'insert', index) + elements)

    def nearest(self, y):
        return self.tk.getint(self.tk.call(
            self._w, 'nearest', y))

    def scan_mark(self, x, y):
        self.tk.call(self._w, 'scan', 'mark', x, y)

    def scan_dragto(self, x, y):
        self.tk.call(self._w, 'scan', 'dragto', x, y)

    def see(self, index):
        self.tk.call(self._w, 'see', index)

    def selection_anchor(self, index):
        self.tk.call(self._w, 'selection', 'anchor', index)

    select_anchor = selection_anchor

    def selection_clear(self, first, last=None):
        self.tk.call(self._w,
                 'selection', 'clear', first, last)

    select_clear = selection_clear

    def selection_includes(self, index):
        return self.tk.getboolean(self.tk.call(
            self._w, 'selection', 'includes', index))

    select_includes = selection_includes

    def selection_set(self, first, last=None):
        self.tk.call(self._w, 'selection', 'set', first, last)

    select_set = selection_set

    def size(self):
        return self.tk.getint(self.tk.call(self._w, 'size'))

    def itemcget(self, index, option):
        return self.tk.call(
            (self._w, 'itemcget') + (index, '-'+option))

    def itemconfigure(self, index, cnf=None, **kw):
        return self._configure(('itemconfigure', index), cnf, kw)

    itemconfig = itemconfigure


class Menu(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'menu', cnf, kw)

    def tk_popup(self, x, y, entry=""):
        self.tk.call('tk_popup', self._w, x, y, entry)

    def activate(self, index):
        self.tk.call(self._w, 'activate', index)

    def add(self, itemType, cnf={}, **kw):
        self.tk.call((self._w, 'add', itemType) +
                 self._options(cnf, kw))

    def add_cascade(self, cnf={}, **kw):
        self.add('cascade', cnf or kw)

    def add_checkbutton(self, cnf={}, **kw):
        self.add('checkbutton', cnf or kw)

    def add_command(self, cnf={}, **kw):
        self.add('command', cnf or kw)

    def add_radiobutton(self, cnf={}, **kw):
        self.add('radiobutton', cnf or kw)

    def add_separator(self, cnf={}, **kw):
        self.add('separator', cnf or kw)

    def insert(self, index, itemType, cnf={}, **kw):
        self.tk.call((self._w, 'insert', index, itemType) +
                 self._options(cnf, kw))

    def insert_cascade(self, index, cnf={}, **kw):
        self.insert(index, 'cascade', cnf or kw)

    def insert_checkbutton(self, index, cnf={}, **kw):
        self.insert(index, 'checkbutton', cnf or kw)

    def insert_command(self, index, cnf={}, **kw):
        self.insert(index, 'command', cnf or kw)

    def insert_radiobutton(self, index, cnf={}, **kw):
        self.insert(index, 'radiobutton', cnf or kw)

    def insert_separator(self, index, cnf={}, **kw):
        self.insert(index, 'separator', cnf or kw)

    def delete(self, index1, index2=None):
        if index2 is None:
            index2 = index1

        num_index1, num_index2 = self.index(index1), self.index(index2)
        if (num_index1 is None) or (num_index2 is None):
            num_index1, num_index2 = 0, -1

        for i in range(num_index1, num_index2 + 1):
            if 'command' in self.entryconfig(i):
                c = str(self.entrycget(i, 'command'))
                if c:
                    self.deletecommand(c)
        self.tk.call(self._w, 'delete', index1, index2)

    def entrycget(self, index, option):
        return self.tk.call(self._w, 'entrycget', index, '-' + option)

    def entryconfigure(self, index, cnf=None, **kw):
        return self._configure(('entryconfigure', index), cnf, kw)

    entryconfig = entryconfigure

    def index(self, index):
        i = self.tk.call(self._w, 'index', index)
        if i == 'none': return None
        return self.tk.getint(i)

    def invoke(self, index):
        return self.tk.call(self._w, 'invoke', index)

    def post(self, x, y):
        self.tk.call(self._w, 'post', x, y)

    def type(self, index):
        return self.tk.call(self._w, 'type', index)

    def unpost(self):
        self.tk.call(self._w, 'unpost')

    def xposition(self, index): # new in Tk 8.5
        return self.tk.getint(self.tk.call(self._w, 'xposition', index))

    def yposition(self, index):
        return self.tk.getint(self.tk.call(
            self._w, 'yposition', index))


class Menubutton(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'menubutton', cnf, kw)


class Message(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'message', cnf, kw)


class Radiobutton(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'radiobutton', cnf, kw)

    def deselect(self):
        self.tk.call(self._w, 'deselect')

    def flash(self):
        self.tk.call(self._w, 'flash')

    def invoke(self):
        return self.tk.call(self._w, 'invoke')

    def select(self):
        self.tk.call(self._w, 'select')


class Scale(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'scale', cnf, kw)

    def get(self):
        value = self.tk.call(self._w, 'get')
        try:
            return self.tk.getint(value)
        except (ValueError, TypeError, TclError):
            return self.tk.getdouble(value)

    def set(self, value):
        self.tk.call(self._w, 'set', value)

    def coords(self, value=None):
        return self._getints(self.tk.call(self._w, 'coords', value))

    def identify(self, x, y):
        return self.tk.call(self._w, 'identify', x, y)


class Scrollbar(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'scrollbar', cnf, kw)

    def activate(self, index=None):
        return self.tk.call(self._w, 'activate', index) or None

    def delta(self, deltax, deltay):
        return self.tk.getdouble(
            self.tk.call(self._w, 'delta', deltax, deltay))

    def fraction(self, x, y):
        return self.tk.getdouble(self.tk.call(self._w, 'fraction', x, y))

    def identify(self, x, y):
        return self.tk.call(self._w, 'identify', x, y)

    def get(self):
        return self._getdoubles(self.tk.call(self._w, 'get'))

    def set(self, first, last):
        self.tk.call(self._w, 'set', first, last)


class Text(Widget, XView, YView):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'text', cnf, kw)

    def bbox(self, index):
        return self._getints(
                self.tk.call(self._w, 'bbox', index)) or None

    def compare(self, index1, op, index2):
        return self.tk.getboolean(self.tk.call(
            self._w, 'compare', index1, op, index2))

    def count(self, index1, index2, *args): # new in Tk 8.5
        args = ['-%s' % arg for arg in args if not arg.startswith('-')]
        args += [index1, index2]
        res = self.tk.call(self._w, 'count', *args) or None
        if res is not None and len(args) <= 3:
            return (res, )
        else:
            return res

    def debug(self, boolean=None):
        if boolean is None:
            return self.tk.getboolean(self.tk.call(self._w, 'debug'))
        self.tk.call(self._w, 'debug', boolean)

    def delete(self, index1, index2=None):
        self.tk.call(self._w, 'delete', index1, index2)

    def dlineinfo(self, index):
        return self._getints(self.tk.call(self._w, 'dlineinfo', index))

    def dump(self, index1, index2=None, command=None, **kw):
        args = []
        func_name = None
        result = None
        if not command:
            result = []
            def append_triple(key, value, index, result=result):
                result.append((key, value, index))
            command = append_triple
        try:
            if not isinstance(command, str):
                func_name = command = self._register(command)
            args += ["-command", command]
            for key in kw:
                if kw[key]: args.append("-" + key)
            args.append(index1)
            if index2:
                args.append(index2)
            self.tk.call(self._w, "dump", *args)
            return result
        finally:
            if func_name:
                self.deletecommand(func_name)

    def edit(self, *args):
        return self.tk.call(self._w, 'edit', *args)

    def edit_modified(self, arg=None):
        return self.edit("modified", arg)

    def edit_redo(self):
        return self.edit("redo")

    def edit_reset(self):
        return self.edit("reset")

    def edit_separator(self):
        return self.edit("separator")

    def edit_undo(self):
        return self.edit("undo")

    def get(self, index1, index2=None):
        return self.tk.call(self._w, 'get', index1, index2)
    # (Image commands are new in 8.0)

    def image_cget(self, index, option):
        if option[:1] != "-":
            option = "-" + option
        if option[-1:] == "_":
            option = option[:-1]
        return self.tk.call(self._w, "image", "cget", index, option)

    def image_configure(self, index, cnf=None, **kw):
        return self._configure(('image', 'configure', index), cnf, kw)

    def image_create(self, index, cnf={}, **kw):
        return self.tk.call(
                 self._w, "image", "create", index,
                 *self._options(cnf, kw))

    def image_names(self):
        return self.tk.call(self._w, "image", "names")

    def index(self, index):
        return str(self.tk.call(self._w, 'index', index))

    def insert(self, index, chars, *args):
        self.tk.call((self._w, 'insert', index, chars) + args)

    def mark_gravity(self, markName, direction=None):
        return self.tk.call(
            (self._w, 'mark', 'gravity', markName, direction))

    def mark_names(self):
        return self.tk.splitlist(self.tk.call(
            self._w, 'mark', 'names'))

    def mark_set(self, markName, index):
        self.tk.call(self._w, 'mark', 'set', markName, index)

    def mark_unset(self, *markNames):
        self.tk.call((self._w, 'mark', 'unset') + markNames)

    def mark_next(self, index):
        return self.tk.call(self._w, 'mark', 'next', index) or None

    def mark_previous(self, index):
        return self.tk.call(self._w, 'mark', 'previous', index) or None

    def peer_create(self, newPathName, cnf={}, **kw): # new in Tk 8.5
        self.tk.call(self._w, 'peer', 'create', newPathName,
            *self._options(cnf, kw))

    def peer_names(self): # new in Tk 8.5
        return self.tk.splitlist(self.tk.call(self._w, 'peer', 'names'))

    def replace(self, index1, index2, chars, *args): # new in Tk 8.5
        self.tk.call(self._w, 'replace', index1, index2, chars, *args)

    def scan_mark(self, x, y):
        self.tk.call(self._w, 'scan', 'mark', x, y)

    def scan_dragto(self, x, y):
        self.tk.call(self._w, 'scan', 'dragto', x, y)

    def search(self, pattern, index, stopindex=None,
           forwards=None, backwards=None, exact=None,
           regexp=None, nocase=None, count=None, elide=None):
        args = [self._w, 'search']
        if forwards: args.append('-forwards')
        if backwards: args.append('-backwards')
        if exact: args.append('-exact')
        if regexp: args.append('-regexp')
        if nocase: args.append('-nocase')
        if elide: args.append('-elide')
        if count: args.append('-count'); args.append(count)
        if pattern and pattern[0] == '-': args.append('--')
        args.append(pattern)
        args.append(index)
        if stopindex: args.append(stopindex)
        return str(self.tk.call(tuple(args)))

    def see(self, index):
        self.tk.call(self._w, 'see', index)

    def tag_add(self, tagName, index1, *args):
        self.tk.call(
            (self._w, 'tag', 'add', tagName, index1) + args)

    def tag_unbind(self, tagName, sequence, funcid=None):
        self.tk.call(self._w, 'tag', 'bind', tagName, sequence, '')
        if funcid:
            self.deletecommand(funcid)

    def tag_bind(self, tagName, sequence, func, add=None):
        return self._bind((self._w, 'tag', 'bind', tagName),
                  sequence, func, add)

    def tag_cget(self, tagName, option):
        if option[:1] != '-':
            option = '-' + option
        if option[-1:] == '_':
            option = option[:-1]
        return self.tk.call(self._w, 'tag', 'cget', tagName, option)

    def tag_configure(self, tagName, cnf=None, **kw):
        return self._configure(('tag', 'configure', tagName), cnf, kw)

    tag_config = tag_configure

    def tag_delete(self, *tagNames):
        self.tk.call((self._w, 'tag', 'delete') + tagNames)

    def tag_lower(self, tagName, belowThis=None):
        self.tk.call(self._w, 'tag', 'lower', tagName, belowThis)

    def tag_names(self, index=None):
        return self.tk.splitlist(
            self.tk.call(self._w, 'tag', 'names', index))

    def tag_nextrange(self, tagName, index1, index2=None):
        return self.tk.splitlist(self.tk.call(
            self._w, 'tag', 'nextrange', tagName, index1, index2))

    def tag_prevrange(self, tagName, index1, index2=None):
        return self.tk.splitlist(self.tk.call(
            self._w, 'tag', 'prevrange', tagName, index1, index2))

    def tag_raise(self, tagName, aboveThis=None):
        self.tk.call(
            self._w, 'tag', 'raise', tagName, aboveThis)

    def tag_ranges(self, tagName):
        return self.tk.splitlist(self.tk.call(
            self._w, 'tag', 'ranges', tagName))

    def tag_remove(self, tagName, index1, index2=None):
        self.tk.call(
            self._w, 'tag', 'remove', tagName, index1, index2)

    def window_cget(self, index, option):
        if option[:1] != '-':
            option = '-' + option
        if option[-1:] == '_':
            option = option[:-1]
        return self.tk.call(self._w, 'window', 'cget', index, option)

    def window_configure(self, index, cnf=None, **kw):
        return self._configure(('window', 'configure', index), cnf, kw)

    window_config = window_configure

    def window_create(self, index, cnf={}, **kw):
        self.tk.call(
              (self._w, 'window', 'create', index)
              + self._options(cnf, kw))

    def window_names(self):
        return self.tk.splitlist(
            self.tk.call(self._w, 'window', 'names'))

    def yview_pickplace(self, *what):
        self.tk.call((self._w, 'yview', '-pickplace') + what)


class _setit:
    def __init__(self, var, value, callback=None):
        self.__value = value
        self.__var = var
        self.__callback = callback

    def __call__(self, *args):
        self.__var.set(self.__value)
        if self.__callback:
            self.__callback(self.__value, *args)


class OptionMenu(Menubutton):
    def __init__(self, master, variable, value, *values, **kwargs):
        kw = {"borderwidth": 2, "textvariable": variable,
              "indicatoron": 1, "relief": RAISED, "anchor": "c",
              "highlightthickness": 2}
        Widget.__init__(self, master, "menubutton", kw)
        self.widgetName = 'tk_optionMenu'
        menu = self.__menu = Menu(self, name="menu", tearoff=0)
        self.menuname = menu._w
        # 'command' is the only supported keyword
        callback = kwargs.get('command')
        if 'command' in kwargs:
            del kwargs['command']
        if kwargs:
            raise TclError('unknown option -'+kwargs.keys()[0])
        menu.add_command(label=value,
                 command=_setit(variable, value, callback))
        for v in values:
            menu.add_command(label=v,
                     command=_setit(variable, v, callback))
        self["menu"] = menu

    def __getitem__(self, name):
        if name == 'menu':
            return self.__menu
        return Widget.__getitem__(self, name)

    def destroy(self):
        Menubutton.destroy(self)
        self.__menu = None


class Image:
    _last_id = 0

    def __init__(self, imgtype, name=None, cnf={}, master=None, **kw):
        self.name = None
        if not master:
            master = _default_root
            if not master:
                raise RuntimeError('Too early to create image')
        self.tk = getattr(master, 'tk', master)
        if not name:
            Image._last_id += 1
            name = "pyimage%r" % (Image._last_id,) # tk itself would use image<x>
        if kw and cnf: cnf = _cnfmerge((cnf, kw))
        elif kw: cnf = kw
        options = ()
        for k, v in cnf.items():
            if callable(v):
                v = self._register(v)
            options = options + ('-'+k, v)
        self.tk.call(('image', 'create', imgtype, name,) + options)
        self.name = name

    def __str__(self): return self.name

    def __del__(self):
        if self.name:
            try:
                self.tk.call('image', 'delete', self.name)
            except TclError:
                # May happen if the root was destroyed
                pass

    def __setitem__(self, key, value):
        self.tk.call(self.name, 'configure', '-'+key, value)

    def __getitem__(self, key):
        return self.tk.call(self.name, 'configure', '-'+key)

    def configure(self, **kw):
        res = ()
        for k, v in _cnfmerge(kw).items():
            if v is not None:
                if k[-1] == '_': k = k[:-1]
                if callable(v):
                    v = self._register(v)
                res = res + ('-'+k, v)
        self.tk.call((self.name, 'config') + res)

    config = configure

    def height(self):
        return self.tk.getint(
            self.tk.call('image', 'height', self.name))

    def type(self):
        return self.tk.call('image', 'type', self.name)

    def width(self):
        return self.tk.getint(
            self.tk.call('image', 'width', self.name))


class PhotoImage(Image):
    def __init__(self, name=None, cnf={}, master=None, **kw):
        Image.__init__(self, 'photo', name, cnf, master, **kw)

    def blank(self):
        self.tk.call(self.name, 'blank')

    def cget(self, option):
        return self.tk.call(self.name, 'cget', '-' + option)

    def __getitem__(self, key):
        return self.tk.call(self.name, 'cget', '-' + key)

    def copy(self):
        destImage = PhotoImage(master=self.tk)
        self.tk.call(destImage, 'copy', self.name)
        return destImage

    def zoom(self, x, y=''):
        destImage = PhotoImage(master=self.tk)
        if y=='': y=x
        self.tk.call(destImage, 'copy', self.name, '-zoom',x,y)
        return destImage

    def subsample(self, x, y=''):
        destImage = PhotoImage(master=self.tk)
        if y=='': y=x
        self.tk.call(destImage, 'copy', self.name, '-subsample',x,y)
        return destImage

    def get(self, x, y):
        return self.tk.call(self.name, 'get', x, y)

    def put(self, data, to=None):
        args = (self.name, 'put', data)
        if to:
            if to[0] == '-to':
                to = to[1:]
            args = args + ('-to',) + tuple(to)
        self.tk.call(args)

    def write(self, filename, format=None, from_coords=None):
        args = (self.name, 'write', filename)
        if format:
            args = args + ('-format', format)
        if from_coords:
            args = args + ('-from',) + tuple(from_coords)
        self.tk.call(args)

    def transparency_get(self, x, y):
        return self.tk.getboolean(self.tk.call(
            self.name, 'transparency', 'get', x, y))

    def transparency_set(self, x, y, boolean):
        self.tk.call(self.name, 'transparency', 'set', x, y, boolean)


class BitmapImage(Image):
    def __init__(self, name=None, cnf={}, master=None, **kw):
        Image.__init__(self, 'bitmap', name, cnf, master, **kw)


def image_names():
    return _default_root.tk.splitlist(_default_root.tk.call('image', 'names'))


def image_types():
    return _default_root.tk.splitlist(_default_root.tk.call('image', 'types'))


class Spinbox(Widget, XView):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'spinbox', cnf, kw)

    def bbox(self, index):
        return self._getints(self.tk.call(self._w, 'bbox', index)) or None

    def delete(self, first, last=None):
        return self.tk.call(self._w, 'delete', first, last)

    def get(self):
        return self.tk.call(self._w, 'get')

    def icursor(self, index):
        return self.tk.call(self._w, 'icursor', index)

    def identify(self, x, y):
        return self.tk.call(self._w, 'identify', x, y)

    def index(self, index):
        return self.tk.call(self._w, 'index', index)

    def insert(self, index, s):
        return self.tk.call(self._w, 'insert', index, s)

    def invoke(self, element):
        return self.tk.call(self._w, 'invoke', element)

    def scan(self, *args):
        return self._getints(
            self.tk.call((self._w, 'scan') + args)) or ()

    def scan_mark(self, x):
        return self.scan("mark", x)

    def scan_dragto(self, x):
        return self.scan("dragto", x)

    def selection(self, *args):
        return self._getints(
            self.tk.call((self._w, 'selection') + args)) or ()

    def selection_adjust(self, index):
        return self.selection("adjust", index)

    def selection_clear(self):
        return self.selection("clear")

    def selection_element(self, element=None):
        return self.tk.call(self._w, 'selection', 'element', element)

    def selection_from(self, index):
        self.selection('from', index)

    def selection_present(self):
        return self.tk.getboolean(
            self.tk.call(self._w, 'selection', 'present'))

    def selection_range(self, start, end):
        self.selection('range', start, end)

    def selection_to(self, index):
        self.selection('to', index)


class LabelFrame(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'labelframe', cnf, kw)


class PanedWindow(Widget):
    def __init__(self, master=None, cnf={}, **kw):
        Widget.__init__(self, master, 'panedwindow', cnf, kw)

    def add(self, child, **kw):
        self.tk.call((self._w, 'add', child) + self._options(kw))

    def remove(self, child):
        self.tk.call(self._w, 'forget', child)

    forget = remove

    def identify(self, x, y):
        return self.tk.call(self._w, 'identify', x, y)

    def proxy(self, *args):
        return self._getints(
            self.tk.call((self._w, 'proxy') + args)) or ()

    def proxy_coord(self):
        return self.proxy("coord")

    def proxy_forget(self):
        return self.proxy("forget")

    def proxy_place(self, x, y):
        return self.proxy("place", x, y)

    def sash(self, *args):
        return self._getints(
            self.tk.call((self._w, 'sash') + args)) or ()

    def sash_coord(self, index):
        return self.sash("coord", index)

    def sash_mark(self, index):
        return self.sash("mark", index)

    def sash_place(self, index, x, y):
        return self.sash("place", index, x, y)

    def panecget(self, child, option):
        return self.tk.call(
            (self._w, 'panecget') + (child, '-'+option))

    def paneconfigure(self, tagOrId, cnf=None, **kw):
        if cnf is None and not kw:
            return self._getconfigure(self._w, 'paneconfigure', tagOrId)
        if isinstance(cnf, str) and not kw:
            return self._getconfigure1(
                self._w, 'paneconfigure', tagOrId, '-'+cnf)
        self.tk.call((self._w, 'paneconfigure', tagOrId) +
                 self._options(cnf, kw))

    paneconfig = paneconfigure

    def panes(self):
        return self.tk.splitlist(self.tk.call(self._w, 'panes'))

def _test():
    root = Tk()
    text = "This is Tcl/Tk version %s" % TclVersion
    text += "\nThis should be a cedilla: \xe7"
    label = Label(root, text=text)
    label.pack()
    test = Button(root, text="Click me!",
              command=lambda root=root: root.test.configure(
                  text="[%s]" % root.test['text']))
    test.pack()
    root.test = test
    quit = Button(root, text="QUIT", command=root.destroy)
    quit.pack()
    root.iconify()
    root.update()
    root.deiconify()
    root.mainloop()


if __name__ == '__main__':
    _test()


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

正規表現マッチ方法

正規表現マッチ方法

Pythonでの正規表現マッチ方法のメモ

  • 1 import re で正規表現モジュールをインポートする。


  • 2 re.compile()関数を呼び出しRegexオブジェクトを生成する(raw文字列を使う)。
    例:phone_num_regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')


  • 3 Regexオブジェクトのsearch()メソッドに、検索対象の文字列を渡すと、Matchオブジェクトを返す。
    例:mo = phone_num_regex.search('私の電話番号は415-555-4242です。')
    moはMatching objectの意


  • 4 Matchオブジェクトのgroup()メソッドを呼び出し、実際にマッチした文字列を取得する。
    例:print('電話番号が見つかりました: ' + mo.group())
    →電話番号が見つかりました: 415-555-4242


一般的な文字集合を表す短縮形

短縮形 意味
\d 0~9の数字
\D 0~9の数字以外
\w 文字、数字、下線(単語wordのw)
\W 文字、数字、下線以外
\s スペース、タブ、改行(空白spaceのs)
\S スペース、タブ、改行以外

正規表現に用いる記号のまとめ

  • ?は、直前のグループの0回か1回の出現にマッチする。
  • *は、直前のグループの0回以上の出現にマッチする。
  • +は、直前のグループの1回以上の出現にマッチする。
  • {n}は、直前のグループのn回の出現にマッチする。
  • {n,}は、直前のグループのn回以上の出現にマッチする。
  • {,m}は、直前のグループの0~m回の出現にマッチする。
  • {n,m}は、直前のグループのn~m回の出現にマッチする。
  • {n,m}?, *?, +?は、直前のグループの非貪欲マッチを行う。
  • ^spamは、「spam」から始まる文字列とマッチする。
  • spam$は、「spam」で終わる文字列とマッチする。
  • .は、改行文字以外の任意の1文字とマッチする。
  • \d, \w, \sは、それぞれ、数字、単語を構成する文字、空白文字にマッチする。
  • \D, \W, \Sは、それぞれ、数字、単語を構成する文字、空白文字以外の文字にマッチする。
  • [abc]は、角カッコの中の任意の1文字にマッチする。
  • [^abc]は、角カッコの文字以外の任意の1文字にマッチする。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker-compose upを用いてDockerコンテナ上でDjangoを起動する

はじめに

docker-composeを用いてDockerコンテナ上でDjangoを起動させます。Macを使用します。

docker-composeを使う理由

Docknizeされたアプリケーションでは、データベースやミドルウェアのコンテナを分け、複数のコンテナでアプリケーションを構成することがあります。
それぞれのコンテナでDocker runを実行するのは面倒です。その際、docker-composeを用いると複数のコンテナを一つのコマンドで制御することが可能となります。
docker-composeはコンテナの振る舞いをdocker-compose.ymlに記載し制御します。

機能毎にコンテナを分ける構成はAWSのチュートリアルでも紹介されておりマイクロサービスと呼ばれています。
マイクロサービスを意識した構成の利点としてはアプリケーションの開発やテストが機能ごとの小さな単位で実施できる事です。
また、各コンテナを疎結合として設計すると機能毎に独立した開発ができるため、他チームの作業を意識することなく開発、デプロイ、スケールさせることが可能です。
私の経験したスタートアップの開発でも、マイクロサービスを意識した設計をしたことで、並行した開発や小さな機能単位での検証や、テストができ便利でした。

本記事はDjangoアプリをDocker上に構築しAWS Fargateにデプロイするプロジェクトの一部です。

Dcokerfileの作成

下準備として、Pipenvを用いて仮想環境にDjangoをインストールしてください。
詳細手順については別に記事を書いているのでリンクを参照してください。
https://qiita.com/keita_gawahara/items/487a635d226fb0705b13

プロジェクトのルートフォルダにDockerfileを作成します。

$ touch Dockerfile

Dockerfileに以下の内容を追記します。

FROM python:3.7-slim

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

WORKDIR /

COPY Pipfile Pipfile.lock /
RUN pip install pipenv && pipenv install --system

COPY . /

docker buildコマンドでDockerfileをビルドします。

$ docker build .
Sending build context to Docker daemon  155.1kB
...
Step 7/7 : COPY . /
 ---> d239897dhfii9u”
Successfully built d26473003af
$touch docker-compose.yml

docker-compose.ymlに以下の内容を追記します。

version: '3.7'

services:
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    ports:
      - 8000:8000

docker-compose up コマンドを用いてコンテナを起動します。

$ docker-compose up
Creating network...
...
web_1  | System check identified no issues (0 silenced).
web_1  | July 13, 2019 - 16:47:03
web_1  | Django version 2.2.3, using settings 'hello_project.settings'
web_1  | Starting development server at http://0.0.0.0:8000/
web_1  | Quit the server with CONTROL-C.

http://127.0.0.1:8000 をブラウザで表示するとDjango welcome pageが表示されました。これでDocker上にDjangoを起動することができました。

CONTROL-Cで終了させたあとdocker-compose downを用いてコンテナを完全に停止させます。

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

ケモインフォマティクスで学ぶMatplotlib

はじめに

ケモインフォマティクスで学ぶPandasに引き続き、リピドミクス(脂質の網羅解析)を題材として、Pythonの代表的なライブラリの一つである「Matplotlib」について解説していきます。
ケモインフォマティクスの実践例を中心に説明していきますので、基本を確認したいという人は以下の記事を読んでからこの記事を読んでみてください。

製薬企業研究者がMatplotlibについてまとめてみた

散布図

Matplotlibは、グラフ描画のためのライブラリです。
データの傾向を可視化したりするのに使えます。

まずは、importでライブラリを読み込みます。
Jupyter Notebookを使っている場合は、%matplotlib inlineと書くことで、ノートブック上でグラフを描画することができます。

ここで、脂肪酸の炭素原子数や二重結合数と物性との関係を解析することを考えましょう。

%matplotlib inline
import matplotlib.pyplot as plt


abbreviations = ['FA 12:0', 'FA 14:0', 'FA 16:0', 'FA 18:0', 'FA 20:0', 'FA 22:0'] # 脂肪酸分子種の略号
Cns = [12, 14, 16, 18, 20, 22] # 脂肪酸の炭素原子数(鎖長)
logPs = [3.99, 4.77, 5.55, 6.33, 7.11, 7.89] # 脂肪酸分子種のlogPowの値

plt.scatter(Cns, logPs) # 散布図の作成
plt.xlabel('Cn') # x軸ラベル
plt.ylabel('logPow') # y軸ラベル

plt.savefig('logP_saturated-fatty-acids.png') # 散布図を画像ファイル(PNGファイル)として保存
plt.show() # 出来上がった散布図を表示

logP_saturated-fatty-acids.png

上の例では、飽和脂肪酸(炭素鎖に二重結合がない脂肪酸分子種)について、炭素原子数CnsとlogPowlogPsの関係を図示しています。
logPowというのは、「水オクタノール分配係数」で、化合物の疎水性の大きさを示しています。
今回は、logPowの値は、LIPID MAPSを参照しました。
見て分かるように、炭素原子数が多くなるにつれて、logPowの値も大きくなっていますね。
これは、炭素原子数が増えるにつれて、分子の疎水性が増すことを示しています。

不飽和脂肪酸(炭素鎖に二重結合がある脂肪酸分子種)についても同様に考えてみます。

%matplotlib inline
import matplotlib.pyplot as plt


abbreviations = ['FA 18:1', 'FA 18:2', 'FA 18:3', 'FA 18:4']
Uns = [1, 2, 3, 4] # 脂肪酸の炭素鎖の二重結合数(不飽和度)
logPs = [6.11, 5.88, 5.66, 5.44]

plt.scatter(Uns, logPs)
plt.xlabel('Un')
plt.ylabel('logPow')

plt.savefig('logP_C18-fatty-acids.png')
plt.show()

logP_C18-fatty-acids.png

今度は、炭素原子数は同じで、二重結合数(不飽和度)を変えた時に、logPowがどう変わるかを図示しています。
二重結合が増えるにつれて、分子の疎水性が下がることが分かります。

棒グラフ

次にin vitroの実験における細胞中の脂肪酸濃度を図示することを考えます。

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np


concs_ctrl = [0.1, 0.05] # コントロールの実験におけるアラキドン酸、ドコサヘキサエン酸の濃度
concs_cmpd_low = [0.05, 0.07] # 化合物添加(低用量)の実験におけるアラキドン酸、ドコサヘキサエン酸の濃度
concs_cmpd_high = [0.01, 0.08] # 化合物添加(高用量)の実験におけるアラキドン酸、ドコサヘキサエン酸の濃度
x = np.arange(len(concs_ctrl)) # 表示する脂肪酸の数

bar_width = 0.3 # 棒グラフの幅

plt.bar(x, concs_ctrl, width=bar_width, align='center') # Controlの条件の棒グラフ
plt.bar(x+bar_width, concs_cmpd_low, width=bar_width, align='center') # 化合物添加時(低用量)の条件の棒グラフ
plt.bar(x+bar_width*2, concs_cmpd_high, width=bar_width, align='center') # 化合物添加時(高用量)の条件の棒グラフ
plt.xticks(x+bar_width, ['AA', 'DHA']) # x軸データ名
plt.ylabel('Concentration (uM)')
plt.legend(('Control', 'Compound X 0.1uM', 'Compound X 1 uM')) # 凡例

plt.savefig('fatty acid concs.png')
plt.show()

fatty acid concs.png

ここでは、3種類の実験条件で、アラキドン酸(arachidonic acid: AA)とドコサヘキサエン酸(docosahexaenoic acid: DHA)の細胞中濃度がどう変わるかを示しています。
ちなみに、炭素原子数と二重結合数で表すと、AAは「FA 20:4」、DHAは「FA 22:6」です。
化合物Xを細胞に添加すると、AAの産生が抑制され、DHAの産生量が用量依存的に少しずつ増加しているのが分かりますね。
なお、今回の例ではn=1の実験データとしてグラフを作成しており、エラーバーはつけていません。

まとめ

ここでは、Matplotlibについて、ケモインフォマティクスで使える実践的な知識を中心に解説しました。
もう一度要点をおさらいしておきましょう。

  • 2種類のデータの相関を解析する場合には散布図が使え、matplotlib.pyplot.scatterで描けます。
  • 値の大小関係を解析する場合には棒グラフが使え、matplotlib.pyplot.barで描けます。

次回は、scikit-learnについて解説する予定です。

参考資料・リンク

プログラミング言語Pythonとは?AIや機械学習に使える?

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

太陽系の運動をシミュレーションしてみる

趣味で宇宙開発を行う団体「リーマンサット・プロジェクト」がお送りする新春アドベントカレンダーです.まとめ記事はこちらからご覧になれます.

who are you?

アームを展開しての自撮りミッションを目指す10cm立方の超小型人工衛星rsp-01開発チームで,姿勢制御系を務めています.普段は,大学でロケットエンジンの数値計算をしています.

はじめに

ISSの軌道衛星の姿勢を扱う記事が飛び出しましたので,この記事では,さらに遠くの太陽系惑星の運動を表示するところを目指してみたいと思います.
以下が軌道要素をもとに計算した軌道のプロットです.内側から水星,金星,...,海王星を表示しています.図の単位は,太陽と地球の平均距離である1天文単位です.
orbit_1.png

惑星の軌道

1.軌道決定に必要な変数の定義

惑星軌道は楕円形状として決定でき,半長径$a$と離心率$e$が必要です.
2つのパラメータは,2000年1月1日正午を基準とするユリウス世紀$T_{TDB}$を引数として,決定できます.係数は,「ミッション解析と軌道設計の基礎」を参照し付録のelements.pyのように作成しています.

\begin{align}
\sum_{k=1}^4 c_{p,k}{T_{TDB}}^{k-1}
\end{align}

2.ニュートンラプソン法による近点離角の導出

各時刻における衛星の位置を示す平均近点離角$M$も上式により決定されます.惑星の座標を決定するために必要な近点離角$E$をこれまでに得た離心率$e$と平均近点離角$M$を用いて求めます.このときに利用するのが,ケプラー方程式です.

\begin{align}
M=E-e\mathrm{sin}E
\end{align}

この式は,解析解が存在しないので,数値解を用います.ここで,$f(E)$を定義すると

\begin{align}
f(E)&=M-E+e\mathrm{sin}E\\
f'(E)&=e\mathrm{cos}E-1
\end{align}

であり,

\begin{align}
E'&=E-f(E)/f'(E)\\
\end{align}

座標の更新を繰り返すと,下図のように方程式の解に近づきます.$E$の値の変化が十分に小さくなった時点で,反復計算を打ち切ります.
image.png

3.x,y座標系への変換

図のように距離を定義すると,惑星の$x$座標と$y$座標は,楕円の性質を利用して次式のように定義されます.
Elements.png

\begin{align}
x&=a\mathrm{cos}E-ae\\
y&=a\sqrt{1-e^2}\mathrm{sin}E
\end{align}

1.および2.で求めた$a$,$e$,$E$を代入することで,あるユリウス世紀$T_{TDB}$における惑星の位置$x$,$y$が求められました.
1.~3.の計算を繰り返し実行することで,惑星の運動を追うことができます.


本記事は,リーマンサット・プロジェクトアドベントカレンダー内で作成しました.
リーマンサット・プロジェクトは「普通の人が集まって宇宙開発しよう」を合言葉に活動をしている民間団体です.
他では経験できない「宇宙開発プロジェクト」に誰もが携わることができます.
興味を持たれた方は https://www.rymansat.com/join からお気軽にどうぞ.

@kentaniさんの「みんなで人工衛星、1人で家のテレビを遠隔操作」もオススメです.

付録

elements.py
import numpy as np

def elems(num, JC):
    coeff = np.empty((6, 4))
    JC_term = np.array([[1.], [JC], [JC ** 2], [JC ** 3]])

    if num == 1: #mercury
        coeff = np.array([[0.38709831, 0, 0, 0], # semimajor axis: a
                          [0.20563175, 0.000020406   , -0.0000000284,  0.000000017], # eccentricity: e
                          [7.00498600, -0.00595160   , 0.00000081000,  0.000000041], # orbital inclination: i (for 3D)
                          [48.3308930, -0.12542290   , -0.0000883300, -0.000000196], # longitude of the ascending node: Omega ( for 3D)
                          [77.4561190, 0.158864300   , -0.0000134300,  0.000000039], # Perihelion longitude: ~omega
                          [252.250906, 149472.6746358, -0.0000053500,  0.000000002]]) # mean latitude: lamda
    elif num == 2: #venus
        coeff = np.array([[0.72332982, 0, 0, 0],
                          [0.00677188, -0.000047766, 0.0000000975,  0.000000044],
                          [3.39466200, -0.000856800, -0.00003244,  0.000000010],
                          [76.6799200, -0.278008000, -0.00014256, -0.000000198],
                          [131.563707, 0.004864600 , -0.00138232, -0.000005332],
                          [181.979801, 58517.815676, 0.000001650, -0.000000002]])
    elif num == 3: #earth
        coeff = np.array([[1.000001018, 0, 0, 0],           
                          [0.01670862,  -0.0000420370,  -0.0000001236,  0.00000000004],
                          [0.00000000,  0.01305460000,  -0.0000093100,  -0.0000000340],
                          [0.00000000,  0.00000000000,   0.0000000000,  0.00000000000],
                          [102.937348,  0.32255570000,   0.0001502600,  0.00000047800],
                          [100.466449,  35999.3728519,  -0.0000056800,  0.00000000000]])
    elif num == 4: #mars
        coeff = np.array([[1.523679342, 0, 0, 0],
                          [0.093400620, 0.00009048300, -0.0000000806, -0.00000000035],
                          [1.849726000, -0.0081479000, -0.0000225500, -0.00000002700],
                          [49.55809300, -0.2949846000, -0.0006399300, -0.00000214300],
                          [336.0602340, 0.44388980000, -0.0001732100, 0.000000300000],
                          [355.4332750, 19140.2993313, 0.00000261000, -0.00000000300]])
    elif num == 5: #jupiter
        coeff = np.array([[5.202603191, 0.0000001913,             0,           0],
                          [0.048494850, 0.0001632440, -0.0000004719, -0.000000002],
                          [1.303270000, -0.001987200, 0.0000331800 , 0.0000000920],
                          [100.4644410, 0.1766828000, 0.0009038700 , -0.000007032],
                          [14.33130900, 0.2155525000, 0.0007225200 , -0.000004590],
                          [34.35148400, 3034.9056746, -0.0000850100,  0.000000004]])
    elif num == 6: #saturn
        coeff = np.array([[9.554909596, -0.0000021389, 0, 0],
                          [0.055086200, -0.0003468180, 0.0000006456, 0.0000000034],
                          [2.488878000, 0.00255150000, -0.000049030, 0.0000000180],
                          [113.6655240, -0.2566649000, -0.000183450, 0.0000003570],
                          [93.05678700, 0.56654960000, 0.0005280900, 0.0000048820],
                          [50.07747100, 1222.11379430, -0.000085010, 0.0000000040]])
    elif num == 7: #uranus
        coeff = np.array([[19.218446062, -0.0000000372, 0.00000000098, 0],
                          [0.04629590, -0.000027337, 0.0000000790, 0.00000000025],
                          [0.77319600, -0.001686900, 0.0000034900, 0.00000001600],
                          [74.0059470, 0.0741461000, 0.0004054000, 0.00000010400],
                          [173.005159, 0.0893206000, -0.000094700, 0.00000041430],
                          [314.055005, 428.46699830, -0.000004860, 0.00000000600]])
    elif num == 8: #neptune
        coeff = np.array([[30.110386869, -0.0000001663, 0.00000000069, 0],
                          [0.0089880900, 0.00000640800, -0.0000000008, 0],
                          [1.7699520000, 0.00022570000, 0.00000023000, 0.0000000000],
                          [131.78405700, -0.0061651000, -0.0000021900, -0.000000078],
                          [48.123691000, 0.02915870000, 0.00007051000, 0.0000000000],
                          [304.34866500, 218.486200200, 0.00000059000, -0.000000002]])

    temp =  np.dot(coeff, JC_term)
    elements = np.empty((3, 1))
    elements[0] = temp[0]
    elements[1] = temp[1]
    elements[2] = temp[5] - temp[4] # M = lamda - ~omega
    elements[2] = np.deg2rad(elements[2])
    return elements
plotResult.py
import matplotlib.pyplot as plt

def plot_2D(state_x, state_y):
    fig = plt.figure()
    plt.plot(state_x[0, :], state_y[0, :], color = 'skyblue')
    plt.plot(state_x[1, :], state_y[1, :], color = 'yellow')
    plt.plot(state_x[2, :], state_y[2, :], color = 'blue')
    plt.plot(state_x[3, :], state_y[3, :], color = 'red')
    plt.plot(state_x[4, :], state_y[4, :], color = 'orange')
    plt.plot(state_x[5, :], state_y[5, :], color = 'springgreen')
    plt.plot(state_x[6, :], state_y[6, :], color = 'violet')    
    plt.plot(state_x[7, :], state_y[7, :], color = 'purple')
    plt.show()
main.py
import numpy as np
import elements as elems
import plotResult as pltResult

def newtonRaphson(e, meanE):
    E = 2 * meanE
    eps = 1e-10
    while True:
        E -= (meanE - E + e * np.sin(E)) / (e * np.cos(E) - 1)
        if abs(meanE - E + e * np.sin(E)) < eps:
            return E

def main():
    JDbase = 2451545 # Julian century := 0 -> Julian day := 2451545
    JY2JD = 36525 # Julian year = 0 -> Julian Day = 36525
    dJD = 1
    totalJD = 65000
    JD = np.arange(JDbase, JDbase + totalJD, dJD)
    imax = len(JD)
    planet = 8
    dimension = 2

    state_x = np.empty((planet, imax))
    state_y = np.empty((planet, imax))

    temp_elem = np.empty(3, ) # a, e, M
    r = np.zeros((dimension, 1))

    for i in range(0, imax):
        JC = (JD[i] - JDbase) / JY2JD
        for planum in range(1, planet + 1):
            temp_elem = elems.elems(planum, JC)
            E = newtonRaphson(temp_elem[1], temp_elem[2])
            state_x[planum - 1][i] = temp_elem[0][0] * (np.cos(E) - temp_elem[1][0]) #x
            state_y[planum - 1][i] = temp_elem[0][0] * np.sqrt(1 - temp_elem[1][0] ** 2) * np.sin(E) #y

    pltResult.plot_2D(state_x, state_y)

if __name__ == '__main__':
    main()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

よく使うtmuxコマンド

新規セッションの作成

tmux
tmux new -s (セッション名)

tmuxのみだとセッション名が自動で割り当てられる.
セッション名を指定する時は下.

セッションへのアタッチ

tmux a
tmux a -t (セッション名)

-t でセッション名を指定しない場合は,直前にアタッチしていたセッションに繋がる.

セッションから退出

ctrl + d

セッション一覧表示

tmux ls

セッションの削除

tmux kill-session
tmux kill-session -t (セッション名)

-t でセッションを指定しない場合は,直前にアタッチしていたセッションを削除する.

tmux全体を終了

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

PythonスクリプトやJupyterファイルのみから依存パッケージを抽出する

この記事の概要

  • dephell コマンドを使うと Python パッケージの依存関係記述ファイルの相互変換ができる
    • setup.py から requirements.txt を作るとか
  • プロジェクトの Python パッケージの import を読み取って適切なフォーマットに変換できる
  • 依存関係が掲載されていないプロジェクトでも使えるのでオススメ

はじめに

データの前処理や可視化はどうやったの?みたいな話で Jupyter Notebook が残っているけど、特に requirements.txt とか setup.py が残ってない、みたいなケースがままあると思います。

もはや依存関係のバージョンの同定は不可能ですし、ほとんどの場合システムに組み込むとかしないので「動けばいい(再現すればいい)」のですが、そもそも動かすために依存するライブラリの一覧を作るのが一苦労です。ノートブックを開いて1、import 文からサードパーティのライブラリを特定して、requirements.txt を作る単純作業になります。

そんなつまらない作業、自動化したいよな〜思うことでしょう。そんなときに使えるのがDepHellです。下記 1 コマンドだけで、スクリプトの import 文から requirements.txt を作ってくれます。

$ dephell deps convert --from=imports --to=requirements.txt

実施手順

下記プロジェクトを例に説明します。

515hikaru/create-requirement-from-imports

上記リポジトリにはサンプルとして僕がなんとなく書いたノートブックが置いてあります。このサンプルでは下記のように import をしています。

  • 先頭のセルで pandas の import
  • 関数内で matplotlib の import(動的インポート)
  • ノートの後半で PyTorch(torch)と sklearn の import

もちろん(?)プロジェクトには requirements.txt もなんにもありません。この状態から、requirements.txt を作ります。

DepHell のインストール

まずはコマンドをインストールしましょう。Python3.6 以上が必要です。公式のインストール方法に従います。

curl -L dephell.org/install | python3

ちなみに現時点では Windows はサポートできていないようです2

Jupyter Notebook をスクリプトに変換

.ipynb ファイルは jupyter nbconvert コマンドで Python スクリプト形式に変換できます。もちろん、ブラウザでダウンロードする方法もありますが、たくさんノートブックがあるときはコマンドの方が楽に変換できるでしょう。

$ jupyter nbconvert --to script notebook/load_data.ipynb

これで notebook/load_data.py ができるはずです。

いざ変換

変換する前に、Python のパッケージであることを示すために __init__.py を置く必要があります。

$ touch notebook/__init__.py

あとは変換コマンドを実行するだけです。

$ dephell deps convert --from imports --to requirements.txt
$ cat requirements.txt
matplotlib
pandas
scikit-learn
torch

ノートブックに登場していたすべての外部パッケージがリストアップされました。

あとはバージョンを固定するなり、このままリポジトリに add するなり、好きにしましょう。

終わりに

サンプルはたった 4 つだったので手動でやってもたかが知れていますが、実際の現場では複数のモジュールを使っていたりしてあとから全容を把握するのは結構大変ということはあると思います。

DepHell が依存関係の記述の一助になれば幸いです。


  1. ほとんどの場合、ノートは 1 つではなく複数でしょう。 

  2. https://github.com/dephell/dephell/issues/343 

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

requirements.txtの自動生成 〜PythonスクリプトやJupyterファイルのみから依存パッケージを抽出する〜

この記事の概要

  • dephell コマンドを使うと Python パッケージの依存関係記述ファイルの相互変換ができる
    • setup.py から requirements.txt を作るとか
  • プロジェクトの Python パッケージの import を読み取って適切なフォーマットに変換できる
  • 依存関係が掲載されていないプロジェクトでも使えるのでオススメ

はじめに

データの前処理や可視化はどうやったの?みたいな話で Jupyter Notebook が残っているけど、特に requirements.txt とか setup.py が残ってない、みたいなケースがままあると思います。

もはや依存関係のバージョンの同定は不可能ですし、ほとんどの場合システムに組み込むとかしないので「動けばいい(再現すればいい)」のですが、そもそも動かすために依存するライブラリの一覧を作るのが一苦労です。ノートブックを開いて1、import 文からサードパーティのライブラリを特定して、requirements.txt を作る単純作業になります。

そんなつまらない作業、自動化したいよな〜思うことでしょう。そんなときに使えるのがDepHellです。下記 1 コマンドだけで、スクリプトの import 文から requirements.txt を作ってくれます。

$ dephell deps convert --from=imports --to=requirements.txt

実施手順

下記プロジェクトを例に説明します。

515hikaru/create-requirement-from-imports

上記リポジトリにはサンプルとして僕がなんとなく書いたノートブックが置いてあります。このサンプルでは下記のように import をしています。

  • 先頭のセルで pandas の import
  • 関数内で matplotlib の import(動的インポート)
  • ノートの後半で PyTorch(torch)と sklearn の import

もちろん(?)プロジェクトには requirements.txt もなんにもありません。この状態から、requirements.txt を作ります。

DepHell のインストール

まずはコマンドをインストールしましょう。Python3.6 以上が必要です。公式のインストール方法に従います。

curl -L dephell.org/install | python3

ちなみに現時点では Windows はサポートできていないようです2

Jupyter Notebook をスクリプトに変換

.ipynb ファイルは jupyter nbconvert コマンドで Python スクリプト形式に変換できます。もちろん、ブラウザでダウンロードする方法もありますが、たくさんノートブックがあるときはコマンドの方が楽に変換できるでしょう。

$ jupyter nbconvert --to script notebook/load_data.ipynb

これで notebook/load_data.py ができるはずです。

いざ変換

変換する前に、Python のパッケージであることを示すために __init__.py を置く必要があります。

$ touch notebook/__init__.py

あとは変換コマンドを実行するだけです。

$ dephell deps convert --from imports --to requirements.txt
$ cat requirements.txt
matplotlib
pandas
scikit-learn
torch

ノートブックに登場していたすべての外部パッケージがリストアップされました。

あとはバージョンを固定するなり、このままリポジトリに add するなり、好きにしましょう。

終わりに

サンプルはたった 4 つだったので手動でやってもたかが知れていますが、実際の現場では複数のモジュールを使っていたりしてあとから全容を把握するのは結構大変ということはあると思います。

DepHell が依存関係の記述の一助になれば幸いです。


  1. ほとんどの場合、ノートは 1 つではなく複数でしょう。 

  2. https://github.com/dephell/dephell/issues/343 

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

requirements.txtの自動生成 〜Pythonスクリプトから依存パッケージを抽出する〜

この記事の概要

  • dephell コマンドを使うと Python パッケージの依存関係記述ファイルの相互変換ができる
    • setup.py から requirements.txt を作るとか
  • プロジェクトの Python パッケージの import を読み取って適切なフォーマットに変換できる
  • 依存関係が掲載されていないプロジェクトでも使えるのでオススメ

はじめに

データの前処理や可視化はどうやったの?みたいな話で Jupyter Notebook が残っているけど、特に requirements.txt とか setup.py が残ってない、みたいなケースがままあると思います。

もはや依存関係のバージョンの同定は不可能ですし、ほとんどの場合システムに組み込むとかしないので「動けばいい(再現すればいい)」のですが、そもそも動かすために依存するライブラリの一覧を作るのが一苦労です。ノートブックを開いて1、import 文からサードパーティのライブラリを特定して、requirements.txt を作る単純作業になります。

そんなつまらない作業、自動化したいよな〜思うことでしょう。そんなときに使えるのがDepHellです。下記 1 コマンドだけで、スクリプトの import 文から requirements.txt を作ってくれます。

$ dephell deps convert --from=imports --to=requirements.txt

実施手順

下記プロジェクトを例に説明します。

515hikaru/create-requirement-from-imports

上記リポジトリにはサンプルとして僕がなんとなく書いたノートブックが置いてあります。このサンプルでは下記のように import をしています。

  • 先頭のセルで pandas の import
  • 関数内で matplotlib の import(動的インポート)
  • ノートの後半で PyTorch(torch)と sklearn の import

もちろん(?)プロジェクトには requirements.txt もなんにもありません。この状態から、requirements.txt を作ります。

DepHell のインストール

まずはコマンドをインストールしましょう。Python3.6 以上が必要です。公式のインストール方法に従います。

curl -L dephell.org/install | python3

ちなみに現時点では Windows はサポートできていないようです2

Jupyter Notebook をスクリプトに変換

.ipynb ファイルは jupyter nbconvert コマンドで Python スクリプト形式に変換できます。もちろん、ブラウザでダウンロードする方法もありますが、たくさんノートブックがあるときはコマンドの方が楽に変換できるでしょう。

$ jupyter nbconvert --to script notebook/load_data.ipynb

これで notebook/load_data.py ができるはずです。

いざ変換

変換する前に、Python のパッケージであることを示すために __init__.py を置く必要があります。

$ touch notebook/__init__.py

あとは変換コマンドを実行するだけです。

$ dephell deps convert --from imports --to requirements.txt
$ cat requirements.txt
matplotlib
pandas
scikit-learn
torch

ノートブックに登場していたすべての外部パッケージがリストアップされました。

あとはバージョンを固定するなり、このままリポジトリに add するなり、好きにしましょう。

終わりに

サンプルはたった 4 つだったので手動でやってもたかが知れていますが、実際の現場では複数のモジュールを使っていたりしてあとから全容を把握するのは結構大変ということはあると思います。

DepHell が依存関係の記述の一助になれば幸いです。


  1. ほとんどの場合、ノートは 1 つではなく複数でしょう。 

  2. https://github.com/dephell/dephell/issues/343 

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

【Python】四捨五入の罠に掛かりそうだった話

はじめに

業務でPythonを使って試算を行う実装をしていたところ、危うく罠に掛かるところだった話です。

私はただ四捨五入がしたかっただけなのに・・・

「あ、ありのまま 今 起こったことを話すぜ!」

「おれは"2.5"を四捨五入して"3"にしていたと思ったら、いつのまにか"2"になっていた」

「な、何を言っているのかわからねーと思うが、おれも何をされたのかわからなかった・・・」

「頭がどうにかなりそうだった・・・
 計算ミスだとか見間違いだとか、そんなチャチなもんじゃあ断じてねえ
 もっと恐ろしいものの片鱗を味わったぜ・・・」

茶番はこれくらいにして本題

先程話したように、Pythonで四捨五入をしようと思いました。

真っ先に思い浮かぶのは
round関数
format関数

「まーここらへん使えば余裕でしょ」

という思いは突然打ち砕かれた・・・

>>> k=2.5
>>> round(k)
2

「え」

このとき脳内はあの頃、義務教育で習ったはずの四捨五入への不信感に満たされた。

「一体いつから・・・四捨五入で2.5が3になると錯覚していた?」

いやいやいやいや

"2.5"を四捨五入すれば"3"だよね。

でもなんで?

試しにformat関数でも試してみよう

>>> format(k, '.0f')
'2'

ほう。
おまえらグルか。

でもなんで?

調査してみた

調べてみると
この方が調査していて解決策も提示してくれていました。
 ↓  ↓  ↓
python3の四捨五入でハマったのでメモ

こちらの方の記事で原因が最近接偶数への丸めだと判明しました。

最近接偶数への丸め[編集]
最近接偶数への丸め (round to the nearest even; RN) は、端数が0.5より小さいなら切り捨て、端数が0.5より大きいならは切り上げ、端数がちょうど0.5なら切り捨てと切り上げのうち結果が偶数となる方へ丸める。JIS Z 8401で規則Aとして定められていて、規則B(四捨五入)より「望ましい」とされている。
四捨五入ではバイアスが発生する、端数0.5のデータが有限割合で存在する場合でも、バイアスがないのが特徴であり、多数足し合わせても丸め誤差が特定の側に偏って累積することがない(偶数+0.5は現れるが奇数+0.5は現れない、といったような特徴があるデータであれば、やはりバイアスはあらわれる)。
参照:Wikipedia - 端数処理

Python2までは0.5も四捨五入できるらしいけど
Python3はこうなるんだって。

つまり
"2.5"とすると偶数側の"2"になってしまうってことですね。

なので"3.5で行うと"4"になってくれます。

>>> k=3.5
>>> round(k)
4

この仕様ってどこに需要があるんだろうか・・・

解決

先程紹介させていただいた記事に@shiracamusさんが解決策を提示してくれていました。

def round(x):
    return (x*2+1)//2
def round(x,d=0): # 桁数を指定する場合はこのようにする
    p=10**d
    return (x*p*2+1)//2/p

これで解決できました。
@sak_2さん
@shiracamusさん
ありがとうございました。

みなさんもお気を付けください。

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

[勉強メモ]【心理統計】MCMCでの母集団のパラメータ推定

はじめに

この記事は、統計初心者大学生が、ベイズ統計での心理統計学の授業に必死についていくために作成したメモ程度の内容のものです。適宜追加予定です。

TL;DR

ミュラーリヤー錯視実験における錯視量の母集団のパラメータをMCMCで推定してみた

ミュラーリヤー錯視とは

OIP.jpg
同じ長さの線分でも、両端に内向きの矢羽をつけると短く、外向きの矢羽をつけると長く長さを見積もってしまうといったどっかで見たことあるアレです。

設定

ある参加者に対してミュラーリヤー錯視の実験を行った結果、図形Aに対する錯視量(10回測定)は,
23,21,19,22,20,17,22,18,20,25
だったそうです。
この参加者の錯視量の母集団が正規分布すると仮定して、MCMC法で錯視量の母集団のパラメータを求めてみます。

MCMC法とは

乱数発生アルゴリズムのこと。

なぜMCMCを使うのか

自分の中でかみ砕き中。。。

下準備

import numpy as np
import scipy as sp
import scipy.stats as stats
import pandas as pd

from IPython.core.pylabtools import figsize
from matplotlib import pyplot as plt

データの準備

sample_data = [23,21,19,22,20,17,22,18,20,25]
data = pd.Series(sample_data)

pymcを使って乱数発生

ここでは、muとsigmaの事前分布として一様分布を仮定しています。ここでポイントとなるのが、データから妥当な値を推測し、かつある程度幅を持たせた上でパラメータとして渡すことらしいです。

import pymc3 as pm

with pm.Model() as model:
  mu = pm.Uniform('mu', 10, 35)
  sigma = pm.Uniform('sigma', 1, 9)
  ml = pm.Normal('ml', mu=mu, sd=sigma, observed=data)
  trace_g = pm.sample(25000)
chain_g = trace_g[5000:]

pm.traceplot(chain_g)
plt.savefig('traceplot.png', dpi=300, figsize=(5.5, 5.5))

plt.figure()

pm.summary(chain_g)

実行結果

コメント 2020-01-25 165857.jpg
図から、今回のサンプルデータから推測される母集団のパラメータ$\mu$は$21.89$、$\sigma$は$4.00$であることがわかりました。
$\hat{R}$はMCMCにおける収束診断における値であり、1に近いほど良いらしい。

終わりに

仮説検定からの脱却、ということでベイズ統計の勉強を始めましたが、書籍等を読んでいるとチェインとかバーンインとかの単語が飛び交い、またパラメータを得るまでの手続きがややこしいため、途中で「結局これは何をしているんだ?」といった箇所が度々あります。
今まで統計ソフトでバーン!と結果を脳死で算出してきた身からすると、母集団のパラメータを推定するだけでこんな労力が必要なのか・・・と脳がパンク寸前です。

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

勉強議事録:1日目

こんにちは UNIZONです。
ピチピチの社会人2年目です。

これからプログラミングを勉強していこうと思うので、
その議事録として記事を書いていこうと思います。

と言っても完璧なプログラミング初心者ではありません。
大学では情報工学を専攻していたので、ちょっとした考え方とかは分かりますが。。。
如何せん、優秀な同期に恵まれていたので、分かんねえな、と思えばコードを貰ってました(クズ)
てことで、準プログラミング初心者(?)です。

まずは、もう一回勉強しないといけねえな、と思った経緯から自分語りしていこうと思います。

私は今、移動体通信事業者で働いております。
総合職の技術の部署です。
ですが!日常やっている事といえばパートナー会社さんとの打ち合わせやエクセルで集計、
稟議書の作成等、思っていた技術とは程遠い業務です。

全然技術力ない癖に、「なんて古臭い事ばっかやってんじゃこの会社は!!」と
不満をグダグダ言っていたら上司に伝わってしまい、
「そこまで言うなら自動化してみろ!!」と技術部署と自動化部署の2つを兼務する事となりました。

自動化部署の先輩に倣い、エクセルのVBAで自動化を進めていましたが
生意気な2年目、「VBAやだ〜〜Pythonとか使いたい〜〜」と酒の場で言ってしまいました。。。

そうしたら、上司から「じゃあPython使ってもいいよ、うちの会社使える人いないけど。導入するからには一人でも成果出せよ」とのプレッシャー。
言ってしまった手前、やっぱ無理ですとは言えない生意気な2年目。。。

て事で、Pythonを勉強します。
はい、完全に自業自得。
文字に起こすとさらに自分の馬鹿さ加減が浮き彫りになる。恥ずかしい。

業務で何に対してPython使えばいいかも分かんないもん。
稟議ばっか書いてるもん。
だがしかし、啖呵切った手前、何か成果物は出したい(←懲りてない)

て事で、業務終了後に何か作れるよう、勉強していきたいです。
張り切って6年前に購入したMacBook Pro RetinaからMacBook Airに乗り換えました。
(形から入るタイプ)

そしたら全然設定が分かんない。
前は大学の先輩に設定してもらったから、zshとか全然知らない。

て事で、プログラミングを勉強する為に、Macの環境の整え方から勉強していきます。。。

今後は
・Mac開発環境を整える
・Python勉強
 ・paiza
 ・Kaggle
で進めていこうと思います。
絶対一人じゃ出来ない。。。。
いつも先輩・同期に頼ってたもん。。。。

三日坊主にならないよう頑張ります。
第一回目はこれで以上!頑張っていきます。

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

Django--INSTALLED_APPSに関してのソース解析

templarbit-illustration-django-1a748506.jpg

前書き

今回の記事を書くに至る経緯を説明します、teratailでこんな質問がありました、
Djangoのモデルを有効にするときのプロジェクトへの教え方が分からない

質問の内容に関しては以下の通りでした。

DjangoのINSTALLED_APPSのモジュールは何故app名前.apps.app名前configように入れているだろう、
ディレクトリ構成で言えば ../app名前/apps.app名前configのはずではないか。

よって、INSTALLED_APPSに関するDjangoのソースコードを説明したいと思います。
Djangoのコアに興味ある方はぜひ最後までお付き合いください。:relaxed:

下準備

解説するため、django_testという簡単なプロジェクトを作ります、ディレクトリ構成は以下のようです。

djnago_test
|-- django_test
|-- |-- __init__.py
|-- |-- asgi.py
|-- |-- settings.py
|-- |-- urls.py
|-- |-- wsgi.py
|-- manage.py

runserver

Djangoのプロジェクトをコマンドラインから起動します。

python manage.py runserver

では、その後何が起こったのでしょうか、manage.pyの中身を見てみましょう。

manage.py
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()
  • setdefaultenvironにkey、valueの辞書形データを追加します、もしkeyが存在する場合、valueを取得します。
  • managementモジュールをインポート。
  • execute_from_command_line(sys.argv)を実行します。

まず、sys.argvの中身から見ていきます、manage.pyのpathと実行コマンドです。

['manage.py', 'runserver']

次はexecute_from_command_line(sys.argv)の中身を見ます。

management/__init__.py
def execute_from_command_line(argv=None):
    """Run a ManagementUtility."""
    utility = ManagementUtility(argv)
    utility.execute()

内容は非常にシンプルです、sys.argvの値を受け取って、
ManagementUtilityをインスタンス化して、execute関数を実行しました。
ManagementUtility__init__関数を見ていきます。

management.py
    def __init__(self, argv=None):
        self.argv = argv or sys.argv[:]
        self.prog_name = os.path.basename(self.argv[0])
        if self.prog_name == '__main__.py':
            self.prog_name = 'python -m django'
        self.settings_exception = None

この場合:

  • self.arg == sys.argv == ['manage.py', 'runserver']
  • self.prog_name == manage.pyのpath

次を見ていきます。
execute関数は何をやったのでしょう、関数の中身は非常に長いので重要な箇所だけ説明します。

management.py
try:
    subcommand = self.argv[1]
except IndexError:
    subcommand = 'help'

python manage.py runserver実行する際に、subcommandの値はrunserverになります。
そして、下記のブロックに入ります。

management.py
...
if subcommand == 'runserver' and '--noreload' not in self.argv:
   try:
      autoreload.check_errors(django.setup)()
...

django.setupの中身を見ていきます。

django/__init__.py
...
def setup(set_prefix=True):
    """
    Configure the settings (this happens as a side effect of accessing the
    first setting), configure logging and populate the app registry.
    Set the thread-local urlresolvers script prefix if `set_prefix` is True.
    """
    from django.apps import apps
    from django.conf import settings
    from django.urls import set_script_prefix
    from django.utils.log import configure_logging

    configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
    if set_prefix:
        set_script_prefix(
            '/' if settings.FORCE_SCRIPT_NAME is None else settings.FORCE_SCRIPT_NAME
        )
    apps.populate(settings.INSTALLED_APPS)

ここまできたら、 INSTALLED_APPSに関する処理が明らかになってきました、
populateのソースを見ていきます、そこそこ長いので、重要な箇所だけ説明します。

registry.py
...
    def populate(self, installed_apps=None):
        ...
            for entry in installed_apps:
                if isinstance(entry, AppConfig):
                    app_config = entry
                else:
                    app_config = AppConfig.create(entry)
                if app_config.label in self.app_configs:
                    raise ImproperlyConfigured(
                        "Application labels aren't unique, "
                        "duplicates: %s" % app_config.label)

                self.app_configs[app_config.label] = app_config
                app_config.apps = self
...

こちらのinstalled_appsの中身は下記のものになります、ループして、一個づつ取り出して次の処理に入ります。
一つ注意すべき点は'django.contrib.admin'のような内容は、タイプは文字列です。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

ループの中身は、INSTALLED_APPSに入ってる要素に対する継承関係の条件判断になります。

if isinstance(entry, AppConfig):
    app_config = entry
else:
    app_config = AppConfig.create(entry)

もちろん、現在はただの文字列なので、elseのブロックに入ります。

app_config = AppConfig.create(entry)

create()の中身を見てみます。

config.py
    def create(cls, entry):
        ...
        try:
            module = import_module(entry)
        except ImportError:
            module = None
            mod_path, _, cls_name = entry.rpartition('.')

            if not mod_path:
                raise
        ...

ここまできたら、 import_module関数を実際使ってみたいと思います、
usersappを作り、それを INSTALLED_APPSに追加します。

python manage.py startapp users
INSTALLED_APPS= [
...
users or users.apps.UsersConfig
]

usersとして追加される場合。

test.py
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')

from importlib import import_module
print(import_module("users"))
# <module 'users' from '/Users/user/django/django_test/users/__init__.py'>

ちゃんとappを見つけてくれました。

users.apps.UsersConfigとして追加される場合。

test.py
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')

from importlib import import_module
print(import_module("users.apps.UsersConfig"))
# ModuleNotFoundError: No module named 'users.apps.UsersConfig'; 'users.apps' is not a package

app見つからないようです、よって、以下のブロックに入ります。

config.py
except ImportError:
    module = None
    mod_path, _, cls_name = entry.rpartition('.')

    if not mod_path:
       raise

mod_path, _, cls_name = entry.rpartition('.')が実行され、
mod_pathの値がusers.appsになり、cls_nameUsersConfigになります。
再度テストしてみます。

main.py
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')

from importlib import import_module
mod_path, _, cls_name = "users.apps.UsersConfig".rpartition('.')
print(import_module(mod_path))
# <module 'users.apps' from '/Users/user/django/django_test/users/apps.py'>

appを見つけてくれました。

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

「日程くん」の結果をスクレイピングする

概要

先日、2020明治安田生命Jリーグの日程が発表されました。(リリース
このリリースにはPDF形式でJ1・J2・J3リーグの日程が提供されています。
また、Jリーグでは様々なデータを試合軸・チーム軸・選手軸で別サイトに提供しています。

Jleague Data Site

本投稿は、PDF形式をスクレイピングすのではなく、上記サイトで提供されている「日程・結果」メニューから得られるページをpandasが提供するread_htmlを使って簡単に取得します。

URL構成

https://data.j-league.or.jp/SFMS01/search?competition_years=2020&competition_frame_ids=1&competition_ids=477&tv_relay_station_name=
  • 基本:https://data.j-league.or.jp/
  • アプリ名?:SFMS01
  • パラメータ1:competition_years=2020 #年度
  • パラメータ2:competition_frame_ids=1 #カテゴリー(J1)
  • パラメータ3:competition_ids=477 #年度ごとのID
  • それ以外は固定のまま

コード説明

game_schedule.py
# cording:uft-8
import pandas as pd
yyyy = 2020
url = 'https://data.j-league.or.jp/SFMS01/search?'
category = {'1': 477, '2': 478, '3': 479}
schedule = pd.DataFrame(index=None, columns=['年度', '大会', '節', '試合日', 'K/O時刻', 'ホーム', 'スコア', 'アウェイ', 'スタジアム', '入場者数', 'インターネット中継・TV放送'])

J1・J2・J3のカテゴリーと年度ごとのIDをdic形式で作成する。
空のデータフレームを作成する。

game_schedule.py
for key, value in category.items():
    para = 'competition_years=' + str(yyyy)
    para1 = '&competition_frame_ids=' + str(key)
    para2 = '&competition_ids=' + str(value)
    para3 = '&tv_relay_station_name='

    full_url = url + para + para1 + para2 + para3
    # print(full_url)
    df = pd.read_html(full_url, attrs={'class': 'table-base00 search-table'}, skiprows=0)
    schedule = pd.concat([schedule, df[0]], sort=False)

ポイントは、pd.read_html(full_url, attrs={'class':'table-base00 search-table'}...で、対象のURLと<table>の属性を指定しています。
取得したものをscheduleに結合します。

game_schedule.py
# NaNを置き換えたければ
# schedule = schedule.fillna({'KO時刻': '●未定●', '入場者':0})
schedule.to_csv('./csv/Game_Schedule_' + str(yyyy) + '.csv', index=False, sep=',')

指定フォルダにcsv形式で保存します。

まとめ

  • シンプルな<table>pandasread_htmlで簡便に取得できる。

データの活用

  • 応援するチームのみ抽出して、遠征するスケジュールに利用する。
  • 試合後は、スコアや入場者数の実績が登録されるので分析に利用できる。

「日程くん」について

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

10分で分かるpandasその1

10分で分かるpandas

はじめに

この記事はpandas公式チュートリアル「10 minutes to pandas」の写経及び解説です

以下のURLを参考にしています
https://pandas.pydata.org/pandas-docs/stable/getting_started/10min.html

環境

  • Python3.7
  • Jupyter Lab

とりあえずインポート

import numpy as np
import pandas as pd
np
pd

以下のように各モジュールが表示されればOK
スクリーンショット 2020-01-25 11.51.03.png

ModuleNotFoundError: No module named 'pandas'と怒られたのでpandasをまず入れます。

---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-1-59ab05e21164> in <module>
      1 import numpy as np
----> 2 import pandas as pd

ModuleNotFoundError: No module named 'pandas'

コマンド
python -m pip install pandas

オブジェクトを作る

参考:【10 minutes to pandas - Object creation】

Seriesクラスにリストを入れることで簡単にデータを作ることが出来ます。

# 簡単に一列作る
s = pd.Series(data=[1, 3, 5, np.nan, 6, 8])
s

スクリーンショット 2020-01-25 12.05.34.png

参考:pandas.Series

date_range()メソッドを使うことで、特定の期間の日付の行を作成出来ます。

# 2020年1月1日から6日間のデータ
dates = pd.date_range("20200101", periods=6)
dates

スクリーンショット 2020-01-25 12.14.36.png

参考:pandas.date_range()

pandasのDataFrameクラス引数indexを指定することで、行インデックスを指定することが出来ます。

# 行インデックスに2020年1月1日からのデータを指定
# 各値にはランダムな数値を入れる
df = pd.DataFrame(np.random.randn(6, 4), index=dates)
df

スクリーンショット 2020-01-25 12.20.49.png

また、同じくDataFrameクラスの引数columnsを指定することで列名を設定することが出来ます。

# 列名ABCDを設定
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list("ABCD"))
df

スクリーンショット 2020-01-25 13.54.51.png

参考:pandas.DataFrame

DataFrameクラスに辞書型のデータを渡すことで、辞書型のキーの部分が列名になります。

df2 = pd.DataFrame(
    {
        "A": 1.,
        "B": pd.Timestamp("20200101"),
        "C": pd.Series(1, index=list(range(4)), dtype="float32"),
        "D": np.array([3] * 4, dtype="int32"),
        "E": pd.Categorical(["test", "train", "test", "train"]),
        "F": "foo",
    }
)
df2

スクリーンショット 2020-01-25 14.08.34.png

dtypes属性に参照することで各列のデータ属性が分かります。

df2.dtypes

スクリーンショット 2020-01-25 14.10.58.png

Jupyter Labなどを使っている場合、列名がタブ保管で表示されます。

db2.<TAB>

スクリーンショット 2020-01-25 14.13.28.png

データを表示する

参考:【10 minutes to pandas - Viewing data】

DataFrameクラスのhead()メソッドを使うことでデータの先頭部を表示できます。

df.head(2)

スクリーンショット 2020-01-25 14.21.33.png

参考:DataFrame.head()

同じくDataFrameクラスのtrail()メソッドを使うことでデータの後尾部を表示できます。

df.tail(2)

スクリーンショット 2020-01-25 14.35.10.png

参考:DataFrame.tail()

DataFrameクラスのindex属性を参照することでそのデータの行インデックスを表示出来ます。

df.index
df2.index

スクリーンショット 2020-01-25 14.36.33.png

参考:DataFrame.index

DataFrameクラスのto_numpy()メソッドを使うことでデータをnumpyで操作しやすいデータに変換できます。

df.to_numpy()
df2.to_numpy()

スクリーンショット 2020-01-25 15.25.48.png

参考:DataFrame.to_numpy()

DataFrameクラスのdescribe()メソッドを使うことで、データの各列の簡単な統計を取ることができます。

df2.describe()

スクリーンショット 2020-01-25 15.44.36.png
参考:DataFrame.describe()

DataFrameクラスのT属性を参照すると、行列入れ替えたデータにアクセスできます。

df.T

スクリーンショット 2020-01-25 15.48.59.png

また、DataFrameクラスのtranspose()メソッドでも同じく行列の入れ替えを取得できます。

df.transpose()

スクリーンショット 2020-01-25 16.00.49.png

参考:DataFrame.T
参考:DataFrame.transpose

DataFrameクラスのsort_index()メソッドを使用することで、行全体もしくは列全体の並び替えを行うことができます。

df.sort_index()

スクリーンショット 2020-01-25 16.10.23.png

引数axisに0もしくは"index"を設定すると行に、1もしくは"columns"を設定すると、列を軸に並び替えします(デフォルト値0)。また、引数ascendingにFalseを指定すると並び順が降順になります(デフォルト値True)。

df.sort_index(axis=0, ascending=False)
df.sort_index(axis=1, ascending=False)

スクリーンショット 2020-01-25 16.12.40.png

参考:DataFrame.sort_index()

DataFrameクラスのsort_values()メソッドを使用することで行単位もしくは列単位に並び替えを行うことができます。

df.sort_values(by="B")
df.sort_values(by="2020-01-01", axis=1)

スクリーンショット 2020-01-25 16.45.17.png

参考:DataFrame.sort_values()

(ここで力尽きる。残り……多くない?10分とは:thinking:

参考:【10 minutes to pandas - Selection】
参考:【10 minutes to pandas - Missing data】
参考:【10 minutes to pandas - Operations】
参考:【10 minutes to pandas - Merge】
参考:【10 minutes to pandas - Grouping】
参考:【10 minutes to pandas - Reshaping】
参考:【10 minutes to pandas - Time series】
参考:【10 minutes to pandas - Categoricals】
参考:【10 minutes to pandas - Plotting】
参考:【10 minutes to pandas - Getting data in/out】
参考:【10 minutes to pandas - Gotchas】

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

pythonによる統計学

合計と平均

numpy.sum(data) #合計
numpy.mean(data) #平均

最大値と最小値、及び中央値

numpy.amax(data)
numpy.amin(data)
numpy.median(data)

分散

「データが平均値からどれほど離れているか」を表す指標

\sigma^2=\frac{1}{N}\sum_{i=1}^{n} (x_i-\mu)^2
numpy.var(data, ddof = 0)

不偏分散

標本分散は、標本平均を用いてさらに分散を計算した値だが、この値は、過小に見積もってしまうというバイアスが起こる。

そこでバイアスをなくしたものが普遍分散となる

\sigma^2=\frac{1}{N-1}\sum_{i=1}^{n} (x_i-\mu)^2
numpy.var(data, ddof = 1)

以降、不偏分散を利用する。

標準偏差

分散の平方根をとったもの

\begin{align}
\sigma&=\sqrt{\sigma^2}\\
&=\frac{1}{N-1}\sum_{i=1}^{n} (x_i-μ)^2
\end{align}
numpy.std(data, ddof=1)

共分散

  • 共分散が0よりも大きい時
    →片方の変数が大きい値をとれば、もう片方も大きくなる
    →正の相関がある。
  • 共分散が0よりも小さい時
    →片方の変数が大きい値をとれば、もう片方がは小さくなる
    →負の相関がある。
Cov(x,y)=\frac{1}{N}\sum_{i=1}^{n-1} (x_i-\mu_x)(y_i-\mu_y)

print(cov_data)
スクリーンショット 2020-01-25 17.37.23.png

# データの取り出し
x = cov_data["x"]
y = cov_data["y"]
# サンプルサイズ
N = len(cov_data)
# 平均値の計算
mu_x = sp.mean(x)
mu_y = sp.mean(y)
# 共分散
cov = sum((x - mu_x) * (y - mu_y)) / (N - 1)

分散共分散行列

Cov(x,y)=
\begin{bmatrix}
\sigma_x^2 & Cov(x,y) \\
Cov(x,y) & \sigma_y^2 
\end{bmatrix}
np.cov(x, y, ddof = 1)

行列から値を取り出す時

hoge = np.cov(x, y, ddof = 1)
cov = hoge[1,0]

ピアソンの積率相関係数

共分散を、最大値1、最小値1に標準化したもの。

\rho_{xy}=\frac{Cov_{(x,y)}}{\sqrt{\sigma_x^2\sigma_y^2}}
# 分散の計算
sigma_2_x_sample = sp.var(x, ddof = 0)
sigma_2_y_sample = sp.var(y, ddof = 0)
# 相関係数
cov_sample / sp.sqrt(sigma_2_x_sample * sigma_2_y_sample)

相関行列

Cov_{(x,y)}=
\begin{bmatrix}
1 & \rho_{xy} \\
\rho_{xy} & 1
\end{bmatrix}
numpy.corrcoef(x,y)

標準化

データの平均を0,標準偏差を1にする変換のこと。すなわち、各データから平均値を引き、標準偏差で割ったもの。

standerd = (data - numpy.mean(data)) / numpy.std(data, ddof=1)

確率密度

連続型変数1における確率のこと。
連続型変数の時、特定の値の確率は常に0となってしまう。というのも、なんらかの値は小数点以下が無限に続いているためである。例えば、人の身長が160センチちょうどということはありえないということである。しかし、「159センチ以上160センチ以下の人の確率」なら求めることができる。その確率のことが「確率密度」である。
e.g. 0から最大値までの確率密度は1となる。

c.f.離散型変数2における確率が多くの人が学校で習う確率のことである。(P(x)=1/4)

特に、実数値をとる変数Xがx<=X<=x+⊿xをとる確率を考える際、⊿x→0の時、P(x)をxの確率密度という。

確率変数

確率を計算する時、計算の対象となる変数を確率変数という。
x=2となる確率が1/3であるとする。このときの2が確立変数である。

正規分布の確率密度関数

N(x|\mu, \sigma^2)=\frac{1}{\sqrt{2\pi\sigma^2}}e^{-{\frac{(x-\mu)^2}{2\sigma^2}}}

例:確率変数x=3、平均=4、標準偏差=0.8の時

>>>x = 3
>>>mu = 4
>>>sigma = 0.8
>>>1 / (numpy.sqrt(2 * sp.pi * sigma**2)) * numpy.exp(- ((x - mu)**2) / (2 * sigma**2))
>>>0.228

また、下の関数で簡単にできる。

>>>stats.norm.pdf(loc = 4, scale = 0.8, x = 3)
>>>0.228

累積分布関数と下側確率、パーセント点

F(x)=P(X\leq x)

のように表される関数のこと。
すなわち、「ある値以下となる確率を計算する関数」のこと。
ここで得られた値を下側確率という。また、この時のxをパーセント点という。
正規分布の時は下の積分計算で求められる。

P(X\leq x)=\int_{-\infty}^{x}\frac{1}{\sqrt{2\pi\sigma^2}}e^{-{\frac{(x-\mu)^2}{2\sigma^2}}}dx
>>>import scipy as sp
>>>from scipy import stats
>>>stats.norm.cdf(loc = 4, scale = 0.8, x = 3) #locは平均、scaleは標準偏差
>>>0.106

パーセント点を求める関数-ppf関数

下側確率が2.5%となるパーセント点

>>>stats.norm.ppf(loc = 4, scale = 0.8, q = 0.025)
>>>2.432

t値とt値の標本分布

t=\frac{\hat{\mu}-\mu}{\frac{\hat{\sigma}}{\sqrt{N}}}

すなわち、

t値=\frac{標本平均-母平均}{標準誤差}

となる。この試行を複数回繰り返したものの分布がt値の標本分布である。

t分布

母集団分布が正規分布である時のt値の標本分布のことをt分布という。


  1. 小数点以下の値をとり、連続的に変化するもの。
    例:xセンチ←3センチ、4.5センチ 

  2. 整数しか取らないもの。
    例:一つ。 

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

【#3】PythonでMinecraftを作る。~プレイヤーの動きの改善(慣性の概念)と衝突判定~

Part of pictures, articles, images on this page are copyrighted by Mojang AB.

minecraft.png

概要

世界的に超有名なサンドボックスゲーム「Minecraft」をプログラミング言語「Python」で再現するプロジェクトです。

前回の記事: 「【#2】PythonでMinecraftを作る。~モデル描画とプレイヤー実装~」

今回やること

前回は、テストテクスチャを使用してのモデル描画からプレイヤー視点の実装までを行いました。

  • プレイヤーの動きの改善
  • 衝突判定の検討

プレイヤーの動きの改善

sq6py-82p4x.gif
前回実装したプレイヤーの動きは不自然だと思いませんか?
これは、「キーを押した時にだけ移動」している為です。
大半の3Dゲームではプレイヤーはスムーズに動きますが、実は内部的にはプレイヤーやオブジェクトの動きは工夫がなされています。
bo5ie-4w21m.gif

なぜ動きが不自然?

あるオブジェクトやエンティティを時間経過で移動させたい時、例えばfor文やwhile文で繰り返し処理を行ってしまうと、フレーム毎の速度がコンピュータの性能に左右され、本当の意味では「実際の時間」とは言えません。
説明が難しい。分かりにくかったらごめんなさい。

動きが不自然であるのは、プレイヤーの速度が一定であることと、滑らないことが原因と考えられます。
段ボール箱を蹴っても、よほど摩擦力が働く場所でない限り、「キュッ!」と止まることは通常ありませんよね。

解決策

プレイヤーの動きを改善する上において、「dt(DeltaTime)」というデルタ時間がカギになります。
デルタ時間前回のフレームを処理してから今回のフレームが実行されるまでの間に何秒経過したのかを表します。

具体的には、デルタ時間を活用して「Inertia(慣性)」という概念をプレイヤーに対して導入します。
関数on_key_press()はキーボードのボタンを押してから離すまで情報をプレイヤーに渡しますから、キーが押されている間、ある値を仮にnと定義すると、nを押している時間と比例して増加させます。

プログラム中では、nをそれぞれvelocity_xvelocity_zと定義しました。
※Velocity = 速度

#プレイヤーのアップデートイベント
def update(self, dt, keys):
    if keys[key.W]:#front
        self.position[0] += dx #通常の移動処理
        self.position[2] -= dz #通常の移動処理
        self.velocity_x += dt * 10 #dtは非常に小さい値なので10を乗算します

このままでは、velocityは押している時間に比例して、いつまでも増加してしまいます。
そこでupdate時にvelocityの値を一定規則で減らします。

次に最大速度を設定し、値が負であるか、最大速度を超えていないかチェックを行います。
値が負であれば0に戻し、最大速度を超えていれば最大速度に戻します。

player.update()関数内
#現在の値を50で割ったものを減算します
self.velocity_x -= self.velocity_x / 50
self.velocity_z -= self.velocity_z / 50

#負の値であれば0に戻します
if self.velocity_x < 0: self.velocity_x = 0
if self.velocity_z < 0: self.velocity_z = 0

max_inertia_speed = 0.2 #値の大きさに比例して滑ります

#最大速度を超えていれば最大速度に戻します
if self.velocity_x > max_inertia_speed: self.velocity_x = max_inertia_speed
if self.velocity_z > max_inertia_speed: self.velocity_z = max_inertia_speed

#前進にはたらく慣性
self.position[0] += self.velocity_x * dx #ローテーションを考慮に入れつつ現在の座標に足す
self.position[2] -= self.velocity_z * dz #ローテーションを考慮に入れつつ現在の座標から引く

試しに実行すると、以下の様に慣性があることが確認できます。
また、左上のデバッグウィンドウのVelocityも時間に比例して減っていることが確認できます。
p8r6m-2cy1g.gif
これでやっと不自然さが無くなりましたね。
本来のマインクラフトの動きを再現できました。

問題点

斜め移動には対応していません。

衝突判定の実装

p4xs6-53ohi.gif
MinecraftをUnity等のツールを使用せず実現するにあたって、これが一番の課題です。
全てが1.0×1.0のブロックであれば比較的容易に実装できる(できそう)のに対して、ブロックごとにカスタムで衝突判定(例えば階段ブロックやドア)を実装することを考えると、非常に大きな壁な気がしています。

MinecraftではAABB(Axis-Aligned Bounding Box)で自由にブロックの衝突判定や見た目上だけのバウンディングボックスを定義できます。
それをPythonでも実装したい。流石に厳しいだろうか。
個人的には、Minecraftをデコンパイルして難読化されたソースコードを根性で読む、程度しか思い付きません。

衝突判定について詳しい方がいらっしゃいましたら、是非コメント欄でアドバイスを頂きたいです。
image.png

続く

現状はこんな感じです。
※動画サイズの関係でgifアップロードできませんでした。
衝突判定がどうにかなれば、後はひたすらコーディングするだけって感じですね。

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

部分一致したものに数値を代入する方法(備忘録①)

使用データ

#使用データ
df
name room_type
0 ホテルA スーペリアツインルーム禁煙
1 ホテルB スーペリアツインルーム喫煙
2 ホテルC デラックスツインルーム
3 ホテルD スタンダードツインルーム禁煙
4 ホテルE ダブルルーム
5 ホテルF デラックスダブルルーム禁煙
6 ホテルG スタンダードツインルーム禁煙
7 ホテルH デラックスキングルーム

このようなものを用意しました。

Goal

room_typeに'スーペリア'、'デラックス'と名前がつくものに1、そうでないものに0を付与した新しいカラムを生成する。

実施事項

new_room_type_list = []

for i in range(8):
    if 'スーペリア' in df['room_type'][i]:
        a = 1
    elif 'デラックス' in df['room_type'][i]:
        a = 1
    else:
        a = 0
    new_room_type_list.append(a)

このようにしてlistを作成
その後dfに追加する。

#dfに作成したnew_room_type_listをdf['new_room_type']として追加する。
df['new_room_type'] = new_room_type_list

確認してみる

df
name room_type new_room_type
0 ホテルA スーペリアツインルーム禁煙 1
1 ホテルB スーペリアツインルーム喫煙 1
2 ホテルC デラックスツインルーム 1
3 ホテルD スタンダードツインルーム禁煙 0
4 ホテルE ダブルルーム 0
5 ホテルF デラックスダブルルーム禁煙 1
6 ホテルG スタンダードツインルーム禁煙 0
7 ホテルH デラックスキングルーム 1

こんな感じでうまく追加することができた。

おまけ:.str.contains()の使用

df['room_type'].str.contains('スーペリア')

0 True
1 True
2 False
3 False
4 False
5 False
6 False
7 False
Name: room_type, dtype: bool

このようにどの行に'スーペリア'が出てくるなどはわかるが、.str.contains()はDataFrame全体に及ぶものなので1行1行をみていくif文などには向かないと判断したため上記の方法を用いた

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

pythonでのグラフ描画

折れ線グラフの描画

これをjupyter notebookで行うとする。
ターミナル上で行うと、ファイルにグラフを保存する必要がある。保存するためには、plt.savefig("ファイル名")とする。

pyplotによる描画

# 数値計算に使うライブラリ
import numpy as np
import pandas as pd

# グラフを描画するライブラリ
from matplotlib import pyplot as plt

# グラフをjupyter Notebook内に表示させるための指定
%matplotlib inline

x = np.array([0,1,2,3,4,5,6,7,8,9])
y = np.array([2,3,4,3,5,4,6,7,4,8])

plt.plot(x, y, color = 'black')
plt.title("lineplot matplotlib")
plt.xlabel("x")
plt.ylabel("y")

スクリーンショット 2020-01-25 15.33.26.png

seabornによる描画

import seaborn as sns
sns.set()

plt.plot(x, y, color = 'black')
plt.title("lineplot seaborn")
plt.xlabel("x")
plt.ylabel("y")

スクリーンショット 2020-01-25 15.37.35.png

ヒストグラムの描画

data = np.array([2,3,3,4,4,4,4,5,5,6])
sns.distplot(data, bins = 5, 
             color = 'black', kde = False)

hist.png

  • binsでデータをいくつのグループに分けるかを定義する。
  • kdeでカーネル密度推定1の表示/非表示を設定
sns.distplot(fish_data, color = 'black' norm_hist=True)


- norm_histによりヒストグラムの面積の合計が1になるように縦軸が変更される。

箱ひげ図

sns.boxplot(x = "species", y  = "length", 
            data = multi, color = 'gray')

スクリーンショット hako_hige.png

バイオリンプロット

カーネル密度推定の結果を用いたもの

sns.violinplot(x = "species", y  = "length", 
               data = multi, color = 'gray')

棒グラフ

sns.barplot(x = "species", y  = "length", 
            data = fish_multi, color = 'gray')

スクリーンショット 2020-01-25 16.08.15.png

散布図

sns.jointplot(x = "x", y = "y", 
              data = cov_data, color = 'black')

参考

あたらしいPythonで学ぶ統計学の教科書 馬場真哉


  1. 統計学において、確率変数の確率密度関数を推定するノンパラメトリック手法のひとつ。 

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

pipをupgradeしたら抜け出せなくなった

事の発端

numpyの更新がなんか上手くいかない。
原因を探っている内にpipのバージョンが古いことが原因らしき場面に直面しました。
なので書いてあるがままに更新を実行。

pip install --upgrade pip

これで一安心と思い、再度実行してみると

Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\Scripts\pip-script.py", line 10, in <module>
    sys.exit(main())
TypeError: 'module' object is not callable

今度はどうやら、バージョンの互換が合わなくなった?のが原因っぽいです。
じゃあpipをアンインストールしても同じエラーでできず
また調べていると

python -m pip uninstall pip

これでアンインストール完了。
ですが

pipのインストールってどうやるんだ…?

素人が出てしまいました。
ですがここであきらめてはもう何も作業ができなくなる。
素直にGoogle先生に聞いてみました。
すると、stackoverflowからこんなサイトに辿り着きました(投稿者もpipの入れ方を探していた様です)。

※以降の実行は自己責任でお願いします。筆者は成功しました。
How to Install PIP on Windows
https://www.liquidweb.com/kb/install-pip-windows/
参照先のLiquidWebさんはウェブホスティングサービスを提供されている会社らしく
信用して手順を使ってみようと思います。
エンジニアとしてそれはどうなの・・・
と思いますが、これ以上時間を使いたくありません。
get-pip.py
参照先をファイルとして保存し、プロンプト上から実行しました。

python get-pip.py

すると

Collecting pip
  Downloading https://files.pythonhosted.org/packages/57/36/67f809c135c17ec9b8276466cc57f35b98c240f55c780689ea29fa32f512/pip-20.0.1-py2.py3-none-any.whl (1.5MB)
     |████████████████████████████████| 1.5MB 1.6MB/s
Installing collected packages: pip
  Found existing installation: pip 19.2.3
    Uninstalling pip-19.2.3:
      Successfully uninstalled pip-19.2.3
Successfully installed pip-20.0.1

成功した!
そのあとのnumpyの更新もなぜか上手くいき、とりあえず解決ということで。。。

所感

モジュールのバージョンが原因のエラーは厄介です
自動的に更新できればいいんですけどねぇ。
駄文でしたが閲覧いただきありがとうございました。

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

PyTorchでDatasetの読み込みを実装してみた

概要

機械学習の勉強を始めてまだ半年の私がなんとかPyTorchでDatasetを作ったので覚え書きついでに投稿します。
GANの勉強でGitHubからコードを落として勉強していたのですが、MNISTやCIFARの読み込みしかしてなかったため、自分の持っているデータセットで実行したくなってDatasetを自作しました。
(記事投稿の練習もかねての記事なのであしからず。。。)

環境

  • 実行環境:PyCharm
  • python:3.6(Anaconda)
  • torch:1.3.1
  • torchvision:0.4.2

Datasetの必須条件

  • PyTorchのDatasetの継承
    学習モデルに渡す際に、DataLoaderにこのDataset継承クラスのオブジェクトを渡すため

  • __getitem__と__len__のメソッド
    __getitem__はデータとラベルをタプルで返すメソッド
    __len__はそのまま意味で、データ数を返すメソッド

なので、基本的な構成としてはこうなります。

class MyDataset(torch.utils.data.Dataset):

    def __init__(self, imageSize, dir_path, transform=None):
        pass

    def __len__(self):
        pass

    def __getitem__(self, idx):
        pass

クラスへの引数としてはデータへのPath以外に、画像の入力サイズと前処理のためのtransformを渡しました。

コンストラクタの定義

クラス生成時に自動で呼び出されるコンストラクタでは、以下の処理を行います。

  • transformの定義
  • すべてのデータパスの読み込み
  • クラス名の定義及び辞書化
    def __init__(self, imageSize, dir_path, transform=None):
        self.transform = transforms.Compose([
            transforms.Resize(imageSize), # 画像のリサイズ
            transforms.ToTensor(), # Tensor化
            transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), # 標準化
        ])

        # ここに入力データとラベルを入れる
        self.image_paths = [str(p) for p in Path(dir_path).glob("**/*.png")]

        self.data_num = len(self.image_paths) # ここが__len__の返り値になる
        self.classes = ['carpet', 'ceramic', 'cloth', 'dirt', 'drywall', 'glass', 'grass', 'gravel', 'leaf', 'metal']
        self.class_to_idx = {'carpet':0, 'ceramic':1, 'cloth':2, 'dirt':3, 'drywall':4, 'glass':5, 'grass':6,'gravel':7, 'leaf':8, 'metal':9}

マテリアル多分類のデータを持っていたので、それを使用しました。

__getitem__の定義

__getitem__は学習時にデータとその正解ラベルを読み込むためのメソッドなので、コンストラクタで読み込んだ情報を使って実装していきます。

    def __getitem__(self, idx):
        p = self.image_paths[idx]
        image = Image.open(p)

        if self.transform:
            out_data = self.transform(image)

        out_label = p.split("\\")
        out_label = self.class_to_idx[out_label[3]]

        return out_data, out_label

画像データはコンストラクタで読み込んでもいいと思いますが、データ数が多いとメモリが心配だったのでその都度読み込むことにしました。
クラスラベルにおいてもわざわざ辞書化するというちょっとめんどくさい方法を使ってます。

DataLoaderへの引き渡し

実際にコード中で読み込むときは、以下のように使えば学習に使えます。
(DataLoaderの引数shuffleは、dataの参照の仕方をランダムにする)

    data_set = MyDataset(32, dir_path=root_data)
    dataloader = torch.utils.data.DataLoader(data_set, batch_size=100, shuffle=True)

まとめソースコード

import torch.utils.data
import torchvision.transforms as transforms
from pathlib import Path
from PIL import Image

class MyDataset(torch.utils.data.Dataset):

    def __init__(self, imageSize, dir_path, transform=None):
        self.transform = transforms.Compose([
            transforms.Resize(imageSize),
            transforms.ToTensor(),
            transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
        ])

        self.image_paths = [str(p) for p in Path(dir_path).glob("**/*.png")]

        self.data_num = len(self.image_paths)
        self.classes = ['carpet', 'ceramic', 'cloth', 'dirt', 'drywall', 'glass', 'grass', 'gravel', 'leaf', 'metal']
        self.class_to_idx = {'carpet':0, 'ceramic':1, 'cloth':2, 'dirt':3, 'drywall':4, 'glass':5, 'grass':6,'gravel':7, 'leaf':8, 'metal':9}


    def __len__(self):
        return self.data_num

    def __getitem__(self, idx):
        p = self.image_paths[idx]
        image = Image.open(p)

        if self.transform:
            out_data = self.transform(image)

        out_label = p.split("\\")
        out_label = self.class_to_idx[out_label[3]]

        return out_data, out_label

if __name__ == "__main__":
    root_data = 'データへのPath'
    data_set = MyDataset(32, dir_path=root_data)
    dataloader = torch.utils.data.DataLoader(data_set, batch_size=100, shuffle=True)

参考サイト

以下のサイトを見ながら実装しました。
ありがとうございました。
pyTorchのtransforms,Datasets,Dataloaderの説明と自作Datasetの作成と使用
PyTorch: DatasetとDataLoader (画像処理タスク編)

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