NumPyによる配列(ndarray)の生成 まとめ

NumPyにおける配列(ndarray)の生成についてまとめます。

1
2
import numpy as np
dummy = np.random.rand(2, 3) # 後ほど使います

全ての要素が1の配列

1
2
3
np.ones((2,3))
array([[1., 1., 1.],
[1., 1., 1.]])
1
2
3
np.ones_like(dummy)
array([[1., 1., 1.],
[1., 1., 1.]])

全ての要素が0の配列

1
2
3
np.zeros((2,3))
array([[0., 0., 0.],
[0., 0., 0.]])
1
2
3
np.zeros_like(dummy)
array([[0., 0., 0.],
[0., 0., 0.]])

要素の値を問わない配列

1
2
3
np.empty((2,3))
array([[0.43365687, 0.47148556, 0.30219278],
[0.83642575, 0.84451664, 0.63210713]])
1
2
3
np.empty_like(dummy)
array([[0.43365687, 0.47148556, 0.30219278],
[0.83642575, 0.84451664, 0.63210713]])

全ての要素が、指定した値の配列

1
2
3
np.full((2, 3), -1)
array([[-1, -1, -1],
[-1, -1, -1]])
1
2
3
np.full_like(dummy, -1)
array([[-1., -1., -1.],
[-1., -1., -1.]])

単位行列

1
2
3
np.eye(2)
array([[1., 0.],
[0., 1.]])
1
2
3
np.eye(2, 3)
array([[1., 0., 0.],
[0., 1., 0.]])
1
2
3
4
np.eye(3, 2)
array([[1., 0.],
[0., 1.],
[0., 0.]])

乱数(0以上1未満の一様乱数)

1
2
3
np.random.rand(2, 3)
array([[0.05281017, 0.30956778, 0.46700981],
[0.49113337, 0.79386647, 0.51450699]])

配列の繰り返し

1
2
3
4
5
6
r = np.array([[0,1],[2,3]])
np.tile(r,(2,3))
array([[0, 1, 0, 1, 0, 1],
[2, 3, 2, 3, 2, 3],
[0, 1, 0, 1, 0, 1],
[2, 3, 2, 3, 2, 3]])

等差数列

1
2
np.arange(3)
array([0, 1, 2])

tupleをlistに変換する方法 まとめ

Pythonでtuple(タプル)をlist(リスト)に変換する方法をまとめます。

基本

list()でくくってあげれば良い。

1
2
3
>>> obj = (1,2)
>>> list(obj)
[1, 2]

ネスト (入れ子)への対応

パターン1. tuple-list構造

これは要するに、タプルの要素がリストなだけなので基本と同じ。

1
2
3
>>> obj = ([1,2], [3,4])
>>> list(obj)
[[1, 2], [3, 4]]

パターン2. list-tuple構造

リスト内包表記で生成したのち、タプル化する

1
2
3
4
obj = [{1,2}, {3,4}]
obj = tuple([list(e) for e in obj])
obj
([1, 2], [3, 4])

ジェネレータ式で生成したのち、タプル化する

1
2
3
4
obj = [{1,2}, {3,4}]
obj = tuple(list(e) for e in obj)
obj
([1, 2], [3, 4])

パターン3. tuple-tuple構造

これまでの方法を組み合わせれば良い。

1
2
3
4
>>> obj = [[1,2], [3,4]]
>>> obj = tuple(tuple(e) for e in obj)
>>> obj
((1, 2), (3, 4))

パターン4. 階層が不明、またはバラバラ

再帰を使って実装でき流。

リストまたはタプルかどうかisinstanceを使ってチェックする。

1
2
3
4
5
6
7
8
def tolist(obj):
new = []
for e in obj:
if isinstance(e, list) or isinstance(e, tuple):
new.append(tolist(e))
else:
new.append(e)
return new
1
2
3
>>> obj = ((1,2),(3,4,5),((6,),),[7],[[[8],],],[([9,],),])
>>> tolist(obj)
[[1, 2], [3, 4, 5], [[6]], [7], [[[8]]], [[[9]]]]

おまけ タプル化

1
2
3
4
5
6
7
8
def totuple(obj):
new = []
for e in obj:
if isinstance(e, list) or isinstance(e, tuple):
new.append(totuple(e))
else:
new.append(e)
return tuple(new)
1
2
3
>>> obj = [[1,2], [3,4],5,(6,7)]
>>> totuple(obj)
((1, 2), (3, 4), 5, (6, 7))

Pythonでloop処理(for文)

はじめに

Pythonの超入門記事です。プログラミングで最も簡単な処理の一つである、for文の書き方を解説します。

サンプルコード

for文を利用して、0から4までの数を出力してみましょう。

よくみるパターンは下記の二つかと思います。

方法1

1
2
3
4
5
6
7
>>> for i in range(5):
>>> print(i)
0
1
2
3
4

方法2

1
2
3
4
5
6
7
>>> for i in [0, 1, 2, 3, 4]:
>>> print(i)
0
1
2
3
4

方法1の解説

次のパターンも見てください。

1
2
3
4
5
6
7
>>> for i in range(0, 5):
>>> print(i)
0
1
2
3
4

次のパターンだとどうでしょうか。

1
2
3
4
5
6
>>> for i in range(1, 5):
>>> print(i)
1
2
3
4

range は二つの引数start, stopをとります。

range をfor文で回すことでstart以上、 stop未満の数を順に取り出すことができます。

そして、startは省略した場合は0となるので、方法1のような使い方ができるのです。

方法2の解説

for文はlistに対しても回すことができます。

list[]記号で括ることで作成できるオブジェクトです。

listオブジェクトは、要素として数以外の変数を取ることもできます

つまり、文字列のlistをfor文で回すことも出来ます。

1
2
3
4
>>> for i in ['orange', 'apple']:
>>> print(i)
orange
apple

要素の型が違っている場合でもOKです。

1
2
3
4
5
>>> for i in ['orange', 'apple', 4]:
>>> print(i)
orange
apple
4

方法1(range)と方法2(list)の違い

これらの特徴からfor文を書く際は、

rangeとlistは次のように使い分けると良いでしょう。

  • range
    • 対象の数を増やしていく場合(スタートは0以外でもOK)
  • list
    • それ以外

発展

厳密にはどういう条件であれば、for文が回せるのでしょうか。

それは、オブジェクトがイテラブルかどうかによります。

イテラブルなオブジェクトには、例えば次のようなものがあります

  • range
  • list
  • tuple
  • set
  • dict
  • str

イテラブルかどうかは次のようなコードで確認することが出来ます。

1
hasattr(obj, "__iter__")

文字列のfor文

先ほどの例に挙げたように、文字列もイテラブルです。

文字列に対してfor文を回すことで、文字を一文字ずつ取得できます。

1
2
3
4
5
6
7
8
>>> for s in "Python":
>>> print(s)
P
y
t
h
o
n

これは、よく使うので覚えておくと良いでしょう。

Ellipsis(...)の解説

はじめに

Pythonの3点リーダー(...)の意味について解説します。

機械学習のベストセラー「ゼロから作るDeep Learning」の2作目「2 自然言語処理編」にも多用されてる記法です。

結論

numpy.nadarrayにおける残りの軸を表します。

numpy.ndarrayのスライスの復習

軸の話をわかりやすくするために、

  • 第1軸のサイズが1
  • 第2軸のサイズが2
  • 第3軸のサイズが3
  • 第4軸のサイズが4

であるようなndarrayAを考える。

1
2
3
4
>>> import numpy as np
>>> A = np.random.rand(1,2,3,4)
>>> A.shape
(1, 2, 3, 4)

今後もこのAを、様々にスライスしshapeを確認します。

第1軸の0番目についてスライスをしたい時は以下のようにします。

1
2
>>> a[0].shape
(2, 3, 4)

では、第2軸の0番目についてスライスをしたい時は?

1
2
>>> a[:,0].shape
(1, 3, 4)

このようにコロンを入れます。

では、第1軸と第4軸の0番目についてスライスをしたい時は?

1
2
>>> a[0,:,:,0].shape
(2, 3)

複数の:の省略としての用法

では、以下のような6次元配列の、第6軸の0番目についてスライスをしたい時は?

1
2
3
>>> B = np.random.rand(1,2,3,4,5,6)
>>> B[:,:,:,:,:,0].shape
(1, 2, 3, 4, 5)

なんだか、コロンが多くて大変です。

こういった場面でElipsisを使えます。

1
2
>>> B[...,0].shape
(1, 2, 3, 4, 5)

先ほどのコードと全く同じ動きです。

つまり、指定していない軸で、全て:を指定したかのように動作します。

1
2
>>> B[[:,0,...,0].shape
(1, 3, 4, 5)

とても便利ですね。

ndarrayのdeep copyに便利

これは、応用テクニックですが、deep copyに利用できます。

  1. Bを書き換えると、Aも書き換わる

    1
    2
    3
    4
    5
    6
    7
    A = np.ones((2,3))
    B = np.zeros((2,3))
    B = A
    B *= 2
    A
    array([[2., 2., 2.],
    [2., 2., 2.]])
  2. Bを書き換えても、Aも変わらない

    1
    2
    3
    4
    5
    6
    7
    A = np.ones((2,3))
    B = np.zeros((2,3))
    B[:,:] = A
    B *= 2
    A
    array([[1., 1., 1.],
    [1., 1., 1.]])
  3. Bを書き換えても、Aも変わらない

    1
    2
    3
    4
    5
    6
    7
    A = np.ones((2,3))
    B = np.zeros((2,3))
    B[...] = A
    B *= 2
    A
    array([[1., 1., 1.],
    [1., 1., 1.]])

    ellipsisを使うとndarrayの次元数を気にせず使えるので、楽です。

ABC155C Poll

問題

https://atcoder.jp/contests/abc155/tasks/abc155_c

方針

  • 文字数が最大となる文字列のリストを生成
  • ソート

    ポイント

    collectionsモジュールのCounterを使うとよい
  • 簡単に数え上げできる
  • メソッドmost_commonを利用することで、頻度が多い順に要素を取り出せる

コード

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from collections import Counter
N = int(input())
S = []
for n in range(N):
S.append(input())
c = Counter(S)
K = []
for i,(k,v) in enumerate(c.most_common()):
if i==0:
vmax = v
else:
if vmax!=v:
break
K.append(k)

K = sorted(K)
for k in K:
print (k)

Pythonでtwitterのbotを作成する方法(後半)

目次

  1. Twitter APIの認証情報を作成してみよう
  2. Pythonを使ってツイートをしてみよう
  3. クラウドを使って自動でツイートするbotを作ってみよう

前回の記事
でステップ1,2までは終了しています。

今回はステップ3の

「クラウドを使って自動でツイートするbotを作ってみよう」

に相当します。

GCP(Google CLoud Platfrom)と呼ばれるクラウドサービスを利用します。

GCP(Google Cloud Platform)とは

Googleが提供するクラウドサービスです。

競合である、Amazonが提供するAWS(Amazon Web Services)も有名ですが、

近年はGCPも人気を集めています。

クラウドを使って自動でツイートするbotを作ってみよう

概要

GCPの以下の2つのサービスを使って、botを構築します。

どちらのサービスも、今回の利用ボリュームであれば無料で利用できます。

手順

Cloud Functions

まずはGCPコンソールにログインする。
https://console.cloud.google.com/?hl=ja

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

左上のハンバーガーメニュー(三本線のアイコン)をクリックして、
コンピューティングにあるCloud Functionsをクリックする。

GCPを利用されるのが初めての場合、ここの手順あたりで無料トライアルへの登録を促されます。

無料トライアルでは、一年間にわたって300ドル分のクーポンが利用できます。

クレジットカードの登録が必要ですが、説明にもある通り自動で課金されることはありません。

また、今回作成するサービスは上述の通り、この無料トライアルを抜きにしても料金が発生しませんので、ご安心を。

Cloud Functionsに戻り、関数を作成をクリックする。

名前を決めていただき、画像のように入力します。

作成後は、URLにアクセスすることで、関数が実行されツイートが行われます。

このURLを控えておいて下さい。

ランタイムを Pythonに設定

twitterモジュールを利用したいので、requirement.txttwitterと追記してください。

main.pyに戻っていただきコードを編集します。

下記のコードを認証情報を適切に設定してコピペして下さい。

認証情報の作成方法については、前回の記事で解説しています。

実行する関数を変更するのも忘れないでください。(このコードの場合、関数名はtweet

1
2
3
4
5
6
7
8
9
10
import twitter
def tweet(request): # これらの認証情報はダミーなので、書き換えてください
auth = twitter.OAuth(consumer_key="Cymp0qFxlwyfXXddETJjl1lNJ",
consumer_secret="CpXJxBRWkW9QQzLeoRoTWbBVUGREWHQ5fU41pdXnIaRbsfEXph",
token="3045399218-lwL7MZq1upTO680eAPAyIoecQsR6kBPwNM35BrS",
token_secret="MVYTxsC4XN4wQ8zVD2Vp9D4ByUcKTBDIPosCgFK9mc98z")
text = 'このツイートはpythonでツイートしています'
t = twitter.Twitter(auth=auth)
status=text
t.statuses.update(status=status)

作成をクリックして、Cloud Functionsの設定は終了です。

テストを実行してみましょう。ツイートされるはずです。

うまくいかない場合、ログからエラーが確認できるのでデバッグします。

Cloud Scheduler

メニューのツールからCloud Schedulerをクリックし、ジョブを作成します。

特にレイテンシを意識する必要もないので、ロケーションはそのままでもOKです。

頻度を設定します。画像のように設定すると、毎日夜24時にツイートをします。

先ほど控えたCloud FunctionsURLを設定します。

完成です。今すぐ実行でテストすることもできます。

まとめ

いかがだったでしょうか。

この後は、ツイートの内容を工夫するなりして遊んでみるのもいいと思います。

勉強目的なのでこれで十分、という方はプロジェクトごと消してしまいましょう。

Python 内包表記とlambdaの書き方

内包表記とlambdaの書き方(結論)

1
2
3
4
5
# 内包表記
B = list(map(lambda x: x*x, A))

# lambda
B = [x*x for x in A]

今、数値のリストAがあるとする。
Aの要素を全て二乗したリストBを得る方法を考える。

様々な方法で実装

準備

  • 0~99までの要素数100のリストA
  • 数を二乗する関数square
    1
    2
    3
    A = range(100)
    def square(a):
    return a*a

    方法1. for文 + square関数

    まずは最も愚直な方法を考える。

最初に空のリストを用意して、ループを回して、と手順が複雑。

1
2
3
4
B = []
for a in A:
B.append(square(a))
print (B)

方法2. map + square関数

高階関数mapを使うと下記のようにシンプルにかける。

Python3では、2までと違いmapはリストではなくイテレータを返すため、リストへの変換が必要。

1
2
B = list(map(square, A))
print (B)

方法3. map + lambda

関数をこの箇所でしか使わない場合、わざわざ宣言をしないという方法もある。

それが、lambdaを用いた方法である。

1
2
B = list(map(lambda x: x*x, A))
print (B)

方法4. リスト内包表記

リスト内包表記が最もシンプルだろう。

1
2
B = [x*x for x in A]
print (B)

おまけ 実行時間の比較

今回のケースでは、内包表記が最も速い。

1
2
3
4
5
>>> %%timeit
>>> B = []
>>> for a in A:
>>> B.append(square(a))
18.1 µs ± 257 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
1
2
3
>>> %%timeit
>>> B = list(map(square, A))
10.1 µs ± 128 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
1
2
3
>>> %%timeit
>>> B = list(map(lambda x: x*x, A))
12.2 µs ± 195 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
1
2
3
>>> %%timeit
>>> B = [x*x for x in A]
5.89 µs ± 112 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

listとnumpy.ndarrayの速度比較にも興味がある方は、Pythonにおけるリスト(list)と配列(array)の違いをご覧ください。

Pythonでtwitterのbotを作成する方法(前半)

目次

  1. Twitter APIの認証情報を作成してみよう
  2. Pythonを使ってツイートをしてみよう
  3. クラウドを使って自動でツイートするbotを作ってみよう

Twitter APIの認証情報を作成してみよう

まずはTwitter Developer Platformにアクセス

https://developer.twitter.com/

Appsをクリック

Create an appをクリック

Making a botをクリック

国やニックネームを入力して、Nextをクリック

APIを使う動機を説明します。参考までにですが、私は下記のような内容をGoogle翻訳して突っこみました。

  • プログラミングの勉強
  • Pythonでbotを作成
  • まとめて、ブログで発信

画像のようにYes, Noを選択していきます。画像のテキストボックスにも先ほどと同様の説明を入れました。

最後にLooks Good!をクリック

規約に同意して、Submit Applicationをクリック

この画面が出ればOK。メールでの確認をし、Developer Platformに戻ります。

右上のメニューから自分の名前をクリックし、Appsをクリック

Create an appをクリック
作成したアプリが見えるので、detailsをクリック

Key and tokensをクリック
Access token & acces token secretの右にあるgenerateをクリック
生成されるAccess tokenaccess token secretを控える

API keyAPI secret keyを控える
これで完了です!お疲れ様でした。

Pythonを使ってツイートしてみよう

サンプルコードを載せておきます。

twitterというモジュールを使うので、インストールしてください。

1
2
3
4
5
6
7
8
9
10
11
12
13
import twitter
def tweet(text): # これらの認証情報はダミーなので、書き換えてください
auth = twitter.OAuth(consumer_key="Cymp0qFxlwyfXXddETJjl1lNJ",
consumer_secret="CpXJxBRWkW9QQzLeoRoTWbBVUGREWHQ5fU41pdXnIaRbsfEXph",
token="3045399218-lwL7MZq1upTO680eAPAyIoecQsR6kBPwNM35BrS",
token_secret="MVYTxsC4XN4wQ8zVD2Vp9D4ByUcKTBDIPosCgFK9mc98z")

t = twitter.Twitter(auth=auth)
status=text
t.statuses.update(status=status)

text = 'このツイートはpythonでツイートしています'
tweet(text)

クラウドを使って自動でツイートするbotを作ってみよう

長くなってしまいそうなので、別記事にしました。
こちらからどうぞ!

Pythonで小数の計算を正確に行う方法

はじめに

次のようなコードがあったとしよう。

標準出力には、何が表示されるだろうか。

1
>>> print (0.03 - 0.02)

何を簡単な話を聞いているのか思うかもしれない。

答えは0.01ではなく、

1
2
>>> print (0.03 - 0.02)
0.009999999999999998

のようになる。

プログラムは(10進数の)小数を正確に表現することが難しいためである。

これはPythonに限った話ではない。

decimalモジュールの紹介

では、小数を正確に表現する手段が全くないかというと、そうでもない。

正確な表現が要求される場面では、そのためのモジュールを用いれば良い。

1
>>> from decimal import *

Pythonの場合、decimalモジュールを用いれば、正確な十進浮動小数点の表現ができ、正確な算術が行える。

1
2
>>> Decimal('0.03') - Decimal('0.02')
Decimal('0.01')

fractionsモジュールの紹介

有理数を正確に表現するためには、fractionsモジュールを用いれば良い。

1
>>> from fractions import Fraction

先の有限小数0.01も正確に表現できる上、

1
2
3
4
5
>>> Fraction(1, 100)
Fraction(1, 100)

>>> Fraction('0.01')
Fraction(1, 100)

無限小数も正確に表現できる。

1
2
>>> Fraction('1/3')
Fraction(1, 3)

Decimalインスタンスにも対応している。

1
2
>>> Fraction(Decimal('0.01'))
Fraction(1, 100)

ARC059A いっしょ

問題

https://atcoder.jp/contests/arc059/tasks/arc059_a

方針

解の候補が限られているため、全探索で解くことができる。

コード

1
2
3
4
5
6
7
8
N = int(input())
A = list(map(int, input().split()))
def calc(A,mu):v # 整数のリストと変換後の値の候補
return sum([(a-mu)**2 for a in A])
ans = 1e+8 # 無限大
for n in range(-100,201): # 解のパターン
ans = min(ans, calc(A,n))
print (ans)

別解

数学的に解くこともできる。
Aの平均を求め、その前後の整数が解となりうることがわかる。

1
2
3
4
5
6
7
8
9
from statistics import mean
import math
N = int(input())
A = list(map(int, input().split()))
def calc(A,mu): # 整数のリストと変換後の値の候補
return sum([(a-mu)**2 for a in A])
floor = math.floor(mean(A))
ceil = math.ceil(mean(A))
print (min(calc(A,floor),calc(A,ceil)))