5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

バッチ処理などで一時テーブルにCSVを投入してデータを処理してましたが
Pandasを使ってみたら高速で尚且つSELECT文を扱うようにCSVの操作が
出来たのでまとめて見ました。
Pandasでデータ分析と聞くと難しそうで距離をおいてましたが
大量データの処理はPandasでいこうかと思っています
Excelで大量のデータを扱ってる人にもExcelを直接開くことが出来るのでお勧めです

前準備

  • pandas 
    データ解析機能を提供するpythonライブラリ
    pipでpandasをインストール
command line
 pip install pandas
 # または pip3 install pandas

今回使用するCSVファイルがこちらになります

hoge_a.csv
name,salary,postcode, birthday
山田, 200,   038-0056, 2004/1/3
佐藤, 300,   300-0727, 1999/6/30
鈴木, 500,   132-0013, 1980/3/3
川田, 700,   300-0727, 1975/11/23
山田, 250,   038-0056, 2004/1/25
山田, 350,   030-0932, 1987/9/12
hoge_b.csv
name,address
山田,    青森
田中,    秋田
佐藤,    茨城
鈴木,    東京
hoge_c.csv
name,salary,age
山田,   200, 20
山田,   350, 44
佐藤,   300, 25
鈴木,   500, 37

※実際に使う場合は空白の部分を詰めてください

CSV読み込み

PandasCsv.py
import pandas as pd

df_a = pd.read_csv("./hoge_a.csv")
df_b = pd.read_csv("./hoge_b.csv")

read_csvでCSVをDataFrameオブジェクトとして読み込んでいます
パラメータを指定していないので、一行目が列名になります

pd.read_csv("./hoge_a.csv",names=['a','b','c','d'])のようにすればnamesの部分を列名にすることもできます
(その場合には、一行目もデータとして扱われます)
read_csvのパラメータ一覧

SELECT

PandasCsv.py
# SELECT name, salary FROM df_a
print(df_a[["name", "salary"]])

実行結果

command line
    name  salary
0   山田     200
1   佐藤     300
2   鈴木     500
3   川田     700
4   山田     250
5   山田     350

DataFrameから指定した列名の列を選択しています
["列名1", "列名2"]のように複数の列名をリストで渡します

ORDER BY

PandasCsv.py
# SELECT * FROM df_a ORDER BY name DESC, salary DESC
print(df_a.sort_values(by=["name", "salary"], ascending=False, ignore_index=True))

実行結果

command line
    name  salary  postcode    birthday
0   鈴木     500  132-0013    1980/3/3
1   川田     700  300-0727  1975/11/23
2   山田     350  030-0932   1987/9/12
3   山田     250  038-0056    2004/1/25
4   山田     200  038-0056    2004/1/3
5   佐藤     300  300-0727   1999/6/30

sort_valuesで渡した列名のリストをターゲットにして並び替えています(リストの最初に指定した列が優先されます)

使用しているパラメータ

  • by(必須):並び替えの対象にする列名
  • ascending:昇順かどうか(Falseで降順)
  • ignore_index:並び順を変更する前のindexを無視するかどうか
    (Trueでindexを新しく振りなおします)

sort_valuesのパラメータ

日付はCSVから読み込んだ段階では、strなので(例:3と25が正しく並び変わらない)ORDER BYする際には、日付型に変更する必要があります

PandasCsv.py
# SELECT * FROM df_a ORDER BY birthday DESC
df_a["birthday"] = pd.to_datetime(df_a["birthday"])
print(df_a.sort_values(by=["birthday"], ascending=False, ignore_index=True))

実行結果

command line
変換なし
    name  salary  postcode    birthday
0   山田     200  038-0056    2004/1/3
1   山田     250  038-0056   2004/1/25
2   佐藤     300  300-0727   1999/6/30
3   山田     350  030-0932   1987/9/12
4   鈴木     500  132-0013    1980/3/3
5   川田     700  300-0727  1975/11/23
変換あり
    name  salary  postcode   birthday
0   山田     250  038-0056 2004-01-25
1   山田     200  038-0056 2004-01-03
2   佐藤     300  300-0727 1999-06-30
3   山田     350  030-0932 1987-09-12
4   鈴木     500  132-0013 1980-03-03
5   川田     700  300-0727 1975-11-23

WHERE

PandasCsv.py
# SELECT * FROM df_a WHERE salary >= 400 AND postcode == "300-0727"
print(df_a[(df_a["salary"] >= 400) & (df_a["postcode"] == "300-0727")])
# または
print(df_a.query("salary >= 400 and postcode == '300-0727'"))

実行結果

command line
    name  salary  postcode    birthday
3   川田     700  300-0727  1975/11/23

df_a[条件]で条件にあった行を抽出できます
またはqueryに条件式を渡しても同じように行を抽出できます

queryのパラメータ

df_a[(df_a["salary"] >= 400) & (df_a["postcode"] == "300-0727")]df_a.query("salary >= 400 and postcode == '300-0727'")もDataFrameになるので
df[["salary", "name"]]のように列を抽出できます

PandasCsv.py
# SELECT salary, name FROM df_a WHERE salary == 1 AND postcode == 'a'
df_new = df_a[(df_a["salary"] >= 400) & (df_a["postcode"] == "300-0727")]
# または
df_new = df_a.query("salary >= 400 and postcode == '300-0727'")
print(df_new[["salary", "name"]])

実行結果

command line
   salary   name
3     700   川田

MAX, MIN, AVG, SUM, COUNT

PandasCsv.py
# MAX 
# SELECT MAX(name), MAX(salary), MAX(postcode), MAX(birthday) FROM df_a
df_a["birthday"] = pd.to_datetime(df_a["birthday"]) # 日付は変換が必要
print(df_a[["name", "salary", "postcode", "birthday"]].max())

# MIN
# SELECT MIN(name), MIN(salary), MIN(postcode), MIN(birthday) FROM df_a
df_a["birthday"] = pd.to_datetime(df_a["birthday"]) # 日付は変換が必要
print(df_a[["name", "salary", "postcode", "birthday"]].min())

# AVG
# SELECT AVG(salary) FROM df_a
print(df_a["salary"].mean())

# SUM
# SELECT SUM(name), SUM(salary) FROM df_a
print(df_a[["name", "salary"]].sum())

# COUNT
# SELECT COUNT(name) FROM df_a
print(df_a[["name"]].count())

実行結果

command line
# MAX
name                         鈴木
salary                      700
postcode               300-0727
birthday    2004-01-25 00:00:00
dtype: object


# MIN
name                         佐藤
salary                      200
postcode               030-0932
birthday    1975-11-23 00:00:00
dtype: object

# AVG
383.3333333333333

# SUM
name      山田佐藤鈴木川田山田山田
salary            2300
dtype: object

# COUNT
name    6
dtype: int64

df_a[["列名1", "列名2"]]で列を指定してmax(最大値) min(最小値) mean(平均値) sum(合計値) count(個数)をそれぞれ実行しています

maxのパラメータ
minのパラメータ
meanのパラメータ
sumのパラメータ
countのパラメータ

GROUP BY

PandasCsv.py
# SELECT name, postcode, SUM(salary) FROM df_a GROUP BY name, postcode
print(df_a.groupby(["name", "postcode"])["salary"].sum().reset_index())

実行結果

command line
    name  postcode  salary
0   佐藤  300-0727     300
1   山田  030-0932     350
2   山田  038-0056     450
3   川田  300-0727     700
4   鈴木  132-0013     500

groupby(列名)でグループ化する列を指定してその後の[列名]sum(合計)しています。また、reset_indexで新しくインデックスを振りなおしています

groupbyのパラメータ
reset_indexのパラメータ

JOIN

PandasCsv.py
# SELECT * FROM df_a LEFT JOIN df_b ON df_a.name = df_b.name
print(pd.merge(df_a, df_b, on="name", how="left"))

実行結果

command line
    name  salary  postcode    birthday  address
0   山田     200  038-0056    2004/1/3      青森
1   佐藤     300  300-0727   1999/6/30      茨城
2   鈴木     500  132-0013    1980/3/3      東京
3   川田     700  300-0727  1975/11/23      NaN
4   山田     250  038-0056   2004/1/25      青森
5   山田     350  030-0932   1987/9/12      青森

mergeを使って二つのテーブルを結合しています

使用しているパラメータ

  • on:結合の対象にする列名(配列で渡せば複数列も可能)
  • how:結合方法の指定(defaultではinner)

mergeのパラメータ

pd.merge(df_a, df_b, on="name", how="left")これもDataFrameになりますので、さらに結合できます。

PandasCsv.py
# SELECT * FROM df_a LEFT JOIN df_b ON df_a.name = df_b.name LEFT JOIN df_a.name = df_c.name
df_ab = pd.merge(df_a, df_b, on="name", how="left")
df_abc = pd.merge(df_ab, df_c, on=["name", "salary"], how="left")
df_abc["age"] = df_abc["age"].astype(pd.Int64Dtype()) 
print(df_abc)

実行結果

command line
    name  salary  postcode    birthday  address   age
0   山田     200  038-0056    2004/1/3      青森    20
1   佐藤     300  300-0727   1999/6/30      茨城    25
2   鈴木     500  132-0013    1980/3/3      東京    37
3   川田     700  300-0727  1975/11/23       NaN   <NA>
4   山田     250  038-0056    2004/1/25      青森   <NA>
5   山田     350  030-0932   1987/9/12      青森    44

df_abc["age"] = df_abc["age"].astype(pd.Int64Dtype())では結合でintの列にNaNがあるとfloatになるのNaNを扱える整数型Int64で変換

AS

PandasCsv.py
# SELECT name, postcode, name + postcode AS name_postcode FROM df_a
df_a["name_postcode"] = df_a["name"] + df_a["postcode"] # 新しい列を追加
print(df_a[["name", "postcode", "name_postcode"]])

# SELECT name, salary, name + salary AS name_salary FROM df_a
df_a["name_salary"] = df_a["name"] + df_a["salary"].astype(str) # 型が違う場合は.astypeで変換する
print(df_a[["name", "salary", "name_salary"]])

実行結果

command line
    name  postcode  name_postcode
0   山田  038-0056    山田038-0056
1   佐藤  300-0727    佐藤300-0727
2   鈴木  132-0013    鈴木132-0013
3   川田  300-0727    川田300-0727
4   山田  038-0056    山田038-0056
5   山田  030-0932    山田030-0932

    name  salary   name_salary
0   山田     200       山田200
1   佐藤     300       佐藤300
2   鈴木     500       鈴木500
3   川田     700       川田700
4   山田     250       山田250
5   山田     350       山田350

AS句で表示したい列を新しくDataFrameに追加しています

OFFSET FETCH LIMIT

PandasCsv.py
# SELECT * FROM df_a ORDER BY 何かしらの列名 OFFSET 2 ROWS FETCH NEXT 3 ROWS ONLY
# SELECT * FROM df_a LIMIT 3 OFFSET 2
print(df_a.loc[2:4])

実行結果

command line
    name  salary  postcode    birthday
2   鈴木     500  132-0013    1980/3/3
3   川田     700  300-0727  1975/11/23
4   山田     250  038-0056    2004/1/25

loc[インデックス始まり:インデックス終わり]で指定の行から指定の行数を取得できます

locのパラメータ

INSERT

PandasCsv.py
# INSERT INTO df_a (name, salary, postcode, birthday) VALUES ("新田", 280, "682-0022", "2000/12/10")
df_insert = pd.DataFrame({"name":["新田"], "salary":[280], "postcode":["682-0022"], "birthday":["2000/12/10"] })
df_a = pd.concat([df_a, df_insert])
print(df_a.reset_index(drop=True))

実行結果

command line
    name  salary  postcode    birthday
0   山田     200  038-0056    2004/1/3
1   佐藤     300  300-0727   1999/6/30
2   鈴木     500  132-0013    1980/3/3
3   川田     700  300-0727  1975/11/23
4   山田     250  038-0056    2004/1/25
5   山田     350  030-0932   1987/9/12
6   新田     280  682-0022  2000/12/10

追加する行のDataFrameを新しく作り(df_insert)それを元のDataFrame(df_a)に足しています。また、reset_indexで新しくインデックスを振りなおしています

使用しているパラメータ

  • drop:古いインデックスを削除するかどうかの指定

concatのパラメータ
reset_indexのパラメータ

UPDATE

PandasCsv.py
# UPDATE df_a SET name = "上田" WHERE salary >= 250
df_a.loc[(df_a["salary"]>=500),["name"]]="上田"
print(df_a)

実行結果

command line
    name  salary  postcode    birthday
0   山田     200  038-0056    2004/1/3
1   佐藤     300  300-0727   1999/6/30
2   上田     500  132-0013    1980/3/3
3   上田     700  300-0727  1975/11/23
4   山田     250  038-0056    2004/1/25
5   山田     350  030-0932   1987/9/12

loc[(条件式),[列名]]を使ってdf_aの指定の値を上書きしています

locのパラメータ

DELETE

PandasCsv.py
# DELETE FROM df_a WHERE name = 山田
print(df_a[df_a["name"]!="山田"])

実行結果

command line
    name  salary  postcode    birthday
1   佐藤     300  300-0727   1999/6/30
2   鈴木     500  132-0013    1980/3/3
3   川田     700  300-0727  1975/11/23

name=山田を削除する
↓ 言い換えれば
name!=山田を表示する
となりますので↑のコードではname!=山田の行だけを表示しています

参考にさせていただいた記事、サイト

5
4
0

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
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?