最近、セキュリティログをCSVファイルでダウンロードして操作していたのですが、pythonのpandasを利用して自動化したいと思い、Pandasの勉強をしてみました。
Pandasとは
pandasは、Pythonで表形式のデータを扱うためのライブラリです。データ分析、加工、保存、可視化まで幅広く使われます。
Pandasの使用
使用する際には、最初に下のインポート文を記載します。
import pandas as pd
データ構造の基本
1次元のSeriesと、2次元のDataFrameがあります。
# Series(1列のデータ)
s = pd.Series([10, 20, 30])
# DataFrame(2次元のデータ)
data = {
'名前': ['合田', '飯田', '上田'],
'年齢': [33, 32, 30]
}
df = pd.DataFrame(data)
Pandasでは行のことをインデックスと呼び、列のことをカラムと呼びますが、このサイトでは基本的には行・列で記載します。
データの表示
データを表示させるときは、下のprint文を使います。
> print(s)
0 10
1 20
2 30
dtype: int64
> print(df)
名前 年齢
0 合田 33
1 飯田 32
2 上田 30
データが多いと、途中が省略されます。その場合には下のオプションを使えば変更できます。
> pd.set_option('display.max_rows', 20) # 行が20行を超えたら省略表示される
> pd.set_option('display.min_rows', 10) # 省略表示時に上下で表示される行数(例:5行+5行)
データの書き込み、読み込み
データをCSV、EXCEL、JSON、Pandas形式で書き込み・読み込みする方法を下に記載します。
df.to_csv('output.csv', index=False, encoding='utf-8-sig')
df.to_excel('output.xlsx', index=False, engine='openpyxl')
df.to_json('output.json', orient='records', force_ascii=False)
df.to_pickle('output.pkl')
df_csv = pd.read_csv('output.csv')
df_excel = pd.read_excel('output.xlsx', engine='openpyxl')
df_json = pd.read_json('output.json')
df_pickle = pd.read_pickle('output.pkl')
型の宣言
上記のように日付を文字列として書かれた場合は、日付として認識されないため誤動作を起こします。これを回避するために型を変換する必要があります。
data = {
'名前': ['合田', '飯田', '上田', '江田', '小田'],
'出身地': ['東京都', '千葉県', '千葉県', '不明', None],
'生年月日': ['2000/5/1', '2000/4/1', None, '2000/7/1', None],
'体重(kg)': [65, 65, 75, 0, None]
}
df = pd.DataFrame(data)
df['生年月日'] = pd.to_datetime(df['生年月日'], errors='coerce')
| 名前 | 出身地 | 生年月日 | 体重(kg) | |
|---|---|---|---|---|
| 0 | 合田 | 東京都 | 2000-05-01 | 65.0 |
| 1 | 飯田 | 千葉県 | 2000-04-01 | 65.0 |
| 2 | 上田 | 千葉県 | NaT | 75.0 |
| 3 | 江田 | 不明 | 2000-07-01 | 0.0 |
| 4 | 小田 | None | NaT | NaN |
※左端のカラムはPandasにより自動で付けられたインデックスです。
カラム名の取り出し
カラムのみ取り出したいときは、以下のコマンドを使用します。
> df.columns
Index(['名前', '出身地', '生年月日', '体重(kg)'], dtype='object')
並び替え
体重(kg)、生年月日を降順でソートした結果を出力します。
> df.sort_values(by=["体重(kg)","生年月日"],ascending=False)
名前 出身地 生年月日 体重(kg)
2 上田 千葉県 NaT 75.0
0 合田 東京都 2000-05-01 65.0
1 飯田 千葉県 2000-04-01 65.0
3 江田 不明 2000-07-01 0.0
4 小田 None NaT NaN
列の抽出
カラム出身地だけを取り出す。
> df['出身地']
2 千葉県
0 東京都
1 千葉県
3 不明
4 None
Name: 出身地, dtype: object
データ欠損関連
更にNoneや重複データを取り除く。
> df['出身地'].dropna()
0 東京都
1 千葉県
2 千葉県
3 不明
Name: 出身地, dtype: object
不明のようなデータも一緒に取り除きたい場合には、先に不明をNoneに変換しておく。
> df['出身地'].replace('不明',pd.NA).dropna()
0 東京都
1 千葉県
2 千葉県
Name: 出身地, dtype: object
重複関連
同じデータを削除します。
> df['出身地'].drop_duplicates()
0 東京都
1 千葉県
3 不明
4 None
Name: 出身地, dtype: object
重複の数を取り出す
> df['出身地'].value_counts()
出身地
千葉県 2
東京都 1
不明 1
Name: count, dtype: int64
SeriesをDataFrameに変換する
> df['出身地'].value_counts().reset_index()
出身地 count
0 千葉県 2
1 東京都 1
2 不明 1
行の抽出
下のデータに対して処理します。ソートがかかっているため、インデックスの並びが違っています。
> df_sorted = df.sort_values(by=["体重(kg)","生年月日"])
> print(df_sorted)
名前 出身地 生年月日 体重(kg)
3 江田 不明 2000-07-01 0.0
1 飯田 千葉県 2000-04-01 65.0
0 合田 東京都 2000-05-01 65.0
2 上田 千葉県 NaT 75.0
4 小田 None NaT NaN
ilocだと、df_sortedの一番上(0行目)を抽出し、
> df_sorted.iloc[0]
名前 江田
出身地 不明
生年月日 2000-07-01 00:00:00
体重(kg) 0.0
Name: 3, dtype: object
locだと、df_sortedのインデックスが0である行を抽出します。
> df_sorted.loc[0]
名前 合田
出身地 東京都
生年月日 2000-05-01 00:00:00
体重(kg) 65.0
Name: 0, dtype: object
条件付き選択
出身地が千葉県で、かつ、体重(kg)が70より大きいインデックスのみ取り出す。
> df[(df['出身地']=='千葉県') & (df['体重(kg)'] > 70)]
名前 出身地 生年月日 体重(kg)
2 上田 千葉県 NaT 75.0
日付も文字列そのままの比較できます。
> df[df['生年月日'] > '2000-04-01 12:00:00']
名前 出身地 生年月日 体重(kg)
0 合田 東京都 2000-05-01 65.0
3 江田 不明 2000-07-01 0.0
queryを使う記述方法もあります。
> df.query(" 出身地 == '千葉県' ")
名前 出身地 生年月日 体重(kg)
1 飯田 千葉県 2000-04-01 65.0
2 上田 千葉県 NaT 75.0
列の追加
列を追加するサンプルを記載します。
> df['年齢'] = [ 25,25,30,25,40 ]
> print(df)
名前 出身地 生年月日 体重(kg) 年齢
0 合田 東京都 2000-05-01 65.0 25
1 飯田 千葉県 2000-04-01 65.0 25
2 上田 千葉県 NaT 75.0 30
3 江田 不明 2000-07-01 0.0 25
4 小田 None NaT NaN 40
行の追加
行を追加するサンプルを記載します。
まずは、追加する行を作成します。
> new_row_dict = dict(zip(df.columns, ['神田','神奈川県',pd.to_datetime('2000-08-01'),90]))
> new_row_df = pd.DataFrame([new_row_dict])
> print(new_row_df)
名前 出身地 生年月日 体重(kg)
0 神田 神奈川県 2000-08-01 90
次に、既存のDataFrameに追加します。
> df = pd.concat([df, new_row_df], ignore_index=True)
> print(df)
名前 出身地 生年月日 体重(kg)
0 合田 東京都 2000-05-01 65.0
1 飯田 千葉県 2000-04-01 65.0
2 上田 千葉県 NaT 75.0
3 江田 不明 2000-07-01 0.0
4 小田 None NaT NaN
5 神田 神奈川県 2000-08-01 90.0
列の削除
列を削除するサンプルを記載します。
> df = df.drop(columns='体重(kg)')
> print(df)
名前 出身地 生年月日
0 合田 東京都 2000-05-01
1 飯田 千葉県 2000-04-01
2 上田 千葉県 NaT
3 江田 不明 2000-07-01
4 小田 None NaT
行を削除
行の削除は、行の選択と同じです。
> df = df.drop(index=1) #インデックスが1のものを削除
> print(df)
名前 出身地 生年月日 体重(kg)
0 合田 東京都 2000-05-01 65.0
2 上田 千葉県 NaT 75.0
3 江田 不明 2000-07-01 0.0
4 小田 None NaT NaN
> df = df[df['出身地']!='千葉県'] #出身地が千葉県のものを削除
> print(df)
名前 出身地 生年月日 体重(kg)
0 合田 東京都 2000-05-01 65.0
3 江田 不明 2000-07-01 0.0
4 小田 None NaT NaN
データの変更
特定の条件に合う項目の値を変更します、
> df.loc[df['名前']=='上田','生年月日'] = pd.to_datetime('1990-06-01')
> print(df)
名前 出身地 生年月日 体重(kg)
0 合田 東京都 2000-05-01 65.0
1 飯田 千葉県 2000-04-01 65.0
2 上田 千葉県 1990-06-01 75.0
3 江田 不明 2000-07-01 0.0
4 小田 None NaT NaN
まとめ
始めたばかりということなので、まずはこのあたりを勉強しました。
次回は、データの集計について書きたいと思います。