GPUを用いたBlazingSQLによる高速なデータの可視化

CPUで動作する便利な可視化ライブラリに必要なデータをGPUで高速に抽出して可視化してみるぞ

可視化ライブラリはCPUで動作しても良いんですね

GPUで描画できるライブラリもあるぞ

下記のサイトにアクセス

https://github.com/BlazingDB/blazingsql

下記の中から”Data Visualization”を選択するとGoogle Accountを持っていれば使用可能になります。

アクセスに成功すると下記のようにJupyter Notebookが現れます。

BlazingContextを作成します。

from blazingsql import BlazingContext
bc = BlazingContext()

NYC Taxi データ・セットがS3で公開されているのでこちらを使用します。

https://www1.nyc.gov/site/tlc/about/tlc-trip-record-data.page

S3からデータを取得してテーブルを作成します。

bc.s3('blazingsql-colab', bucket_name='blazingsql-colab')

bc.create_table('taxi', 's3://blazingsql-colab/yellow_taxi/taxi_data.parquet')

作成したテーブルからデータを取得して、末尾5行のデータを表示します。

bc.sql('select * from taxi').tail()

取得されたデータはcudf形式なのでpandas形式に直して、描画処理を行います。

cudfについては下記をご覧ください。

bc.sql('SELECT * FROM taxi').to_pandas().plot(kind='scatter', x='passenger_count', y='tip_amount')

各時間ごとの合計乗車数を表示します。SQLで必要な処理を定義してGPU上で処理できるため、高速に処理ができます。

必要なデータを取得した後にpandas形式に修正して描画処理します。

riders_by_hour = '''
                 select
                     sum(passenger_count) as sum_riders,
                     hour(cast(tpep_dropoff_datetime || '.0' as TIMESTAMP)) as hour_of_the_day
                 from
                     taxi
                 group by
                     hour(cast(tpep_dropoff_datetime || '.0' as TIMESTAMP))
                 order by
                     hour(cast(tpep_dropoff_datetime || '.0' as TIMESTAMP))
                     '''
bc.sql(riders_by_hour).to_pandas().plot(kind='bar', x='hour_of_the_day', y='sum_riders', title='Sum Riders by Hour', figsize=(12, 6))

各時間ごとの平均乗車数と平均Tip金額を表示します。SQLで必要な処理を定義してGPU上で処理できるため、高速に処理ができます。

必要なデータを取得した後にpandas形式に修正して描画処理します。

xticks = [n for n in range(24)]

avg_riders_by_hour = '''
                     select
                         avg(passenger_count) as avg_passenger_count,
                         hour(dropoff_ts) as hour_of_the_day
                     from (
                         select
                             passenger_count, 
                             cast(tpep_dropoff_datetime || '.0' as TIMESTAMP) dropoff_ts
                         from
                             taxi
                             )
                     group by
                         hour(dropoff_ts)
                     order by
                         hour(dropoff_ts)
                         '''
bc.sql(avg_riders_by_hour).to_pandas().plot(kind='line', x='hour_of_the_day', y='avg_passenger_count', title='Avg. # Riders per Trip by Hour', xticks=xticks, figsize=(12, 6))

avg_tip_by_hour = '''
                  select
                      avg(tip_amount) as avg_tip_amount,
                      hour(dropoff_ts) as hour_of_the_day
                  from (
                      select
                          tip_amount, 
                          cast(tpep_dropoff_datetime || '.0' as TIMESTAMP) dropoff_ts
                      from
                          taxi
                          )
                  group by
                      hour(dropoff_ts)
                  order by
                      hour(dropoff_ts)
                      '''
bc.sql(avg_tip_by_hour).to_pandas().plot(kind='line', x='hour_of_the_day', y='avg_tip_amount', title='Avg. Tip ($) per Trip by Hour', xticks=xticks, figsize=(12, 6))

DataShaderを使用

ラスターデータ化して描画処理を高速化します。下記のような気温や降水量、標高データなどを表すのに役立ちます。

raster_image3

画像は下記サイトを参照:

https://www.esrij.com/gis-guide/gis-datamodel/raster-data/

DataShaderはこのラスターデータ作成を簡単にできます。cudf.DataFrameを扱えるのGPU上で描画処理ができます。

https://github.com/holoviz/datashader

必要なライブラリをインポートします。

from datashader import Canvas, transfer_functions as tf
from colorcet import fire

下記のコードで位置ごとの下車数を可視化できます。どの位置がどれだけ下車しているか把握できます。AM6:00からPM4:00までの時間の各位置(x,y)での下車数を可視化しています。

query = '''
        select 
            dropoff_x, dropoff_y 
        from 
            taxi 
            where  
                hour(cast(tpep_pickup_datetime || '.0' as TIMESTAMP)) BETWEEN 6 AND 15
                '''
nyc = Canvas().points(bc.sql(query), 'dropoff_x', 'dropoff_y')
tf.set_background(tf.shade(nyc, cmap=fire), "black")

下記のコードはPM6:00からAM4:00までの時間の各位置(x,y)での下車数を可視化しています。

query = '''
        select 
            dropoff_x, dropoff_y 
        from 
            taxi 
            where  
                hour(cast(tpep_pickup_datetime || '.0' as TIMESTAMP)) BETWEEN 18 AND 23
                OR hour(cast(tpep_pickup_datetime || '.0' as TIMESTAMP)) BETWEEN 0 AND 3
                '''
nyc = Canvas().points(bc.sql(query), 'dropoff_x', 'dropoff_y')
tf.set_background(tf.shade(nyc, cmap=fire), "black")

HoloViews

HoloViewsはオープンソースの可視化ライブラリであり、少ないコードで可視化できるライブラリです。

https://github.com/holoviz/holoviews

下記のコードで乗客数とTips金額の関係性を可視化します。

from holoviews import extension, opts
from holoviews import Scatter, Dimension
import holoviews.operation.datashader as hd

extension('bokeh')
opts.defaults(opts.Scatter(height=425, width=425), opts.RGB(height=425, width=425))

cmap = [(49,130,189), (107,174,214), (123,142,216), (226,103,152), (255,0,104), (50,50,50)]

s = Scatter(bc.sql('select passenger_count, tip_amount from taxi').to_pandas(), 'passenger_count', 'tip_amount')

# 0-6 passengers, $0-$100 tip
ranged = s.redim.range(passenger_count=(-0.5, 6.5), tip_amount=(0, 100))
shaded = hd.spread(hd.datashade(ranged, x_sampling=0.25, cmap=cmap))

riders_v_tip = shaded.redim.label(passenger_count="Passenger Count", tip_amount="Tip ($)")
riders_v_tip

下記のコードで運賃とTipsの関係性を可視化します。

s = Scatter(bc.sql('select fare_amount, tip_amount from taxi').to_pandas(), 'fare_amount', 'tip_amount')

# 0-30 miles, $0-$60 tip
ranged = s.redim.range(fare_amount=(0, 100), tip_amount=(0, 100))
shaded = hd.spread(hd.datashade(ranged, cmap=cmap))

fare_v_tip = shaded.redim.label(fare_amount="Fare Amount ($)", tip_amount="Tip ($)")
fare_v_tip

cuxfilter

GPU上で一般的な描画処理ができるライブラリになります。

https://github.com/rapidsai/cuxfilter

Blazing SQLでデータを取得して、cuxfilterでGPU上でデータを描画するためのcuxfilter.DataFrameを取得します。

import cuxfilter
cux_df = cuxfilter.DataFrame.from_dataframe(bc.sql('SELECT passenger_count, tip_amount, dropoff_x, dropoff_y FROM taxi'))

作成したcuxfilter.DataFrameから描画処理用のchartsに変換します。

chart_0 = cuxfilter.charts.datashader.scatter(x='dropoff_x', y='dropoff_y')

chart_1 = cuxfilter.charts.bokeh.bar('passenger_count', add_interaction=False)

chart_2 = cuxfilter.charts.datashader.heatmap(x='passenger_count', y='tip_amount', x_range=[-0.5, 6.5], y_range=[0, 100], 
                                              color_palette=cmap, title='Passenger Count vs Tip Amount ($)')

chart_0: 各位置の降車数の可視化します。

chart_0.view()

chart_1: 乗客数の合計を可視化します。

chart_1.view()

chart_2:乗客数とTipの関係を可視化します。

chart_2.view()

複数GPUを用いた可視化

Localで動作するBlazing SQLのGPUクラスターを作成します。

from dask_cuda import LocalCUDACluster
from dask.distributed import Client

cluster = LocalCUDACluster()
client = Client(cluster)

bc = BlazingContext(dask_client=client, network_interface='lo')

先程と同様にs3からデータを取得してテーブルを作成します。

bc.s3('blazingsql-colab', bucket_name='blazingsql-colab')

bc.create_table('distributed_taxi', 's3://blazingsql-colab/yellow_taxi/taxi_data.parquet')

PM6:00からAM4:00までの各位置(x, y)の降車数を可視化します。

query = '''
        select 
            dropoff_x, dropoff_y 
        from 
            distributed_taxi 
            where  
                hour(cast(tpep_pickup_datetime || '.0' as TIMESTAMP)) BETWEEN 18 AND 23
                OR hour(cast(tpep_pickup_datetime || '.0' as TIMESTAMP)) BETWEEN 0 AND 3
                '''

nyc = Canvas().points(bc.sql(query), 'dropoff_x', 'dropoff_y')

tf.set_background(tf.shade(nyc, cmap=fire), "black")

GPUで必要なデータを高速に抽出->よく使用される描画ライブラリにつなげるまで試してみたぞ

結構、簡単にできましたね

Close Bitnami banner
Bitnami