統計分析お題：kaggleのUFO Sightingデータセットを分析してみる。

1949年から2013年までの、UFOを発見したという情報をまとめたデータセットがあるようです（有名のようです）。

データセットはこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517776/e3fbf8d1-0011-3c94-e0bf-559c41cc76c1.png)

- 基本的に発見日時
- 発見した町
- 州
- 国名
- UFOの形
- （おそらく）目撃した時間[sec]
- （おそらく）目的した時間[hours or min]
- 目撃談（コメント）
- 情報提供日
- 発見した場所の緯度
- 発見した場所の経度

なので、このデータセットの国名の列を使って、「国別UFO発見件数の年間推移グラフ」を作ってみたいと思います。

試すにあたり、以下の分析事例を参考にしました。

https://www.kaggle.com/code/hebakullab/ufo-sightings

# やってみる
## データセットの準備

データセットはここにあります。(Kaggleのアカウントを作成する必要があります。無料です。）

https://www.kaggle.com/datasets/NUFORC/ufo-sightings/

データセットは以前セットアップしたときに用意したdataフォルダに配置。

https://qiita.com/syoney/items/458c495ca7636bc29ca7

## データ読み込みおよびクリーンアップ
まずデータを読み込み。

```ufo_sighting.py
import pandas as pd
#CSVファイル読み込み

df= pd.read_csv('../data/ufo_sighting/scrubbed.csv')

print(df_area.head())
```

Warningが出ますがそのまま進みます。

datetime列の時刻において、深夜０時の表記が24:00になっているため、今後時間データとして利用しやすくするため、これを00:00に変換。
また、Country列には空白セルも含まれるため、そこには「Unknown」という文字列を挿入。

```ufo_sighting.py
df['datetime'] = df['datetime'].str.replace('24:00', '00:00')
df['country'].fillna('Unknown')
print(df.info())
```

出力結果は以下。

```
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 80332 entries, 0 to 80331
Data columns (total 11 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   datetime              80332 non-null  object 
 1   city                  80332 non-null  object 
 2   state                 74535 non-null  object 
 3   country               70662 non-null  object 
 4   shape                 78400 non-null  object 
 5   duration (seconds)    80332 non-null  object 
 6   duration (hours/min)  80332 non-null  object 
 7   comments              80317 non-null  object 
 8   date posted           80332 non-null  object 
 9   latitude              80332 non-null  object 
 10  longitude             80332 non-null  float64
dtypes: float64(1), object(10)
memory usage: 6.7+ MB
None
```


datetime列は今のところobjectタイプのため、これをdatetime型に変換して、さらにインデックスに指定。

```ufo_sighting.py
df['datetime'] = pd.to_datetime(df['datetime'])
df = df.set_index('datetime')
print(df.info())
```

出力結果は以下。

```
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 80332 entries, 1949-10-10 20:30:00 to 2013-09-09 23:00:00
Data columns (total 11 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   city                  80332 non-null  object 
 ＜略＞
```

これでdatetime列を時系列として扱えるようになりました。

## 全体でみるUFO目撃数の年毎の推移

ここでとりあえず、国別ではなく、全体で見た年間のUFO目撃件数を出してみる。


```ufo_sighting.py
import matplotlib 
import matplotlib.pyplot as plt

# 日本語フォントを指定（文字化け対策）。
matplotlib.rcParams['font.family'] = 'MS Gothic'

# データセットにcount列を追加し、すべてのセルに1を代入。（この次の集計用に使う）
df['count'] = 1

# count列を、年毎にグループ化し、それにグラフのタイトルと汎用を付けて折れ線グラフとしてプロット。
df['count'].groupby(pd.Grouper(freq='A')).sum().plot(label="年毎のUFO目撃件数").legend()
```
すると以下のグラフを得られる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517776/f7348608-0299-034c-ba8d-ac22250e077d.png)

1970年ごろにじわじわと報告が上がり始め、1995年から急激に目撃件数が増えている模様。

# 国別のUFO目撃件数年毎推移

count列を追加し、年毎にその値(すなわち1）を合計することで、年毎のレコード件数合計を出す作戦。

```ufo_sighting.py

df_temp = pd.DataFrame()

# データセットのCountry列から、重複排除して国名を取得
for column_name,item in df['country'].drop_duplicates().reset_index().iterrows():
    print(item[1])
    # 取得した国名のみ該当するデータフレームを取得
    df_country = df[df['country'] == item[1]]

    # 取得した国名に絞って、先と同様年間件数を集計し、df_tempに国名をインデックスとして格納する。
    df_temp[item[1]] = df_country['count'].groupby([pd.Grouper(freq='A')]).sum()

# この時点で国別、年毎のレコード合計件数が揃ったことになる。そのままplotしてみる。
df_temp.plot(title="国別UFO発見件数の年間推移").legend()

```

すると以下のグラフが得られる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517776/9a9af8e9-8f43-eae9-6624-a7fc8c76b9f4.png)


us(米国）のUFO発見件数ががダントツ。1995年からの急激な伸びも、米国のデータが牽引していた模様。このデータと出自はNUFORC（National UFO Reporting Center）という組織らしいのですが、組織のURLにアクセスしてみたけど、タイムアウトでアクセスできませんでした。（データを本格的に収集したのが1995年から、、とか理由を探ってみたかったです）

あとおまけで、国別のUFO発見合計件数も出してみました。

```ufo_sighting.py
df[['country']].groupby('country').value_counts().plot.bar(title="国別UFO発見件数").grid()
```

年毎などの単位ではなく、国ごとに全件集計ということであれば、value_counts()が便利な模様。以下のグラフが得られる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3517776/53d8faf8-c85b-61c4-edf3-2f81e4362582.png)

## 終わりに

このデータセットにはほかにも緯度経度や、発見したUFOに関する概要、UFOの形状などもあるので、また別の切り口でも分析を続けてみたいです。（ここまでの分析プロセスもやっぱりエクセルのほうが絶対速いので、ジオデータから地図上にプロットなどができるとこういう分析ツールの優位性を実感できると思いました）