
詳解 確率ロボティクス Pythonによる基礎アルゴリズムの実装 (KS理工学専門書)
- 作者:上田隆一
- 発売日: 2019/12/20
- メディア: Kindle版
目次
はじめに
上記の書籍を参考に、Juliaコードにより
ロボティクスの技術を学べるプロジェクトを
前回記事からスタートしました。
今回からは書籍の第2章にあたる、確率と
統計の基礎について紹介していくとして、
まずはプロジェクト内で扱うセンサデータの
概要把握について解説します。
GitHubリポジトリ
本記事で紹介するJuliaコードは全てこちらの
リポジトリにて公開しています。
センサデータを分析することの意義
自律移動するロボットには様々なセンサが
搭載されます。そのセンサ群から得られる
データというのは決して綺麗なものではなく、
ノイズや取付による偏差やばらつきを持つ
ことが多いです。
こういったデータを使ってロボットを制御
するに、まずはデータをじっくり分析して、
それらが持つ特徴を把握しておくことが
必要になります。
センサのサンプルデータ
本プロジェクトでは、赤外線LEDを照射して
物体までの距離を測る光センサと、レーザ
光線をスキャンして外界の形状を計測する
LiDARの2種類を外界認識センサとして用います。
これらを壁に向けて、そこまでの2次元距離を
計測した際のデータをサンプルデータとして
扱います。
データは全てリポジトリのdataフォルダにあり、
スペース区切りのテキスト形式で保存されています。
これらは左から順にデータを取得した日付、
時刻、光センサによる計測距離、LiDARに
よる計測距離となっています。
データの概要把握
データを細かく分析する前に、大体どのような
特徴を持ったデータなのかをざっくり把握して
みることにします。
詳細な分析というものはどうしても時間が
必要なので、急ぎで何かしらのアウトプットを
出したい場合は、とりあえず手っ取り早く
全体像を掴んでみるというのも大事です。
必要なJuliaパッケージの読み込み
まずは、上記のテキストファイルから
データを読み込んで、各列に名前を
割り当てたデータフレームに変換します。
そのために下記二つのパッケージを
読み込みます。
using DataFrames, CSV
一つ目はデータフレーム作成用、二つ目は
CSV形式データを扱うために使用します。
データファイルのパスの指定
続いてデータのファイルを読み込みます。
そのために下記のようにファイルのパスを
指定します。
data_path = joinpath(split(@__FILE__, "src")[1], "data/sensor_data_200.txt")
単純に相対パスで与えることもできますが、
こういう書き方をすることで絶対パスで
指定することが出来ます。
わざわざ絶対パスで指定する理由として、
サンプルコードを実行するのにsrc以下の
ディレクトリまで移動する必要がなくなると
いうのがあります。
@__FILE__
マクロで実行されたファイルの
絶対パスを取得し、split()関数でsrc
を境に
分割します。
ここで分割されたパスはsrc
より手前部分と
後部分の2つが要素となる配列になるので、
前者を[1]で指定し、dataフォルダ以下の相対
パスとjoinpath関数で連結します。
ちなみにJuliaでは、Pythonと違い配列の要素に
アクセスするためのインデックスが1始まりと
なるので注意しましょう。
ファイルの読み込みとデータフレーム作成
上記のように指定したファイルを下記のコードで
読み込み、データフレームに変換します。
df_200_mm = CSV.read(data_path, DataFrame, header=["date", "time", "ir", "lidar"], delim=' ')
入力引数のdelimで区切り文字(今回はスペース)を
指定し、それで4列に区切られたCSV形式のデータに
します。そして、headerによって各列にカラム名を
設定し、データフレームとして出力します。
データの概要の出力
最後に下記のコードでデータの概要を出力します。
println("sensor_data_200.txt") println("Data size = ", size(df_200_mm)) println("Column Names = ", names(df_200_mm)) println("Data type = ", eltype.(eachcol(df_200_mm))) println("Describe = ", describe(df_200_mm))
出力結果は下記のようになり、上から順に
ファイル名、データサイズ、カラム名、
各列のデータのタイプ、統計量になります。
Data size = (58988, 4) Column Names = ["date", "time", "ir", "lidar"] Data type = DataType[Int64, Int64, Int64, Int64] Describe = 4×7 DataFrame Row │ variable mean min median max nmissing eltype │ Symbol Float64 Int64 Float64 Int64 Int64 DataType ─────┼─────────────────────────────────────────────────────────────────────────────── 1 │ date 2.01801e7 20180122 2.01801e7 20180124 0 Int64 2 │ time 117592.0 0 1.13958e5 235959 0 Int64 3 │ ir 308.682 283 308.0 338 0 Int64 4 │ lidar 209.737 193 210.0 229 0 Int64
特にdescribe関数を使うと、各データのカラム名、
タイプ、最小値、最大値、中央値、平均値などを
テーブルにまとめて表示してくれるので分かりやすいです。
コードのモジュール化
最後に、ここまでのコードをまとめて実行するために
モジュール化したものを紹介しておきます。
src/prob_stats/sensor_data/print_sensor_data.jl
module PrintSensorData using DataFrames, CSV function print_data_200() data_path = joinpath(split(@__FILE__, "src")[1], "data/sensor_data_200.txt") df_200_mm = CSV.read(data_path, DataFrame, header=["date", "time", "ir", "lidar"], delim=' ') println("sensor_data_200.txt") println("Data size = ", size(df_200_mm)) println("Column Names = ", names(df_200_mm)) println("Data type = ", eltype.(eachcol(df_200_mm))) println("Describe = ", describe(df_200_mm)) println("") return df_200_mm end function print_data_600() data_path = joinpath(split(@__FILE__, "src")[1], "data/sensor_data_600.txt") df_600_mm = CSV.read(data_path, DataFrame, header=["date", "time", "ir", "lidar"], delim=' ') println("sensor_data_600.txt") println("Data size = ", size(df_600_mm)) println("Column Names = ", names(df_600_mm)) println("Data type = ", eltype.(eachcol(df_600_mm))) println("Describe = ", describe(df_600_mm)) println("") return df_600_mm end end
センサから壁までの距離が200mmのデータと、
600mmのデータをそれぞれデータフレームに
変換し、概要を出力するプログラムです。
Juliaを起動し、下記のコマンドで実行できます。
julia> include("src/prob_stats/sensor_data/print_sensor_data.jl")
julia> PrintSensorData.print_data_200()
julia> PrintSensorData.print_data_600()
まとめ
サンプルのセンサデータをCSV、データフレームに
変換し、その中身の概要をざっと確認する方法に
ついて解説しました。
今後は、データをいろんな観点で可視化し、
詳細な傾向を分析していきます。