BigQuery DataFramesを使ってみる

2023.09.19

はじめに

データアナリティクス事業本部のkobayashiです。

BigQueryのエンジンを利用してPandas互換のDataframeやscikit-learnライクな機械学習ライブラリを扱えるBigQuery DataFramesを使ってみたのでまとめます。

BigQuery DataFramesとは

BigQuery DataFramesは、DataFrameとしてはpandas互換のPythonic DataFrameのbigframes.pandasモジュールとscikit-learnライクのbigframes.mlモジュールを扱うことができ、それらの機能をBigQueryエンジンで実行することができます。

詳しくは以下をご確認ください。

BigQuery DataFramesを使ってみる

では早速BigQuery DataFramesを使ってみたいと思います。試すこととしてはまずはpandas互換のPythonic DataFrameのbigframes.pandasモジュールで一般的にPandasで行うデータ分析を行ってみます。

scikit-learnライクのbigframes.mlモジュールに関しては別エントリでまとめたいと思います。

環境

  • Python: 3.11.4
  • bigframes: 0.3.0

インストール

インストールはいつも通りpipで簡単に済ませます。

$ pip install bigframes

BigQuery DataFramesを使ってみる

BigQuery DataFramesの準備が整ったので早速試してみたいと思います。

扱うデータは以下のような天候データを扱います。

SELECT * FROM {project_id}.data_set_test.jp_weather;
date month city w_type temperature precipitation sunlight cloudage
2021-11-13 11 京都 10.500000000 0.000000000 7.600000000 null
2021-03-03 3 京都 5.900000000 0.000000000 6.600000000 null
2021-11-14 11 京都 12.100000000 0.000000000 3.600000000 null
2021-03-04 3 京都 10.000000000 0.000000000 6.100000000 null
2021-11-15 11 京都 12.800000000 0.000000000 7.900000000 null
2021-11-16 11 京都 13.500000000 0.000000000 7.600000000 null
2021-11-17 11 京都 12.800000000 0.000000000 8.000000000 null
2021-03-07 3 京都 8.200000000 0.000000000 6.100000000 null

このデータをBigQuery DataFramesで扱います。内容としては{project_id}.data_set_test.jp_weatherのデータを使ってPandasで行う一般的な分析操作を行います。コードは以下になります。

import os
import bigframes.pandas as bpd

bpd.options.bigquery.project = os.environ.get("GOOGLE_PROJECT_ID")
bpd.options.bigquery.location = "asia-northeast1"

df1 = bpd.read_gbq("{project_id}.data_set_test.jp_weather")
# df1 = bpd.read_gbq("SELECT * FROM {project_id}.data_set_test.jp_weather")

# データの要約
## 最初の5行を取得
print(df1.head())
## 最後の5行を取得
print(df1.tail())
## 行数・列数を取得
print(df1.shape)
## 列名の取得
print(df1.columns)
## 列のデータ型を取得
print(df1.dtypes)
## 要約統計量
print(df1.describe())

# データの加工
## 列の抽出
print(df1["date"])
print(df1[["date", "temperature"]])
## cityごとのデータ数
print(df1["city"].value_counts())

# データの集計
print(df1.groupby("city")["temperature"].mean().sort_values(ascending=False))

使い方として主な箇所は1行目から7行目になります。

  • 2行目: import bigframes.pandas as bpdbigframes.pandasモジュールをインポートする
  • 4行目: bpd.options.bigquery.projectにGoogleCloudのプロジェクトIDを設定する
  • 5行目: bpd.options.bigquery.locationでデータセットのロケーションを設定する。設定しない場合はデフォルトのUSロケーションが使われる。
  • 7行目: bpd.read_gbq()でデータを読み込む。引数には上記のコードの様にテーブルIDを指定する方法とSQLを指定する方法が可能。

9行明以降はPandasで扱える処理をbigframes.pandasモジュールでも使ってみます。結果は以下のように通常のpandasと同様の結果が返ってきますのでPandasでのデータ分析を普段から行っているなら特に違和感なく使えるかと思います。

# データの要約
## 最初の5行を取得
        date  month city  ... precipitation     sunlight cloudage
0 2021-11-13     11   京都  ...          0E-9  7.600000000     None
1 2021-03-03      3   京都  ...          0E-9  6.600000000     None
2 2021-11-14     11   京都  ...          0E-9  3.600000000     None
3 2021-03-04      3   京都  ...          0E-9  6.100000000     None
4 2021-11-15     11   京都  ...          0E-9  7.900000000     None

[5 rows x 8 columns]

## 最後の5行を取得
           date  month city  ... precipitation      sunlight     cloudage
3655 2021-04-14      4  名古屋  ...   2.500000000   6.000000000  5.800000000
3656 2021-04-22      4  名古屋  ...          0E-9  11.500000000  5.800000000
3657 2022-01-16      1  名古屋  ...          0E-9   9.000000000  5.800000000
3658 2021-07-30      7  名古屋  ...   2.000000000   8.200000000  5.800000000
3659 2021-11-10     11  名古屋  ...          0E-9   4.200000000  5.800000000

[5 rows x 8 columns]

## 行数・列数を取得
(3660, 8)

## 列名の取得
Index(['date', 'month', 'city', 'w_type', 'temperature', 'precipitation',
       'sunlight', 'cloudage'],
      dtype='object')

## 列のデータ型を取得
date             date32[day][pyarrow]
month                           Int64
city                  string[pyarrow]
w_type                string[pyarrow]
temperature                    object
precipitation                  object
sunlight                       object
cloudage                       object
dtype: object

## 要約統計量
                      date     month
count                 3660    3660.0
mean   2021-08-21 12:00:00  6.513661
min    2021-02-20 00:00:00       1.0
25%    2021-05-22 00:00:00       4.0
50%    2021-08-21 12:00:00       7.0
75%    2021-11-21 00:00:00      10.0
max    2022-02-20 00:00:00      12.0
std                    NaN  3.451705

## 列の抽出
0      2021-11-13
1      2021-03-03
2      2021-11-14
3      2021-03-04
4      2021-11-15
          ...    
3655   2021-04-14
3656   2021-04-22
3657   2022-01-16
3658   2021-07-30
3659   2021-11-10
Name: date, Length: 3660, dtype: datetime64[s]

## 列の抽出
           date   temperature
0    2021-11-13  10.500000000
1    2021-03-03   5.900000000
2    2021-11-14  12.100000000
3    2021-03-04  10.000000000
4    2021-11-15  12.800000000
...         ...           ...
3655 2021-04-14  16.100000000
3656 2021-04-22  19.900000000
3657 2022-01-16   4.300000000
3658 2021-07-30  29.100000000
3659 2021-11-10  13.300000000

[3660 rows x 2 columns]

## cityごとのデータ数
city
京都     366
仙台     366
大阪     366
札幌     366
東京     366
横浜     366
福岡     366
那覇     366
長野     366
名古屋    366
Name: count, dtype: int64[pyarrow]
           date  month city  ... precipitation      sunlight     cloudage
0    2021-11-13     11   京都  ...          0E-9   7.600000000         None
1    2021-03-03      3   京都  ...          0E-9   6.600000000         None
2    2021-11-14     11   京都  ...          0E-9   3.600000000         None
3    2021-03-04      3   京都  ...          0E-9   6.100000000         None
4    2021-11-15     11   京都  ...          0E-9   7.900000000         None
...         ...    ...  ...  ...           ...           ...          ...
3655 2021-04-14      4  名古屋  ...   2.500000000   6.000000000  5.800000000
3656 2021-04-22      4  名古屋  ...          0E-9  11.500000000  5.800000000
3657 2022-01-16      1  名古屋  ...          0E-9   9.000000000  5.800000000
3658 2021-07-30      7  名古屋  ...   2.000000000   8.200000000  5.800000000
3659 2021-11-10     11  名古屋  ...          0E-9   4.200000000  5.800000000

[3660 rows x 8 columns]

# データの集計
city
那覇     23.688798
福岡     18.062022
大阪     17.378142
横浜     16.779235
京都     16.674044
名古屋    16.671038
東京     16.418579
仙台     13.662295
長野     12.698361
札幌      10.26694
Name: temperature, dtype: object

データのメモリ展開

上記のコードですが、BigQuery DataFramesの特性上、BigQuery サービス上でデータと処理を保持をされています。したがってdf1を使って操作を行うたびにBigQueryのセッションからデータを取得しています。代わりに

df1 = bpd.read_gbq("{project_id}.data_set_test.jp_weather").to_pandas()

のようにするとこの時点でデータをメモリ上に読み込んでから後続の処理をするようになります。この場合はdf1の操作のたびにBigQueryのAPIを呼び出すことはしなくなしますが、実行マシーンのメモリを圧迫するのでケースバイケースでの使い分けが必要になります。

まとめ

BigQueryのエンジンを利用してPandas互換のDataframeを扱えるBigQuery DataFramesを使ってみました。bigframes.pandas.read_gbq()でBigQuery上のデータを読み込んでしまえば以降はPandasと同じ関数を使って分析を行うことができ非常に便利です。 次回、scikit-learnライクのbigframes.mlモジュールを扱ってみたいと思います。

最後まで読んで頂いてありがとうございました。