配列・文字列スライス操作

pythonでよく使う配列のスライス操作の確認

pythonを勉強し始めてからすごくスライス操作を使うので、ここで一度自分の確認のためにもまとめたいと思います。

配列の操作

まずは配列から、pythonでは作った配列に自動的に番号がつくようになっていて(indexと呼びます)0からスタートして作った中身の数分番号が振り当てられます。

l = [5,3,1,2]
print(l.index(5))
print(l.index(3))
print(l.index(1))
print(l.index(2))
$ python atcoder.py
0
1
2
3

こんな感じに配列の中の5,3,1,2には0123が順番に振られていることがわかりました。 ちなみにl.index()の.index()は配列などindexがふられているものに使える関数で、指定したところのindex番号が取れます。

次はそのインデックスを使って配列の値を取り出します。

l = [5,3,2,1]

print(l[0])
print(l[2])
$ python atcoder.py
5
2

こんな感じに配列に[]をつけてその中に取り出したいインデックスを指定します。 l[0]とすると0番目の5が取れます。

次は一つではなく複数の配列の中身をとります。

l = [5,3,2,1]
print(l[0:2])
$ python atcoder.py
[5, 3]

複数の値を取りたい時はみてわかるように[インデックス:インデックス]として、 はじめに指定した番号のところから後に指定した番号の範囲までを取得できます。 注意して欲しいのがfor文などと一緒で[0:2]とした場合2の一つ前つまりこの場合は0から1までの値を取得するようになっています。

次は最初からあるところまでや、あるところから最後までの方法

l = [5,3,2,1]
print(l[1:])
$ python atcoder.py
[3, 2, 1]
l = [5,3,2,1]
print(l[:3])
$ python atcoder.py
[5, 3, 2]

最初の方は[インデックス:]で指定したインデックスから最後までの値を取り出します 後の方は[:インデックス]で最初から指定したインデックスまで、後の方は先ほど説明したように一個手前までです。

応用

こんなことは日常にないかもしれませんが適当に数字が横に並んでいてどこで分けると一番左と右の大きさの差が少なくなるのか?みたいな時にはスライス操作が便利です。

l = [3,14,6,40,2,6,17,4,6,7,38,5,44,22,1,6,6,7]

for i in range(1,len(l)):
    l_l = l[:i]
    print(f"l_l{l_l}")
    l_r = l[i:]
    print(f"l_r{l_r}")

ある番号までと、ある番号からっていうある番号の値をひとつずつ増やしていくことで、右と左に全ての位置で分けられます。 rangeが1からなのは0からにすると一番初めのループでのl_lがl[:0]となり空の配列が出来上がり空とそのほかというのは比べる必要がにないのでそうしました。

l_l[3]
l_r[14, 6, 40, 2, 6, 17, 4, 6, 7, 38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14]
l_r[6, 40, 2, 6, 17, 4, 6, 7, 38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6]
l_r[40, 2, 6, 17, 4, 6, 7, 38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40]
l_r[2, 6, 17, 4, 6, 7, 38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2]
l_r[6, 17, 4, 6, 7, 38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6]
l_r[17, 4, 6, 7, 38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17]
l_r[4, 6, 7, 38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4]
l_r[6, 7, 38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4, 6]
l_r[7, 38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4, 6, 7]
l_r[38, 5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4, 6, 7, 38]
l_r[5, 44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4, 6, 7, 38, 5]
l_r[44, 22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4, 6, 7, 38, 5, 44]
l_r[22, 1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4, 6, 7, 38, 5, 44, 22]
l_r[1, 6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4, 6, 7, 38, 5, 44, 22, 1]
l_r[6, 6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4, 6, 7, 38, 5, 44, 22, 1, 6]
l_r[6, 7]
l_l[3, 14, 6, 40, 2, 6, 17, 4, 6, 7, 38, 5, 44, 22, 1, 6, 6]
l_r[7]

でここから全ての差を取ればいいですね、今回の記事には関係ないですが一応書きます

l = [3,14,6,40,2,6,17,4,6,7,38,5,44,22,1,6,6,7]

min_g = 10000000
ans = 0
for i in range(len(l)):
    l_l = l[:i]
    l_r = l[i:]

    if min_g > abs(sum(l_l)-sum(l_r)):
        min_g = abs(sum(l_l)-sum(l_r))
        ans = i

print(ans)
$ python atcoder.py
10

インデックス番号が10番目までと10番目からで分ける方法が一番差がないらしいです。

まとめ

まだまだスライスにはたくさんあって全部書くのは大変なので基本ですごく使うものを書きました。

djangoでline botを作る

line botdjangoを使って作る

まずはline developersのアカウントを取得するためlineのアカウントでログイン

developers.line.biz

f:id:saitama_28:20200523135220p:plain



左上のconsole homeから新規provider をcreateする

f:id:saitama_28:20200523135039p:plain

そのしたのproviderからcreate new channelを選択し、channel typeはmessaging API

その後はそれぞれの設定をする。ここまでするとqrコードで自分の作るline botが登録できるようになる。

f:id:saitama_28:20200523143840j:plain

 

今回は予約botを作るのでLINEでよく見るこういうようなメニュー(リッチメニュー と言います)を押したらメッセージを送り、それに対して、line bot側がいつにしますか?というメッセージとともにlineのテンプレートメッセージというものを使って日時表示カルーセル とともにline botがメッセージを送り返す。それに対してユーザーが日時を選択すると予約ができるというシステムを作っていきます

 

まずはここにログインして先ほど作ったアカウントを選択

www.linebiz.com

  • 左のメニューからリッチメニューを選択右上の作成ボタンをクリック

    f:id:saitama_28:20200523135559p:plain

  • 表示設定はタイトル以外はデフォルトでOK

f:id:saitama_28:20200523135718p:plain

  •  その下のコンテンツ設定はテンプレートを選択し画像を貼るか、自分で文字入りの画像を作る
  • 作れたらアクションのところでタイプをテキストにして予約にする

保存して実際に作ったメニューを自分のスマホでタップすると予約というメッセージが送られると思います。

djangoを使ってメッセージを返す

ここまで行ったら次はdjangoで送られてきたメッセージに対してメッセージテンプレートというものを使ってカルーセルをline botから送信したいと思います。

今回はpythonのバージョン・パッケージ管理システムであるanacondaを使ってdjangoをinstallします

www.anaconda.com

 入れてない人は↑の一番したからダウンロードしてください

f:id:saitama_28:20200523132930p:plain

anacondaが入れられたらanaconda navigatorを立ち上げて

  • Environmentsを選択
  • 左下のcreateを選択
  • 名前をdjango37などにしてpythonを選択しversionは3.7を選択-

右下のcreateを選択し環境構築が完了

この状態ではまだdjangoは入ってないのでターミナルを開いて

$ conda activate django37

で環境を立ち上げる

その後

$ conda install django

djangoをinstallこれで環境ができました。

そしたらまずは 

$ django-admin startproject reception_line_bot

でプロジェクトを作成します。

reception_line_bot/
    manage.py
    reception_line_bot/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

 こんな感じに作れたと思います。

次にアプリケーションを作ります。

$ cd reception_line_bot

でreception_line_botの中に入ってから,

$ python manage.py startapp bot 

とすると

bot/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

となったと思います。

次にエディタでreception_line_bot/urls.pyを編集していきます。

"""reception_line_bot URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path

urlpatterns = [
path('admin/', admin.site.urls),
]

こうなっていると思いますが、urlpatternsのところにdjangoが受け取ったline botのリクエストをどのファイルのどの関数に送るかを指定します。

なので今回は

import bot.views
urlpatterns = [
#path('admin/', admin.site.urls),
path('', bot.views.reception),
]

とします。receptionはこれからviews.pyに書く関数です。

views.pyにコードを書く前にline botを作成した時に発行されたチャンネルシークレットとアクセストークンはコードの中に直接書くとまずいので、jsonを通してviews.pyで受け取れるようにしたいと思います。なので一番上のline_reception_botの下にsetting.jsonを作り、

f:id:saitama_28:20200523154823p:plain

providersからチャネルを選択しmessaging APIの一番したでaccess tokenを発行し、コピペします。

次に

f:id:saitama_28:20200523155117p:plain

messaging APIの隣のBasic settingsのところからChannel secretを取得します。

その二つを先ほど作ったsetting.jsonにコピペしていきます

{
"LINE":{
"channel_secret":"fakfkajpdpaida132941",
"access_token":"a3nm7yOY7IoUt8blZ6QqK6RShadfsajdjfadfljfafdsdjsdfailfajjpqjpoejpqjpfjpqejiepqwifqpjdjidcS9yEBGieq+VMQs0EL+mQDtwdB04daft89/aad1O/w1cDnyilFU="
}
}

こんな感じ、(channel_secretとaccess_tokenは適当に変えました)

そしたらviews.pyを開いてユーザーが送ってきたメッセージに対して何か送るコードを書いていきます。

from django.views.generic import TemplateView
from django.shortcuts import render
from django.http.response import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json
import urllib.request
from reception_line_bot.settings import BASE_DIR
# Create your views here.

@csrf_exempt
def reception(request):
json_open = open('setting.json', 'r')
json_load = json.load(json_open)
channel_secret = json_load['LINE']['channel_secret']
access = json_load['LINE']['access_token']
request_body = request.body
data = confirm_json_loads(request_body)
body = request.body.decode('utf-8')
user_message = data["events"][0]["message"]["text"]
reply_token = data["events"][0]["replyToken"]
send_message(reply_token,user_message,access)
return JsonResponse({"message":"OK"})

 

今日はここまでにして次回は何か送り返すところぐらいまで行けたらいいなと思っています。

anacondaとかpythonの知識はそこそこわかるようになってきたのですが。lineからのリクエストなどpostやgetやhttpなど見えないところがまだわかりません。がんばります。

 

 

print & format の大事さ!!!!!

タイトルにある通り最近気づいたのがpythonがエラーをはかないとき、どこまでとおっているのかくにんするのにprintで確認するとわかりますね~独学ではそんなことわかりませんでした。

あとそのprintをするのにもフォーマットをしたほうがいいといわれて、フォーマットしなくても大体わかるじゃん?とか思ってたんですけど、コードが多くなってたくさんプリントするときにどれがどれだかマジでわからないんですね。。(笑)最初からフォーマットをしておけばどれがどれだかわかるのに。。。

その他今日気づいたことはほとんど完成した後に一か所を修正するとそれに通ずるすべての場所も変更しないといけなくて、またそれがどの場所かも全部たどらなきゃいけなくてめちゃくちゃ大変でした、僕が初心者であるからなのかもしれませんが、とにかく完成させてうごかしたくなっちゃうんですが途中途中コードを整理していかないと後で地獄を見るということがわかりました。

まあやってみなくちゃわからないことだらけですね。

読んでいただきありがとうございました。

tensor型の配列を大きい順にかえる

お久しぶりです。今日はpytorchを使って色々やっていたのですがオセロの一番強いところをtensor型から取得するということだったのですが。

まず最大値のを取るやり方は

変数.argmax()で

その後一番強いのから順に取得して置けるところまでループを回すというということでつまずいてしまいました。結局自分ではわからず先輩に聞いたのですが、まずpytorchをupdateしないと使えないという...笑

僕はanacondaの環境を使っているので

conda update pytorchでupdate

してから

torch.argsort()

で並び替えました。その後

.tolist

でリスト型に変えて最大順に取得できました。

自分で調べて解決できるようにしないと。。がんばります

 

今日はほとんど進まなかったので復習としてpythonの正規表現を覚書として。。

今日はほとんど進まなかったので前に勉強した正規表現の復習としてここに書きます

主にif文で正規表現を使いたいときのことです。

マッチ

import re

m = re.match("[0-9]" , "12341137")
if m:
print("マッチ!")
else:
print("マッチしてない")

 この場合結果はマッチ!

[0-9]で第二引数が数字ならマッチ。

import re

m = re.match("[0-9]" , "アイウエオ")
if m:
print("マッチ!")
else:
print("マッチしてない")

この場合はマッチしてない。

[0-9]の代わりには\dも使えるそうです。ただしその場合にはr'\d'としないとバックスラッシュが文字列の一部として扱われてしまいます。

数字以外だったら\Dです。

まだpython自体の知識が少ない。。。。

 

Tensor型の2次元配列を1次元に変えたい!!

今日やっていたことの中でTensor型の二次元配列を一次元に変えたいということで、実際にはオセロの盤面の8x8の二次元配列を1x128(2プレイヤーのそれぞれの盤面)の一次元配列に変えることでした。

今はまだ8x8を1x64の配列にすることにしかしてないのですが、pytorchのTensorを使って

board_1 = torch.Tensor([
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, -1, 0, 0, 0],
[0, 0, 0, -1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0]
])
board = torch.flatten(board_1, start_dim = 0)

でできました。

torch.flattenは第一引数に変えたい配列、第二引数にstart_dim=変更後の配列、です。

boardをプリントすると

tensor([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,

         0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  1.,

        -1.,  0.,  0.,  0.,  0.,  0.,  0., -1.,  1.,  0.,  0.,  0.,  0.,  0.,

         0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,

         0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])

こんな感じ

次回やることはこの 配列の-1の部分を0にすることとこれを二倍にし、反転させた配列を作ることです。

読んでくださってありがとうございました

pytorchエグいてええええええええ

Tensor?ニュートラルネットワーク?Linear?うーん全然わからない。。。

何がわからないって?何がわからないのかもわからないです。

ただちょこちょこpythonの基本は勉強していたわけでpytorchでも文法的なことは調べなくてもよくなった。それは成長ですね〜

後僕一応英語学科なんで英語はそこそこ読めるんですけど公式ドキュメントに出てくる英単語が全く知らん。でもそれも典型的な技術系の単語らしく?ほとんど読めるようになりました。

ただ流石に例えばそれが日本語で書かれていたら理解できるのか?みたいなこともあってそれはもうお手上げ、日本語でもわからないとこを調べてまたそこから調べて。。。みたいな無限ループですね。パソコンじゃなくて僕が壊れるかもしれません。

また次の火曜日までに少し時間があるので自分で勉強頑張るぞ