LoginSignup
10

More than 5 years have passed since last update.

ざっくりPythonのおさらい その3。Numpy, Pandas

Last updated at Posted at 2018-09-02

引き続いて、numpy, pandasの基本的な使い方をざっくりと載せておきます。
本記事では行列系の演算は扱ってません。
(とは言っても、機械学習、ディープラーニングでデータを扱っていると避けては通れないので、適宜追加していきます。)

前回までのおさらいは、以下の記事をご参照ください。

[ざっくりPythonのおさらい その1。基本文法など]
https://qiita.com/48hands/items/31b7ac2b49addbb8658c

[ざっくりPythonのおさらい その2。おもにデータ保存]
https://qiita.com/48hands/items/ab86b7463268e669d216

Numpy

import numpy as npで利用する。

np.array

一次元の配列

import numpy as np

a1 = np.array([1, 2, 3, 4, 5])
print(a1)

# 配列サイズの確認
print(a1.shape)

# 次元数の確認
print(a1.ndim)

# 要素数の確認
print(a1.size)
[1 2 3 4 5]
(5,)
1
5

多次元の配列

import numpy as np

# 二次元の配列生成
a2 = np.array([[1, 2, 3], [4, 5, 6]])
print(a2[0])
print(a2[1])
print(a2[0][1])

# 配列サイズの確認
print(a2.shape)

# 次元数の確認
print(a2.ndim)

# 要素数の確認
print(a2.size)
[1 2 3]
[4 5 6]
2
(2, 3)
2
6

np.arange

# 0から9の一次元配列
a = np.arange(10)
print(a)

# 0から29まで5ずつスキップの一次元配列
a = np.arange(0, 30, 5)
print(a)

# 0から2まで0.3ずつスキップの一次元配列
a = np.arange(0, 2, 0.3)
print(a)
[0 1 2 3 4 5 6 7 8 9]
[ 0  5 10 15 20 25]
[ 0.   0.3  0.6  0.9  1.2  1.5  1.8]

np.zeros / np.ones

業務処理では滅多に使うことがないかもしれませんが、行列計算でよく使います。

np.zeros

# 3行4列の二次元配列
a = np.zeros((3, 4), dtype=np.int32)
print(a)
[[0 0 0 0]
 [0 0 0 0]
 [0 0 0 0]]

np.ones

# 3行4列の二次元配列
a = np.ones((3, 4), dtype=np.int32)
print(a)
[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 1]]

np.reshape

arange関数と組み合わせて使うことが多いです。

# 2 * 3の配列を作成
a = np.arange(6).reshape(2, 3)
print(a)
[[0 1 2]
 [3 4 5]]
# 2 * 3 * 4の配列を作成
a = np.arange(24).reshape(2, 3, 4)
print(a)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

np.vstack / np.hstack

以下のようなデータを扱うものとして記載しています。

x = np.arange(0, 10, 2)
y = np.arange(5)
z = np.arange(0, 100, 20)

print(x)
print(y)
print(z)
[0 2 4 6 8]
[0 1 2 3 4]
[ 0 20 40 60 80]

np.vstack

垂直にスタックします。

print(np.vstack([x, y, z]))
[[ 0  2  4  6  8]
 [ 0  1  2  3  4]
 [ 0 20 40 60 80]]

np.hstack

水平方向にスタックします。

print(np.hstack([x, y, z]))
[ 0  2  4  6  8  0  1  2  3  4  0 20 40 60 80]

np.random

# 2行3列の値がランダムな数の配列を生成
a = np.random.randn(2,3)
print(a)
[[-0.00500654 -0.252814   -0.57280965]
 [-1.44175418 -0.22190351 -0.48507611]]

演算

配列同士の演算

配列の要素同士の計算。(行列計算ではない。)

a = np.array([[1, 2, 3, 4, 5], [3, 4, 5, 6, 7]])
b = np.array([[2, 4, 6, 7, 9], [1, 2, 4, 2, 8]])

# 要素同士の足し算
print(a + b)

# 要素同士の掛け算
print(a * b)
[[ 3  6  9 11 14]
 [ 4  6  9  8 15]]
[[ 2  8 18 28 45]
 [ 3  8 20 12 56]]

統計的な計算

a = np.array([[1, 2, 3, 4, 5], [3, 4, 5, 6, 7]])
print(a)

# すべての要素を使って計算
print(a.sum())
print(a.max())
print(a.min())
print(a.mean())
print(a.std())

# 列ごとに集計
print(a.sum(axis=0))
# 行ごとに集計
print(a.sum(axis=1))
[[1 2 3 4 5]
 [3 4 5 6 7]]

40
7
1
4.0
1.73205080757

[ 4  6  8 10 12]
[15 25]

Pandas

業務処理としては、Pandasの方がNumpyよりも使う印象。(PandasもNumpyを中で使っているのでこの表現は正確ではないですが..)

Pandasによってデータをデータフレームの形式(表のようなもの)で扱えます。
import pandas as pdで利用する。

データフレームの生成

一次元データ

import pandas as pd
import numpy as np

# 一次元
s = pd.Series([1, 2, 3, 4, np.nan, 5])
print(s)
0    1.0
1    2.0
2    3.0
3    4.0
4    NaN
5    5.0

左の0,1,2,3,4,5はインデックスを示している。

二次元データ

二次元の場合はよくdfを変数名としてつかう。

カラムとデータをセットで与える場合

pd.DataFrameの引数にディクショナリ形式でデータを与える。

df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
print(df)
   A  B
0  1  3
1  2  4

左の0,1はインデックスを示している。

カラムとデータを別で与えたい場合

df = pd.DataFrame(np.random.randn(5, 4),
                  columns=['A', 'B', 'C', 'D'])
print(df)
          A         B         C         D
0 -0.305246 -0.244308  0.960713 -1.948262
1  1.827907  2.123698  1.880136 -0.663541
2 -0.194168  1.093406  1.690319  0.609997
3 -0.530745 -0.740414  0.669239 -1.154399
4 -0.344853 -1.834740 -0.075733 -0.057627

さらに、インデックスを0,1,2,...のように定義せずに任意のものを与えたい場合は、以下のように与えることもできる。

df = pd.DataFrame(np.random.randn(5, 4),
                  index=["a" + str(i) for i in range(5)],
                  columns=['A', 'B', 'C', 'D'])
print(df)
           A         B         C         D
a0  0.530294  0.322370  0.478835 -0.126045
a1  0.432960 -1.546127  0.492869  2.012067
a2 -1.603422 -0.610451  0.463467  0.199561
a3 -0.368643  1.409762 -0.185814 -0.573302
a4  0.090929  0.036672 -0.027835  0.558301

もしくは、pandasのxx_range関数が用意されている。

# date_range関数を使って、20180101-20180105をインデックスとして定義
df = pd.DataFrame(np.random.randn(5, 4),
                  index=pd.date_range('20180101', periods=5),
                  columns=['A', 'B', 'C', 'D'])
print(df)
                   A         B         C         D
2018-01-01 -0.586486 -0.291565  0.473952 -0.685849
2018-01-02 -1.393820 -0.487958 -1.589376  0.105860
2018-01-03 -0.753569 -0.864522  0.662988  0.645619
2018-01-04  0.606714  0.260588  0.128833  0.432453
2018-01-05 -0.189775 -0.656559  0.161292 -0.429529

データの参照

head / tail / columns / values

df = pd.DataFrame(np.random.randn(5, 4),
                  columns=['A', 'B', 'C', 'D'])

# 上から2行を取得
print(df.head(2))

# 下から2行を取得
print(df.tail(2))

# カラムを取得
print(df.columns)

# 値を取得
print(df.values)
          A         B         C         D
0 -0.999091 -0.122181 -0.894873  0.039718
1  0.718243 -0.133020  1.106097  0.786122

          A         B         C         D
3  1.535138 -1.018447  1.178315 -0.277484
4 -0.741541 -1.409563 -0.349262  1.506808

Index(['A', 'B', 'C', 'D'], dtype='object')

[[-0.99909119 -0.12218051 -0.89487256  0.03971803]
 [ 0.71824258 -0.13302039  1.10609694  0.78612167]
 [ 0.74734781  1.28302495 -0.25022485 -0.92677622]
 [ 1.53513828 -1.01844676  1.17831484 -0.27748411]
 [-0.74154141 -1.4095629  -0.34926238  1.50680833]]

なお、head,tail,columns,valuesの型は以下のようになっている。

print(type(df.head(2)))
print(type(df.tail(2)))

print(type(df.columns))
print(type(df.values))
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.core.indexes.base.Index'>
<class 'numpy.ndarray'>

columnsvaluesをリスト形式にしたい場合は、以下のようにすればリストに変換できると思われる。(このやり方がいいのかはわかりませんが、どうしてもpandasのデータをリストで扱いたい場合の手段として残しておきます。)

df = pd.DataFrame(np.random.randn(5, 4),
                  index=pd.date_range('20180101', periods=5),
                  columns=['A', 'B', 'C', 'D'])

print(list(df.columns))
print(list([list(a) for a in df.values]))
['A', 'B', 'C', 'D']
[[-0.002235757935339935, 1.6529973427058939, 0.64203999192301642, -1.3210444284424014], [2.3671442978642845, -1.0722592191428966, 1.2885945049511809, 0.026156012112749916], [0.77976030738001834, 0.33266376052480762, -2.5191588600551702, -0.36360286000823311], [-1.9147929973641573, 0.71150943274316547, 0.17461225929264279, -0.38409302462051303], [2.4247639005597312, 1.3167549003901313, 1.0682682650746929, 0.50789521949882876]]

行のみを指定したアクセス

行のアクセスはインデックスを使う。

# 5行4列のデータフレーム
df = pd.DataFrame(np.random.randn(5, 4),
                  index=["a" + str(i) for i in range(5)],
                  columns=['A', 'B', 'C', 'D'])

# インデックス番号を指定して参照する
print(df[0:3])

# インデックス名を指定して参照する
# df[0:3]と同じ結果になる
print(df['a0':'a2'])
           A         B         C         D
a0  0.805062 -1.033655  3.012355 -0.283463
a1  0.944916 -0.506144 -1.118409 -1.420088
a2  0.045544 -0.466361 -2.671331 -1.080808

           A         B         C         D
a0  0.805062 -1.033655  3.012355 -0.283463
a1  0.944916 -0.506144 -1.118409 -1.420088
a2  0.045544 -0.466361 -2.671331 -1.080808

行とカラムを指定したアクセス

loc関数にインデックスのレンジと取得したいカラムの配列を渡す。

# 5行4列のデータフレーム
df = pd.DataFrame(np.random.randn(5, 4),
                  index=["a" + str(i) for i in range(5)],
                  columns=['A', 'B', 'C', 'D'])

# a0〜a2までの行かつ、カラムA,Cのみを取得
print(df.loc['a0':'a2', ['A', 'C']])

# すべての行かつ、カラムA,Cのみを取得
print(df.loc[:, ['A', 'C']])
           A         C
a0  0.144033 -1.296219
a1  1.005402  1.443974
a2 -1.426863 -0.036709

           A         C
a0  0.144033 -1.296219
a1  1.005402  1.443974
a2 -1.426863 -0.036709
a3 -1.915530 -1.260232
a4 -0.385383 -0.243092

iloc関数で行と列の要素番号を指定したアクセスはこちら。

df = pd.DataFrame(np.random.randn(5, 4),
                  index=["a" + str(i) for i in range(5)],
                  columns=['A', 'B', 'C', 'D'])

print(df.iloc[0, 0])
print(df.iloc[0:3, 0:3])
-0.196552994109

           A         B         C
a0 -0.196553  0.819213 -0.185168
a1 -0.783100 -1.275004 -0.215038
a2 -0.430817 -0.497900  0.128841

カラムの追加

カラムの追加はディクショナリ形式でリストを追加するようにできる。

# もとのデータフレーム(3行4列)
df = pd.DataFrame(np.random.randn(3, 4),
                  index=pd.date_range('20180101', periods=3),
                  columns=['A', 'B', 'C', 'D'])
print(df)

# カラムEを追加する
df['E'] = ['Makio', 'Shintaro', 'Hanako']
print(df)
                   A         B         C         D
2018-01-01 -0.899274 -2.721258  0.397787  0.318388
2018-01-02  0.773072 -0.091913 -0.086014  1.379136
2018-01-03 -0.203123  0.191961  1.127242  0.989349

                   A         B         C         D         E
2018-01-01 -0.899274 -2.721258  0.397787  0.318388     Makio
2018-01-02  0.773072 -0.091913 -0.086014  1.379136  Shintaro
2018-01-03 -0.203123  0.191961  1.127242  0.989349    Hanako

関数の適用

mapもしくはapplyに関数を渡す。

df = pd.DataFrame(
    {'A': [1, 2, 3, 4], 'B': ['Hanako', 'Makio', 'Taro', 'Kanako']})

print(df)

df['A2'] = df['A'].map(lambda x: x * 2)
df['B2'] = df['B'].map(lambda x: x.startswith('H'))
df['AB'] = df.apply(lambda x: x['B'] + str(x['A']), axis=1) # axis=1で各行に関数を適用している

print(df)
   A       B
0  1  Hanako
1  2   Makio
2  3    Taro
3  4  Kanako

   A       B  A2     B2       AB
0  1  Hanako   2   True  Hanako1
1  2   Makio   4  False   Makio2
2  3    Taro   6  False    Taro3
3  4  Kanako   8  False  Kanako4

上の例ではlambdaで渡しているが、以下のようにも記述できる。
lambdaで定義する処理が長くなりそうな場合は、こちらを使うのがよさそう。

df = pd.DataFrame(
    {'A': [1, 2, 3, 4], 'B': ['Hanako', 'Makio', 'Taro', 'Kanako']})

print(df)


def func1(x):
    return x * 2


def func2(x):
    return x.startswith('H')


def func3(x):
    return x['B'] + str(x['A'])


df['A2'] = df['A'].map(func1)
df['B2'] = df['B'].map(func2)
df['AB'] = df.apply(func3, axis=1)

print(df)

また、assignメソッドを使って以下のようにも記述できる。

df = pd.DataFrame(
    {'A': [1, 2, 3, 4], 'B': ['Hanako', 'Makio', 'Taro', 'Kanako']})

df2 = df.assign(
    A2=lambda df: df['A'].apply(lambda x: x * 2),
    B2=lambda df: df['B'].apply(lambda x: x.startswith('H')),
    AB=lambda df: df.apply(lambda x: x['B'] + str(x['A']), axis=1))

print(df2)

データの絞り込み

where句相当

queryメソッドを使うのが簡単。

df = pd.DataFrame(
    {'A': [-1, 0, 1, 0, -4], 'B': ['one', 'two', 'two', 'three', 'five']})

# Aが0かつBが'two'を条件として抽出
print(df.query('A == 0 and B == "two"'))
   A    B
1  0  two

where in相当

df = pd.DataFrame(
    {'A': [-1, 0, 1, 0, -4], 'B': ['one', 'two', 'two', 'three', 'five']})

# B列がtwo,fourのものを抽出
df2 = df[df['B'].isin(['two', 'four'])]
print(df2)
   A    B
1  0  two
2  1  two

データのソート

sort_valuesメソッドを使う。

df = pd.DataFrame(
    np.array([[1, 4], [2, 7], [5, 2], [3, 3], [-1, 6], [2, 2], [3, 4]]),
    index=pd.date_range('20180101', periods=7), columns=['A', 'B'])

print(df)

# カラムA降順でソート
print(df.sort_values(by='A', ascending=False))

# カラムA降順、カラムB降順でソート
print(df.sort_values(by=['A', 'B'], ascending=[False, False]))
            A  B
2018-01-01  1  4
2018-01-02  2  7
2018-01-03  5  2
2018-01-04  3  3
2018-01-05 -1  6
2018-01-06  2  2
2018-01-07  3  4

            A  B
2018-01-03  5  2
2018-01-04  3  3
2018-01-07  3  4
2018-01-02  2  7
2018-01-06  2  2
2018-01-01  1  4
2018-01-05 -1  6

            A  B
2018-01-03  5  2
2018-01-07  3  4
2018-01-04  3  3
2018-01-02  2  7
2018-01-06  2  2
2018-01-01  1  4
2018-01-05 -1  6

データの集計

groupbyメソッドで集計できる。

df = pd.DataFrame({'A': ['foo', 'bar', 'foo', 'bar'],
                   'B': np.random.randn(4)}
                  )
print(df)

# カラムAをグループ集計して合計を求める
result_df = df.groupby('A').sum()
print(result_df)
     A         B
0  foo  0.125125
1  bar  0.886186
2  foo -2.036310
3  bar -1.993052

            B
A            
bar -1.106866
foo -1.911185

簡単に統計値を確認する

describeメソッドを使うと簡単に基本統計量が確認できる。

df = pd.DataFrame(np.random.randn(5, 4),
                  index=pd.date_range('20180101', periods=5),
                  columns=['A', 'B', 'C', 'D'])
print(df)
print(df.describe())
           A         B         C         D
a0 -0.101431 -0.540538  0.413183 -1.112668
a1  1.139180  0.236635  1.234778  0.005053
a2  1.546940 -0.474595  0.860131 -0.058529
a3  0.339556  0.032907  0.069717 -0.638064
a4 -1.490855  1.516060 -1.045449 -0.065478

              A         B         C         D
count  5.000000  5.000000  5.000000  5.000000
mean   0.286678  0.154094  0.306472 -0.373937
std    1.186178  0.829791  0.875132  0.488301
min   -1.490855 -0.540538 -1.045449 -1.112668
25%   -0.101431 -0.474595  0.069717 -0.638064
50%    0.339556  0.032907  0.413183 -0.065478
75%    1.139180  0.236635  0.860131 -0.058529
max    1.546940  1.516060  1.234778  0.005053

データフレーム同士の結合

# 3行2列のデータフレームを作成
df1 = pd.DataFrame(np.random.randn(3, 2), columns=['A', 'C'])
df2 = pd.DataFrame(np.random.randn(3, 2), columns=['A', 'B'])

# 縦方向に結合
# ignore_indexでdf1,df2で振られているインデックスを無視して振り直す。
merge_df = pd.concat([df1, df2], ignore_index=True)

print(merge_df)
          A         B         C
0 -0.195391       NaN  0.597881
1 -1.412883       NaN -1.028382
2  0.010281       NaN  0.837267
3  0.351978 -0.251637       NaN
4 -0.479735 -1.370914       NaN
5  0.907136  1.774478       NaN

欠損値NaNを扱う

置換する場合

前節のmerge_dfでカラムB,CのNaNを0で置換する。

merge_df['B'].fillna(0, inplace=True)
merge_df['C'].fillna(0, inplace=True)
print(merge_df)
          A         B         C
0  0.496169  0.000000  2.323138
1 -0.094766  0.000000  0.250895
2 -1.200690  0.000000  0.891685
3 -0.528584 -0.358417  0.000000
4  0.706201  0.381958  0.000000
5  0.736269 -0.130781  0.000000

削除する場合

dropnaメソッドを利用してレコードを削除する。
オプションの違いもあるため、以下のようなデータフレームで例示しています。

df = pd.DataFrame(
    {'A': [np.nan, 1, 2],
     'B': [np.nan, np.nan, 3]
     })

print(df)
     A    B
0  NaN  NaN
1  1.0  NaN
2  2.0  3.0
すべてのカラムがNaNのレコード削除

howallを指定する。

print(df.dropna(how='all'))
     A    B
1  1.0  NaN
2  2.0  3.0
いずれかのカラムがNaNのレコード削除

howanyを指定する。
(dropnaメソッドのデフォルトなので明示的に指定しなくてもよい。)

print(df.dropna(how='all'))
     A    B
2  2.0  3.0

データフレームのコピー

データフレームのコピーはcopyメソッドを使う。

df1 = pd.DataFrame(
    {'A': [1, 2, 3],
     'B': [2, 2, 3]
     })


df2 = df1.copy()
df2['C'] = [5,6,7]

print(df1)
print(df2)
   A  B
0  1  2
1  2  2
2  3  3

   A  B  C
0  1  2  5
1  2  2  6
2  3  3  7

当たり前だが、データフレームも参照渡しなので、以下のdf1df2は同じ結果になる。

df1 = pd.DataFrame(
    {'A': [1, 2, 3],
     'B': [2, 2, 3]
     })

df2 = df1
df2['C'] = [5,6,7]

print(df1)
print(df2)
   A  B  C
0  1  2  5
1  2  2  6
2  3  3  7

   A  B  C
0  1  2  5
1  2  2  6
2  3  3  7

転置

とても簡単に転置できる。

df = pd.DataFrame(np.random.randn(5, 4),
                  index=pd.date_range('20180101', periods=5),
                  columns=['A', 'B', 'C', 'D'])
print(df)

# 転置
print(df.T)
                   A         B         C         D
2018-01-01  1.623736 -1.138568  0.963784  1.143847
2018-01-02  0.473417  0.937296 -0.274963  0.803029
2018-01-03 -0.628118  1.058111  0.848354 -0.563482
2018-01-04 -0.129076 -0.135657  1.400161  0.094259
2018-01-05  0.985847  1.522559 -0.094080  0.899734


   2018-01-01  2018-01-02  2018-01-03  2018-01-04  2018-01-05
A    1.623736    0.473417   -0.628118   -0.129076    0.985847
B   -1.138568    0.937296    1.058111   -0.135657    1.522559
C    0.963784   -0.274963    0.848354    1.400161   -0.094080
D    1.143847    0.803029   -0.563482    0.094259    0.899734

外部データの読み書き

テキストデータの読み書き

読み込み

pd.read_csvで読み込む。

hoge.csv
name,age
hanako,22
taro,25
df = pd.read_csv('hoge.csv', sep=',', encoding='utf-8')
# ヘッダーがない場合には、header=Noneを指定する。
# df = pd.read_csv('hoge.csv', sep=',', header=None,encoding='utf-8')

print(df)
     name  age
0  hanako   22
1    taro   25
書き込み
import csv

# データフレームのインデックスはファイル出力させたくなかったので
# index=Falseを指定している。
# quoting=csv.QUOTE_ALLの部分は、quoting=1としても結果は同じ
df.to_csv('target.csv',
          sep=',',
          index=False,
          encoding='utf-8',
          header=True,
          quoting=csv.QUOTE_ALL)
target.csv
"name","age"
"hanako","22"
"taro","25"

RDBに対する読み書き

読み込み

pd.read_sqlを使ってデータを読み込む。

SQLAlchemyを使ってengineを引数に渡すVer

engineを渡すだけなので、コネクション管理しなくてもよいのかと思う。

import sqlalchemy

# mysql+pymysqlを指定する
url = 'mysql+pymysql://username:password@127.0.0.1/my_db'
engine = sqlalchemy.create_engine(url, echo=True)

df = pd.read_sql('select * from persons', engine)
print(df)
    id      name
0    1   Robot-1
1    2   Robot-2
2    3   Robot-3

SQLAlchemyを使わずにコネクションを渡すVer

import mysql.connector

conn = mysql.connector.connect(host='127.0.0.1',
                               port=3306,
                               user='root',
                               database='my_db')

df = pd.read_sql('select * from persons', conn)
print(df)
    id      name
0    1   Robot-1
1    2   Robot-2
2    3   Robot-3
書き込み

df.to_sqlで実行すればよいが、引数conにはSQLAlchemyのengineを指定しないと実行できなかった。

url = 'mysql+pymysql://username:password@127.0.0.1/my_db'
engine = sqlalchemy.create_engine(url, echo=True)

df = pd.read_csv('robot.csv')

# 第一引数にテーブル名を指定。
# conにはengineを指定
# index=FalseにしてDataFrameのインデックスは無効化した。
# if_existsをappendとしてテーブルにデータを新規に追加する
df.to_sql('persons', 
          con=engine, 
          index=False, 
          if_exists='append')

[注意事項]

ここで、if_existsは、'append'のほか、'fail','replace'を指定できるが、'fail'はテーブルが存在していたらValueErrorになる。

'replae'を指定すると、drop tableしてからデータをインサートするので注意が必要。

また、用意したデータ(robot.csv)はこちら。

robot.csv
id,name
100,Robot-101
101,Robot-102
102,Robot-103

echo=Trueengineを生成しているので、SQL実行ログも出力してくれる。

2018-09-02 19:11:02,923 INFO sqlalchemy.engine.base.Engine SHOW VARIABLES LIKE 'sql_mode'
2018-09-02 19:11:02,923 INFO sqlalchemy.engine.base.Engine {}
2018-09-02 19:11:02,926 INFO sqlalchemy.engine.base.Engine SELECT DATABASE()
2018-09-02 19:11:02,926 INFO sqlalchemy.engine.base.Engine {}
2018-09-02 19:11:02,927 INFO sqlalchemy.engine.base.Engine show collation where `Charset` = 'utf8mb4' and `Collation` = 'utf8mb4_bin'
2018-09-02 19:11:02,927 INFO sqlalchemy.engine.base.Engine {}
2018-09-02 19:11:02,928 INFO sqlalchemy.engine.base.Engine SELECT CAST('test plain returns' AS CHAR(60)) AS anon_1
2018-09-02 19:11:02,928 INFO sqlalchemy.engine.base.Engine {}
2018-09-02 19:11:02,929 INFO sqlalchemy.engine.base.Engine SELECT CAST('test unicode returns' AS CHAR(60)) AS anon_1
2018-09-02 19:11:02,929 INFO sqlalchemy.engine.base.Engine {}
2018-09-02 19:11:02,929 INFO sqlalchemy.engine.base.Engine SELECT CAST('test collated returns' AS CHAR CHARACTER SET utf8mb4) COLLATE utf8mb4_bin AS anon_1
2018-09-02 19:11:02,929 INFO sqlalchemy.engine.base.Engine {}
2018-09-02 19:11:02,930 INFO sqlalchemy.engine.base.Engine DESCRIBE `persons`
2018-09-02 19:11:02,930 INFO sqlalchemy.engine.base.Engine {}
2018-09-02 19:11:02,932 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2018-09-02 19:11:02,932 INFO sqlalchemy.engine.base.Engine INSERT INTO persons (id, name) VALUES (%(id)s, %(name)s)
2018-09-02 19:11:02,932 INFO sqlalchemy.engine.base.Engine ({'id': 100, 'name': 'Robot-101'}, {'id': 101, 'name': 'Robot-102'}, {'id': 102, 'name': 'Robot-103'})
2018-09-02 19:11:02,936 INFO sqlalchemy.engine.base.Engine COMMIT

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10