データのGitHub"delika"を使って運動量と天気について調べてみた


# はじめに

ますます運動する機会が減ってきておりお腹周りも気になってきてはいるのですが、筆者はついつい天気が悪いからと言って運動する機会から目を背けがちです。では本当に運動量と天気のデータに関連はないのか？天気が悪いと動く気しないよね？っということで、運動量のデータと天気のデータに何らかの関連が見られないか調べてみたいと思います。
やることは iPhone からヘルスケアデータを取り出す、天気データを集める、2つのデータをぶつけて相関とってみる、です。（何気なく採集されている iPhone ならびに Apple Watch のデータを使って何かしたい。エンジニアなら誰しもそう思うじゃないですか。）
今回はデータの保持と簡単な分析をするために delika というプラットフォームを使います。


# delika ってなに？

delika ( https://delika.io )は一言でいうと「データのGitHub」です。データ分析する人たちのために使えそうなデータを世界中のみんなで共有できるようにするプラットフォームで、delika 上に共有されたデータに対してSQLクエリを書くことがで簡単な分析を行うことも出来ます。
現在対応しているのはCSVファイル形式のデータです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318342/242abf60-9605-8baa-cf87-8dbe17351eb5.png)

# 分析に使うデータの用意
## iOS のヘルスケアデータを取り出す

さっそく delika にアップするデータを用意します。iOSのヘルスケアデータは標準でXMLを出力できるようですが、XMLってどうなのよ、今どき。処理するの面倒過ぎるでしょ、と。
今回は「QS Access」( https://apps.apple.com/jp/app/qs-access/id920297614 ) を使います。

「QS Access」は無料で公開されている iOSアプリで適切なデータアクセス許可を設定してあげるだけで、お望みのヘルスケアデータをCSVファイルに出力し、各種アプリやメールで共有できます。（たまに落ちるけど）

やり方はとっても簡単。起動すると出力できる値一覧がずらっと表示されるので、必要な値を選んで「Create Table」するだけ。今回はそんなにたくさんの値を見てもしょうがないので、わかりやすそうな以下の2つに絞りました。

- StepCount
- ActiveCalories(kcal)

出来上がったCSVファイルはこんな感じです。

```
Start,Finish,Active Calories (kcal),Steps (count)
24-Sep-2014 00:00,25-Sep-2014 00:00,0.0,2903.0
25-Sep-2014 00:00,26-Sep-2014 00:00,0.0,5467.0
26-Sep-2014 00:00,27-Sep-2014 00:00,0.0,6000.0
27-Sep-2014 00:00,28-Sep-2014 00:00,0.0,2952.0
28-Sep-2014 00:00,29-Sep-2014 00:00,0.0,2534.0
29-Sep-2014 00:00,30-Sep-2014 00:00,0.0,4019.0
30-Sep-2014 00:00,01-Oct-2014 00:00,0.0,4726.0
01-Oct-2014 00:00,02-Oct-2014 00:00,0.0,5473.0
～略～
```


## お天気データを取ってくる

次は天気のデータを取ってきます。
天気データといったら気象庁さんですので、気象庁のホームページ（ https://www.data.jma.go.jp/gmd/risk/obsdl/ ）からダウンロードします。ここでは前日分までのデータをダウンロードすることができます。

出力方法は以下の通りです。
1. 「地点を選ぶ」でジャスト自分の住んでる位置に観測点はありませんが近しい駅を指定します。
2. 「項目を選ぶ」で出力したい値を選択します
3. 「期間を選ぶ」で出力したいデータの期間を選択します
4. 「表示オプション」で、「利用上注意が必要なデータの扱い」や「観測環境などの変化の前後で、値が不均質となったデータの扱い」などを指定します
5. 「画面に表示」で出力したデータをプレビューします
6. 問題なければ、「CSVファイルをダウンロード」でファイルをダウンロードします

表示オプションで指定する値はマジメに分析する際は考慮しなければいけませんが、今回は簡単にするために以下のように設定して出力しました。

- 利用上注意が必要なデータの扱い：「値を表示（格納）しない」
- 観測環境などの変化の前後で、値が不均質となったデータの扱い：「観測環境などの変化前の値を表示(格納)しない。」
- ダウンロードCSVファイルのデータ仕様：「データ表示画面と同様に、数値以外の記号を含む」

出来上がったCSVファイルはこんな感じです。

```
ダウンロードした時刻：2020/12/14 17:30:33

,横浜,横浜,横浜,横浜,横浜,横浜,横浜
,平均気温(℃),最高気温(℃),最低気温(℃),降水量の合計(mm),日照時間(時間),平均現地気圧(hPa),平均湿度(％)
,,,,,,,
2017年1月1日,8.5,13.6,4.2,--,9.5,1017.6,56
2017年1月2日,8.9,13.3,5.6,--,6.7,1011.9,65
2017年1月3日,9.2,14.1,4.5,--,9.0,1009.3,51
2017年1月4日,9.3,14.5,5.3,--,9.2,1008.8,47
2017年1月5日,7.3,10.7,4.2,--,9.5,1012.6,38
2017年1月6日,5.5,8.8,2.7,--,9.4,1018.7,44
2017年1月7日,5.2,9.2,1.2,--,9.1,1016.4,54
～略～
```

# データをちょっと加工する
自分のヘルスケアデータとお天気データを取得できましたが、このままでは分析しづらいのでややデータを加工します。データあるあるですが、データの提供者それぞれのフォーマットでデータが公開されているので、あるキーでデータをぶつけようとしてもその前に加工が必要になります。今回は日付でヘルスケアデータと天気データをぶつけたいですが、2つのファイルでフォーマットが異なるので揃えてあげます。

## ヘルスケアデータの加工
自分のヘルスケアデータの日時フォーマットが delikaで受け付ける標準と異なるので修正します。今回は以下の pandas を python スクリプトで変換しました。

```python
import pandas as pd
df = pd.read_csv('HealthData.csv')
df['Start'] = df['Start'].dt.strftime('%Y-%m-%d 00:00:00')
df['Finish'] = df['Finish'].dt.strftime('%Y-%m-%d 00:00:00')
df.to_csv('HealthData_output.csv')
```

## お天気データの加工
もう一つのお天気データも同様に日時フォーマットの修正します。
が、その前に不要なヘッダを削除して読みやすくしておきます。

```
observation_date,average_temperature,max_temperature,min_temperature,precipitation,daylight,pressure,humidity
2017年1月1日,8.5,13.6,4.2,--,9.5,1017.6,56
2017年1月2日,8.9,13.3,5.6,--,6.7,1011.9,65
～略～
```

yyyy年MM月dd日のフォーマットだと処理ができないので日時フォーマットの入れ替えを行います。

```python
import pandas as pd
df = pd.read_csv('Whether.csv')
df['observation_date'] = pd.to_datetime(df2['observation_date'], format='%Y年%m月%d日').dt.strftime('%Y-%m-%d 00:00:00')
df.to_csv('Whether_output.csv')
```

出来上がったファイルはこんな感じです。

```
observation_date,average_temperature,max_temperature,min_temperature,precipitation,daylight,pressure,humidity
2017-01-01 00:00:00,8.5,13.6,4.2,--,9.5,1017.6,56
2017-01-02 00:00:00,8.9,13.3,5.6,--,6.7,1011.9,65
2017-01-03 00:00:00,9.2,14.1,4.5,--,9.0,1009.3,51
～略～
```

# delika にデータをアップロード

準備が整いましたので delika にアップします。
データのアップロードにはアカウントが必要ですので、https://delika.io にアクセスしてユーザアカウントを作っておきます。

delika では DataSet と呼ばれる単位でデータを管理しておりGitHubでいうところのレポジトリに近い考え方です。DataSet の中にはデータファイルを表す DataFile を複数持たせることができます。

早速、ヘッダの「＋」メニューの「New Dataset」から Dataest を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318342/1a24f265-c5c8-bcce-d700-a0801607d120.png)

このとき共有するデータのライセンスを指定することができます。特に商用で使わってもらっても構わない（そんな用途ないと思うけど）がクレジットは示してほしいので「CC BY 4.0」にしておきました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318342/f594c34c-8c90-4379-bdf0-fa267ec8f88e.png)

## ヘルスケアデータのアップロード
続いてファイルのアップロードです。

作成したデータセットの画面で「Upload Files」のタブを選択し、「Choose files...」でアップロードしたいファイルを選択します。
※以下の画面は既にファイルをアップロード後のスクリーンショットです。まっさらな状態だと～.csv の2つがないはず。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318342/1530d596-894c-574b-9648-187d7252453a.png)



登録されたヘルスケアデータがこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318342/f0edb079-23c8-ffd1-187a-1fb342d9a88a.png)

時刻形式や数値形式はアップロード時に自動で判別して取り込まれます。
「Schema」タブを除けば、どんなデータ形式として取り込まれたのか確認できます。さらに型の変更も。

## 天気データのアップロード

続いて天気データのアップロードです。
ヘルスケアデータのアップロードと同様ですが、このデータにはいわゆる NULL な値が「--」として記録されてます。このまま取り込んでしまうとせっかくの数値データが文字列データになってしまうので、アップロード時のオプションとして「Null string」に「--」を指定してあげます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318342/6cbcea99-990f-d014-53d5-64dc0496195b.png)

以下のように、NULL な値が薄く表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318342/f28c21f6-3e56-b212-e622-d2cbdbb29523.png)

# クエリを発行してデータを抽出

※この記事は2020年に書いたもので当時はcorr関数がサポートされていましたが、現在はサポートされていません。

delika では登録されたデータに対してSQLでクエリを発行しデータの加工・抽出・分析を行うことができます。
SQLはこんな感じにテーブル名の代わりに [アカウント名/DataSet名/DataFile名] の形式で指定してあげます。そのほかの文法は普通のSQLと同じです。
今回のヘルスケアデータは私が AppleWatch を付けてない日がアクティブカロリーが取得出来ていないのでデータとして外すようにし、アクティブカロリーの平均値、最小値、最大値、そして、歩数はアクティブカロリーと関係しているのかを表す相関係数をとってみます。

```sql
SELECT 
  avg(t.active_calories__kcal_) as average,
  min(t.active_calories__kcal_) as min,
  max(t.active_calories__kcal_) as max,
  corr(t.active_calories__kcal_,t.steps__count_) as corr
FROM [akashikei/HealthData/HealthData_output.csv] t 
WHERE t.active_calories__kcal_ > 0
```

右上の「＋」メニューから「New Query」を選択して、実行したいクエリを書いて「Run Query」ボタンで実行です。
実行結果はこんな感じです。
当たり前ですが歩数とアクティブカロリーには強い相関がありますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318342/24a6df76-b700-e9cf-dd63-20577501a67b.png)

では、せっかくSQLを書けるのでお天気がおじさんのカロリー消費に影響を与えてるのか否やを調べてみましょう。
2つのテーブルもとにファイルを結合して相関をとってみます。

```sql
SELECT 
  corr(t.active_calories__kcal_,t2.average_temperature) as corr_average_temp,--平均気温
  corr(t.active_calories__kcal_,t2.min_temperature) as corr_min_temp, --最低気温
  corr(t.active_calories__kcal_,t2.max_temperature) as corr_max_temp, --最高気温
  corr(t.active_calories__kcal_,t2.precipitation) as corr_precipitation, --降水量
  corr(t.active_calories__kcal_,t2.daylight) as corr_daylight,  --日照時間
  corr(t.active_calories__kcal_,t2.pressure) as corr_pressure,  --気圧
  corr(t.active_calories__kcal_,t2.humidity) as corr_humidity --湿度
FROM [akashikei/HealthData/HealthData_output.csv] t 
INNER JOIN [akashikei/HealthData/Wheather_output.csv] t2 ON t.Start = t2.observation_date
WHERE t.active_calories__kcal_ > 0
```

さて気になる結果は、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318342/72ed68da-a9da-7f5e-9af6-4b9451af08eb.png)

んー微妙。ほぼ相関ないと思えますが、平均気温と気圧が他に比べれば非常に弱い相関があるかな、といったところです。気圧に関しては、確かに低気圧になったときに片頭痛で動けなくなることがあるのでその影響も若干あるのかな、と思えてきました。

# おわりに

さて、オチがなんとも中途半端な結果になってしまったですが、いかがでしたでしょうか。
delika を使えば手元にあるデータやどこかから落としてきたデータを簡単に結合して遊んでみることができます。もちろん手元だけだったらPandasやR等を使って分析すればよいですが、大きな違いは自分が持ってるデータだけでなく、delika 上で共有されているデータセットであれば自由に使えることです。自分以外の誰かのデータを使って新たな分析を行うことが出来ます。
こういったプラットフォームを世の中の人が使っていけば、データを使った新しい発見や思いもつかなかった使い方が見えてきたりもするのではないでしょうか。
今回使ったデータも以下の URL で共有しておきましたので、我こそはという方、筆者の運動が疎かになる理由をぜひ探ってみてください。
https://delika.io/akashikei/HealthData

ちなみに、delika は Python ( https://docs.delika.io/python/ ) や R ( https://docs.delika.io/R/ ) から簡単に使える API クライアントも持っています。実はデータの加工からアップロードまではこれらのクライアントを活用したほうが圧倒的に便利です。こちらはまたの機会に紹介したいと思います。