こちらのウェビナーで説明した内容の抜粋です。最初のセクションの「pandasを用いたデータ分析」をカバーしています。今さら聞けないPython - Pythonの基礎の続きです。
全体構成は以下の通りです。
- 今さら聞けないPython - Pythonの基礎
- 今さら聞けないPython - pandasを用いたデータ分析
- 今さら聞けないPython - scikit-learnを用いた機械学習
- 今さら聞けないPython - Sparkのご紹介
ウェビナーで使用したノートブックはこちらにあります。
本記事でカバーしているノートブックはこちらです。
-
pandas
を使う動機づけ -
pandas
とその歴史 - COVID-19データセットのインポート
pd.read_csv()
- データの要約
-
head
,tail
,shape
-
sum
,min
,count
,mean
,std
describe
-
- データのスライスと加工
- スライス,
loc
,iloc
value_counts
drop
sort_values
- フィルタリング
- スライス,
- データのグルーピングおよび集計関数の実行
groupby
- 欠損値、重複への対応
isnull
-
unique
,drop_duplicates
fillna
- 可視化
- ヒストグラム
- 散布図
- 折れ線グラフ
pandas
を使う動機づけ
大きな絵からスタートしましょう...
- 人類は道具を使う動物です
- コンピューターは我々が作り出した最もパワフルなツールの一つです
- コードを書くことで、これらのツールのフルパワーを解き放つことができます
Ok、クールだね。でもなぜpandas
?
-
これまで以上にデータは意思決定において重要となっています。
-
Excelは素晴らしいものですが、もし...
- 毎日新規のデータに対して再実行できるように分析を自動化したいとしたら?
- 同僚と共有できるようにコードベースを構築したいとしたら?
- ビジネス上の意思決定につながるより堅牢な分析を必要としたら?
- 機械学習を行いたいとしたら?
-
Pythonにおけるデータ分析やデータサイエンティストによって使用されるコアのライブラリの一つが
pandas
にようこそ...
pandas
とその歴史
pandas
は、Pythonプログラミング言語上で開発された、高速、パワフル、柔軟かつ、簡単に使用できるオープンソースのデータ分析、データ操作ツールです。
ハイライト:
- 2008年に開発され、2009年にオープンソース化されました。
- インデックスがインテグレーションされたデータ操作のための高速かつ効率的なデータフレームオブジェクト
- インメモリーのデータ構造と様々なフォーマット間のデータ読み書きツール: CSV、テキストファイル、Microsoft Excel、SQLデータベース、高速なHDF5フォーマット。
- インテリジェントなデータアライメントとインテグレーションされた欠損データへの対応: 計算時に自動でラベルベースのアライメントを取得し、汚いデータを容易に綺麗な状態に変換。
- データセットに対する柔軟な リシェイプとピボット。
- 大規模データセットに対するインテリジェントなラベルベースの スライス、ファンシーインデックス、サブセット作成。
- サイズ可変性を持つデータ構造に対するカラムの追加・削除。
- パワフルなgroup byを用いたデータの集計、変換によるデータセットに対するsplit-apply-combineオペレーション。
- データセットに対する高性能のマージとジョイン。
- 階層型軸インデックスによる、低次元データ構造における直感的な高次元データ操作手段の提供。
- 時系列機能: 日付範囲の生成、頻度変換、移動ウィンドウ統計情報、日付シフト、ラギング。ドメイン固有の時間オフセットの作成、データ損失なしの時系列データのジョインもサポート。
- Cython、Cで記述されたクリティカルなコードパスにより高度に最適化されたパフォーマンス。
- Pythonとpandasは、金融、神経科学、経営、統計学、広告、Web分析などを含むさまざまな学術、商用の領域で活用されています。
COVID-19データセットのインポート
フォルダー構造を検索するために %sh ls
を使います。%sh
はDatabricksノートブックでシェルコマンドを実行することができるマジックコマンドです。
%sh ls /dbfs/databricks-datasets/COVID/
CORD-19
CSSEGISandData
ESRI_hospital_beds
IHME
USAFacts
coronavirusdataset
covid-19-data
download_daily_covid-19_datasets.sh
estimated_patient_impact_and_hospital_capacity_by_state
%sh ls /dbfs/databricks-datasets/COVID/CSSEGISandData/csse_covid_19_data/csse_covid_19_daily_reports
01-01-2021.csv
01-02-2021.csv
01-03-2021.csv
01-04-2021.csv
01-05-2021.csv
01-06-2021.csv
01-07-2021.csv
01-08-2021.csv
01-09-2021.csv
01-10-2021.csv
CSVファイルの最初の数行を表示するために %sh head
を使います。
%sh head /dbfs/databricks-datasets/COVID/CSSEGISandData/csse_covid_19_data/csse_covid_19_daily_reports/04-11-2020.csv
FIPS,Admin2,Province_State,Country_Region,Last_Update,Lat,Long_,Confirmed,Deaths,Recovered,Active,Combined_Key
45001,Abbeville,South Carolina,US,2020-04-11 22:45:33,34.22333378,-82.46170658,9,0,0,0,"Abbeville, South Carolina, US"
22001,Acadia,Louisiana,US,2020-04-11 22:45:33,30.295064899999996,-92.41419698,98,4,0,0,"Acadia, Louisiana, US"
51001,Accomack,Virginia,US,2020-04-11 22:45:33,37.76707161,-75.63234615,15,0,0,0,"Accomack, Virginia, US"
16001,Ada,Idaho,US,2020-04-11 22:45:33,43.4526575,-116.24155159999998,513,6,0,0,"Ada, Idaho, US"
19001,Adair,Iowa,US,2020-04-11 22:45:33,41.33075609,-94.47105874,1,0,0,0,"Adair, Iowa, US"
pandas
をインポートします。別名をpd
とします。
import pandas as pd
CSVファイルを読み込みます。これによってデータフレーム
が生成されます。1行目のコマンドではファイルシステムユーティリティを用いてファイルをローカルにコピーしています。
dbutils.fs.cp("dbfs:/databricks-datasets/COVID/CSSEGISandData/csse_covid_19_data/csse_covid_19_daily_reports/04-11-2020.csv", "file:/tmp/covid.csv")
pd.read_csv("file:/tmp/covid.csv")
それでは数行のコードを組み合わせて、再利用できるようにデータフレーム
を保存してみましょう。
import pandas as pd
df = pd.read_csv("file:/tmp/covid.csv")
df
データの要約
データの最初の数行と最後の数行を見てみましょう。
df.head()
df.tail(2)
データセットは何行でしょうか?
df.shape
Out[10]: (2967, 12)
データを要約しましょう。
# df.sum()
# df.min()
# df.max()
# df.count()
df.mean()
# df.std()
Out[11]: FIPS 31172.744602
Lat 36.564846
Long_ -80.663000
Confirmed 584.822042
Deaths 36.747893
Recovered 135.600944
Active 259.575666
dtype: float64
これらのサマリー統計情報を集計して表示することができます...
df.describe()
データのスライスと加工
感染者数だけを取り出します。
df['Confirmed']
Out[13]: 0 9
1 98
2 15
3 513
4 1
...
2962 268
2963 1
2964 40
2965 14
2966 0
Name: Confirmed, Length: 2967, dtype: int64
国と感染者数を取り出します。その前に、データフレームの列名を取得します。
df.columns
Out[14]: Index(['FIPS', 'Admin2', 'Province_State', 'Country_Region', 'Last_Update',
'Lat', 'Long_', 'Confirmed', 'Deaths', 'Recovered', 'Active',
'Combined_Key'],
dtype='object')
df[['Country_Region', 'Confirmed']]
新たなカラム Date
を作成します。
import datetime
df["Date"] = datetime.date(2020, 4, 11)
df["Date"].head()
Out[17]: 0 2020-04-11
1 2020-04-11
2 2020-04-11
3 2020-04-11
4 2020-04-11
Name: Date, dtype: object
データフレームの最初の11行を取り出してスライスします。
df.loc[:10, ['Country_Region', 'Confirmed']]
# df.loc[0:10, ['Country_Region', 'Confirmed']] # 同じ処理です
最初の行の最初のカラムだけを返却します。
df.iloc[0, 0]
Out[19]: 45001.0
国ごとにいくつの地域があるのでしょうか?value_counts
を使用して、値ごとのカウントをとります。
df["Country_Region"].value_counts()
Out[20]: US 2702
China 33
Canada 16
United Kingdom 12
France 11
...
Georgia 1
Germany 1
Ghana 1
Greece 1
Zimbabwe 1
Name: Country_Region, Length: 185, dtype: int64
FIPSとはなんでしょうか?ここでは不要なので削除します。drop
の引数axis=1
は列方向であることを指定しています。
df = df.drop("FIPS", axis=1)
感染者数でソートします。引数ascending=False
は降順を指定しています。
df.sort_values("Confirmed", ascending=False)
アメリカ(US)で起きていることだけを見てみましょう。
df[df["Country_Region"] == "US"]
データのグルーピングと集計関数の実行
感染者数が最も多い国はどこでしょうか?データをグルーピングし合計を計算します。集計関数はスカラー値(単一の値)を返却することに注意してください。
Country_Region
をキーにグルーピングを行い、グループごとの感染者数Confirmed
の合計をsum()
で取得し、感染者数合計の降順で表示します。
df.groupby("Country_Region")["Confirmed"].sum().sort_values(ascending=False)
Out[26]: Country_Region
US 526764
Spain 163027
Italy 152271
Germany 124908
France 93909
...
South Sudan 4
Timor-Leste 2
Papua New Guinea 2
Yemen 1
Samoa 0
Name: Confirmed, Length: 185, dtype: int64
感染者数が最も多いUSの州はどこでしょうか?フィルタリング条件を追加し、Province_State
ごとに集計します。
df[df['Country_Region'] == "US"].groupby("Province_State")["Confirmed"].sum().sort_values(ascending=False)
Out[27]: Province_State
New York 181026
New Jersey 58151
Michigan 23605
Massachusetts 22860
Pennsylvania 21719
California 21711
Louisiana 20014
Illinois 19180
Florida 18494
Texas 13145
Georgia 12159
Connecticut 11510
欠損データと重複への対応
null値はあるのでしょうか?
df.isnull().tail()
sum()
でnull値の数を取得することができます。
df.isnull().sum()
Out[29]: Admin2 272
Province_State 181
Country_Region 0
Last_Update 0
Lat 58
Long_ 58
Confirmed 0
Deaths 0
Recovered 0
Active 0
Combined_Key 0
Date 0
dtype: int64
df['Country_Region'].unique().shape
Out[30]: (185,)
null値を特定の値で置き換えることもできます。
df.fillna("NO DATA AVAILABLE").tail(3)
可視化
- ヒストグラム
- 散布図
- 折れ線グラフ
import matplotlib.pyplot as plt
%matplotlib inline
us_subset_df = df[df["Country_Region"] == "US"]
USの州と地域ごとの死者数の 分布 はどうなっているのでしょうか?
us_subset_df.groupby("Province_State")["Deaths"].sum().hist(bins=30)
死者数に比べて感染者数はどうなっているのでしょうか?
us_subset_df[us_subset_df["Deaths"] < 1000].plot.scatter(x="Confirmed", y="Deaths")
複数の日のデータをインポートします。
src_path_base = "dbfs:/databricks-datasets/COVID/CSSEGISandData/csse_covid_19_data/csse_covid_19_daily_reports/"
dest_path_base = "file:/tmp/covid_daily_reports/"
files = [
'11-21-2020.csv',
'11-22-2020.csv',
'11-23-2020.csv',
'11-24-2020.csv',
'11-25-2020.csv',
'11-26-2020.csv',
'11-27-2020.csv',
'11-28-2020.csv',
'11-29-2020.csv',
'11-30-2020.csv'
]
dfs = []
for file in files:
filename = dest_path_base+file
dbutils.fs.cp(src_path_base+file, filename)
temp_df = pd.read_csv(filename)
temp_df.columns = [c.replace("/", "_") for c in temp_df.columns]
temp_df.columns = [c.replace(" ", "_") for c in temp_df.columns]
month, day, year = filename.split("/")[-1].replace(".csv", "").split("-")
d = datetime.date(int(year), int(month), int(day))
temp_df["Date"] = d
dfs.append(temp_df)
all_days_df = pd.concat(dfs, axis=0, ignore_index=True, sort=False)
all_days_df = all_days_df.drop(["Lat", "Long_", "FIPS", "Combined_Key", "Last_Update"], axis=1)
時間と共に感染病はどのように広がったのでしょうか?
all_days_df.groupby("Date")["Confirmed"].sum().plot(title="Confirmed Cases over Time", rot=45)
これをケースのタイプごとにブレークダウンします。
all_days_df.groupby("Date")["Confirmed", "Deaths", "Recovered"].sum().plot(
title="Confirmed, Deaths, Recovered over Time", rot=45
)
特定の場所における増加状況はどうなっているでしょうか?
(
all_days_df[
(all_days_df["Country_Region"] == "US")
& (all_days_df["Province_State"] == "California")
& (all_days_df["Admin2"] == "San Francisco")
]
.groupby("Date")["Confirmed", "Deaths", "Recovered"]
.sum()
.plot(title="Confirmed, Deaths, Recovered over Time", rot=45)
)
このように、pandasデータフレームを活用することで柔軟にデータ分析を行うことができます。
今さら聞けないPython - scikit-learnを用いた機械学習に続きます。