pandas:【SQL文で例える】データ抽出方法


準備

前提

データ作成

import pandas as pd
dic = {'id':['01','02','03','04','05'],'name':['a','b','c','d','e'],'value':[70,38,29,93,18],'fold':[1,0,0,2,1],'file':['f1','f2','f3','f4','f5'],'file_base':['f1','f3','f3','f5','f3'],'key':['a001','a002','a003','b001','c001']}
df =pd.DataFrame(dic)
print(df)
print(df.shape)
   id name  value  fold file file_base   key
0  01    a     70     1   f1        f1  a001
1  02    b     38     0   f2        f3  a002
2  03    c     29     0   f3        f3  a003
3  04    d     93     2   f4        f5  b001
4  05    e     18     1   f5        f3  c001
(5, 7)
  • サイズ(5, 7)のデータフレーム作成
  • id,name,file,file_base…文字列型
  • value,fold…数値型
  • 一番左は行のインデックス番号

WHERE句

select * from df where fold = 1;

例1

df[df.fold==1]
   id name  value  fold file file_base   key
0  01    a     70     1   f1        f1  a001
4  05    e     18     1   f5        f3  c001
  • df[行条件]で抽出している
    • 列はすべてなので列名の指定はなし
  • 行条件
    • df.fold==1
    • 行の指定(ブールインデックス参照)
    • fold列が1と等しい行のみTrueになったデータ

例2

df.iloc[df.index[df.fold==1]]
   id name  value  fold file file_base   key
0  01    a     70     1   f1        f1  a001
4  05    e     18     1   f5        f3  c001
  • df.loc[行番号]で抽出している
    ※例1と違って行番号なので注意
    • 列はすべてなので列名の指定はなし
  • 行番号
    • df.index[df.fold==1]
    • df.fold==1
      • fold列が1と等しい行のみTrueになったデータ
    • df.index[…]
      • 引数にブールインデックスを指定
      • Trueになっている行のみインデックス番号を返す
      • この例だとインデックス番号は0と4

select id, name from df where fold = 0;

例1

df[df.fold==0][['id','name']]
   id name
1  02    b
2  03    c
  • df[行条件][列名]で抽出している
  • 行条件
    • df.fold==0
    • 行の指定(ブールインデックス参照)
    • fold列が0と等しい行のみTrueになったデータ
  • 列名
    • ['id’,’name’]
    • リスト形式で複数列指定

例2(df.locを使用した例)

df.loc[df.index[df.fold==0],['id','name']]
   id name
1  02    b
2  03    c
  • df.loc[行番号,列名]で抽出している
    ※例1と違って行番号なので注意
  • 行番号
    • df.index[df.fold==0]
    • df.fold==0
      • fold列が0と等しい行のみTrueになったデータ
    • df.index[…]
      • 引数にブールインデックスを指定
      • Trueになっている行のみインデックス番号を返す
      • この例だとインデックス番号は1と2
  • 列名
    • ['id’,’name’]
    • リスト形式で複数列指定

副問合せ、GROUP BY

select * from df where file in (select file_base from df where fold != 2 group by file_base);

全文

df[df['file'].isin(df.loc[:,'file_base'][df['fold'] != 2].unique())]
   id name  value  fold file file_base   key
0  01    a     70     1   f1        f1  a001
2  03    c     29     0   f3        f3  a003
  • 次の3つの構成
  • SELECT句
    • df[…]
    • 全列なので行のみ指定
  • WHERE句
    • df['file’].isin(…)
    • file列を絞り込む
    • …に対象のリスト
  • サブクエリ(副問い合わせ部分)
    • df.loc[:,’file_base’][df['fold’] != 2].unique()
    • SQL文ではサブクエリの部分
    • fold列が2以外の条件(where fold !=2)
    • file_base列でuniqueを使ってGroup byと同等の処理(group by file_base)

サブクエリ(df.loc[:,’file_base’][df['fold’] != 2].unique())

w = df.loc[:,'file_base'][df['fold'] != 2].unique()
w1 = df.loc[:,'file_base']
w2 = w1[df['fold'] != 2]
w3 = w2.unique()
print(w)
print(w.shape)
print(w1)
print(w1.shape)
print(w2)
print(w2.shape)
print(w3)
print(w3.shape)
['f1' 'f3']
(2,)
0    f1
1    f3
2    f3
3    f5
4    f3
Name: file_base, dtype: object
(5,)
0    f1
1    f3
2    f3
4    f3
Name: file_base, dtype: object
(4,)
['f1' 'f3']
(2,)
  • w
    • ['f1’ 'f3’]がwの結果
  • w1
    • df.locを使って列絞り込み
    • 行は「:」なので全5行
    • (4, )のサイズになっている(Series)
  • w2
    • fold列が2でないデータのboolインデックス
    • w1の全5行からboolインデックス参照
    • 結果4行
  • w3
    • f1,f1,f1,f3のデータをユニーク(unique)にする
    • w結果['f1’ 'f3’]を得る

WHERE句(df['file’].isin(…))

sub_query = df.loc[:,'file_base'][df['fold'] != 2].unique()
w = df['file'].isin(sub_query)
print(w)
0     True
1    False
2     True
3    False
4    False
Name: file, dtype: bool
  • sub_query
    • 前項の通り[f1,f3]
    • リストになっている
  • w
    • file列がf1,f3の行がTrueになっているブールインデックス
    • インデックス番号0,2の行がTure

SELECT句(df[…])

w = df['file'].isin(df.loc[:,'file_base'][df['fold'] != 2].unique())
rtn = df[w]
print(rtn)
   id name  value  fold file file_base   key
0  01    a     70     1   f1        f1  a001
2  03    c     29     0   f3        f3  a003
  • w
    • 前項の通りブールインデックス
    • file列がf1,f3の行がTrue
  • rtn
    • ブールインデックス参照により行が抽出される
    • 抽出される行はインデックス番号が0,2
    • 最初の”全文”の結果と一致する

部分一致(LIKE)

select * from df where key like 'a%’;(前方一致)
select * from df where key like '%001’;(後方一致)

全文

x = df[df['key'].str.contains('^a')]
y = df[df['key'].str.contains('001$')]
print(x)
print(x.shape)
print(y)
print(y.shape)
   id name  value  fold file file_base   key
0  01    a     70     1   f1        f1  a001
1  02    b     38     0   f2        f3  a002
2  03    c     29     0   f3        f3  a003
(3, 7)
   id name  value  fold file file_base   key
0  01    a     70     1   f1        f1  a001
3  04    d     93     2   f4        f5  b001
4  05    e     18     1   f5        f3  c001
(3, 7)
  • a
    • key列がaで始まる行を抽出
    • 「^a」
      • 正規表現の記号=「^」
      • aで始まると言う意味
  • b
    • key列が001で終わる行を抽出
    • 「001$」
      • 正規表現の記号=「$」
      • 001で終わると言う意味

LIKE句の部分だけ実行

df['key'].str.contains('^a')
0     True
1     True
2     True
3    False
4    False
Name: key, dtype: bool
  • df['key’]
    • key列を指定
  • str.contains('a’)
    • 文字列aを含む行がTrue
    • インデックス番号0,1,2がTrueのブールインデックス

集計(COUNT(*) GROUP BY)

select count(*) from df group by file_base;

a = df.file_base.value_counts()
print(a)
f3    3
f1    1
f5    1
Name: file_base, dtype: int64
  • df.file_base
    • 列名を指定
    • group by句に相当
  • value_counts()
    • 集計関数
    • count(*)に相当
  • f3が3件、f1とf5は1件ずつの結果を得た


Posted by futa