Tech Lib https://note-tech.com エンジニア志望の方に向けた実践技術の共有サイトです。 Sun, 12 Nov 2023 13:24:33 +0000 ja hourly 1 https://wordpress.org/?v=6.2.4 https://note-tech.com/wp-content/uploads/2020/07/cropped-logo_twitter-32x32.png Tech Lib https://note-tech.com 32 32 【GPT Builder】初心者向けGPTsの作り方 https://note-tech.com/how-to-create-gpts/?utm_source=rss&utm_medium=rss&utm_campaign=how-to-create-gpts https://note-tech.com/how-to-create-gpts/#respond Sun, 12 Nov 2023 08:22:49 +0000 https://note-tech.com/?p=1485 先日のOpenAI DevConでコーディングなしでオリジナルのGPT(=GPTs)を作れる機能が発表・リリースされ、早速多くの方々がGPTsを作っています。筆者もいくつかGPTsを作ってみたのですが非常に簡単に作れまし […]

The post 【GPT Builder】初心者向けGPTsの作り方 first appeared on .]]>
先日のOpenAI DevConでコーディングなしでオリジナルのGPT(=GPTs)を作れる機能が発表・リリースされ、早速多くの方々がGPTsを作っています。筆者もいくつかGPTsを作ってみたのですが非常に簡単に作れました。
ただ有料会員限定なので、課金するか悩んでいる人もいるかと思います。そこで、この記事ではGPTsが気になっている人や、これから作りたい方向けに作り方を簡単に紹介していきます。

GPTs作成までの流れ

GPTs作成までの流れを記載します。

  1. 有料会員(ChatGPT Plus)ユーザーになる。
  2. ChatGPTのサイトからExplore→ My GPTs下の「Create a GPT」でGPT Builderページへ
  3. 「Create」タブで、GPT Builderと会話しながら作りたいGPTsを伝える。聞かれる内容は、
    • 何をするGPTsを作りたいか。
    • GPTsの名前(仮称をGPT Builderが提案してくれます)
    • GPTsのアイコン(GPT Builderが候補を作ってくれます)
    • GPTsの振る舞い方や特定について(どのような質問やトピックに焦点を当てたいかなど)
    • など

GPTsは、GPT Builderと呼ばれるチャットボットと質問のやり取りをしながら作っていくのが基本的な作り方です。作成したいGPTsによって質問内容は変わってきますが、大まかな流れは共通かと思います。
それでは、続いて実際の画面キャプチャを見ながら作成するところを見ていきましょう。

GPTsを作成する

有料会員であるChatGPT PlusユーザーになるとGPTsを作成する項目(Explore)が表示されるようになります。ただし自分の場合は発表当日に有料会員登録したため、反映されるまで数日要しました。今はどうか分からないですが、即日反映とは限らないので注意してください。

EXPloreを選択すると、GPTsを作成するページが開き上段に自分のGPTs、下段に他者やOpenAIが作成したGPTsが表示されます。(画像ではMy GPTsのところに私が作成したGPTsが2つ並んでいます。)
Create a GPTからGPTsの作成を開始します。

Createタブで作成

Create a GPTをクリックすると、GPT BuilderがどういうGPTsを作りたいか質問してくるので、回答していけばGPTsが作られます。作成したGPTsは画面右のPreviewで挙動を確認できます。

以下のキャプチャは試しに作成したGPTsの作り方をサポートするGPT(GPT Creator)です。(紛らわしくてすみません。。)
作成したGPTsは右上のSaveで、非公開かURLを知っている人に公開するか指定できます。Publicでの公開は11月末にリリース予定のGPT Storeを楽しみに待ちましょう。

Configureタブで詳細を指定

Configureタグを選択すると先ほどの会話で得られたGPTsの目的や振る舞いなどが記載されています。そのためより詳細な設定を指示したい場合は、Configureタグで調整することが可能です。また、Createタブを使わず、初めからConfigureタブだけで作成することも可能です。

各項目のポイントは次のとおりです。

  1. Adding an image: GPT用の画像を作成依頼または自分でアップロード可能。
  2. Additional Instructions: GPTの動作、機能、避けるべき行動に関する詳細指示を提示できる。
  3. Prompt Starters: 会話開始のためのプロンプト例。
  4. Knowledge: GPTに追加のコンテキストを提供、アップロードされたファイルの内容が出力に含まれる可能性あり。
  5. New Capabilities: Webブラウジング、DALL·E画像生成、高度なデータ分析の有効化でGPTの機能拡張。
  6. Custom Actions:: サードパーティAPIの詳細を提供してGPTに利用させることが可能。既存のプラグインマニフェストを用いてアクションを定義可能。

My GPTs

GPTsが作成されると冒頭で紹介したMy GPTsに追加されます。

終わりに

いかがでしたか、簡単にオリジナルGPTが作れることが伝わったかと思います。X(旧twitter)を見てても多くの方々が面白いGPTsを作成しており、11末にリリースされるGPT Storeが待ち遠しい限りです。
筆者もそれまでに色々試行錯誤して面白くて便利なGPTsを作りたいと思います。

参考リンク

Creating a GPT | OpenAI Help Center
How to create a GPT

The post 【GPT Builder】初心者向けGPTsの作り方 first appeared on .]]>
https://note-tech.com/how-to-create-gpts/feed/ 0
[物体検出/セグメンテーション]AIによる画像処理タスク1 https://note-tech.com/image_ai_tasks/?utm_source=rss&utm_medium=rss&utm_campaign=image_ai_tasks https://note-tech.com/image_ai_tasks/#respond Sat, 20 May 2023 02:49:26 +0000 https://note-tech.com/?p=703 この記事では日々進化し続けるAI技術のうち、DeepLearningを用いた画像識別系のAIタスクについて具体的なアーキテクチャと共に概要を説明します。社会のニーズに合わせてAIタスクも細分化され、多種多様なタスクがあり […]

The post [物体検出/セグメンテーション]AIによる画像処理タスク1 first appeared on .]]>
この記事では日々進化し続けるAI技術のうち、DeepLearningを用いた画像識別系のAIタスクについて具体的なアーキテクチャと共に概要を説明します。社会のニーズに合わせてAIタスクも細分化され、多種多様なタスクがありますが代表的なものに限定し、ポイントを絞った記事にします。

物体検出(Object Detection)

画像に写っている人や物を検出するタスクが物体検出です。物体の位置を検出(Localization)しバウンディングボックスと呼ばれる矩形で囲み、囲まれた物体が何かを分類(Classification)します。

object detection(物体検出)
引用: https://pjreddie.com/darknet/yolo/

概要

物体検出のアーキテクチャは大きく2種類あり、YOLOやSSDに代表されるone-stage型と、Faster RCNNやに代表されるtwo-stage型があります。

  • two-stage
    • Selective Search(R-CNN, Fast R-CNNの場合)やRegion Proposal Network(Faster F-CNNの場合)という領域候補を生成する処理と、領域候補に対して物体分類(Classification)を行う処理の2段構成
    • 領域検出と分類を
    • 代表的なアーキテクチャ:R-CNN(Region based CNN), Fast R-CNN, Faster R-CNN
  • one-stage
    • 領域候補を生成せずに、物体分類とバウンディングボックス作成を同時に実施
    • 代表的なアーキテクチャ:YOLO(You Only Look Once), SSD(Single Shot Detection)
    • 特徴:処理がシンプルで比較的高速

代表的なアーキテクチャ

Faster R-CNN

two-stage型の代表的なアーキテクチャがR-CNNです。名前から分かる通り、Faster R-CNNはR-CNNを高速化したFast R-CNNをさらに高速化したアーキテクチャです。R-CNNは大まかに言うと、

  • 物体が存在する領域候補(Region Proposal)を生成
  • 生成された各領域に対して画像分類

という2ステップを取ります。
R-CNNではselective searchというアルゴリズムを用い画像あたり最大2000ヶ所の領域候補を生成し、各領域候補に対してCNNで特徴抽出を行って画像分類するため、膨大な計算量になりました。ここではR-CNNの改良版のFaster R-CNNについて取り上げます。

Faster R-CNNの全体概要を元論文を引用しつつ説明します。

構成要素としては、

  • 特徴マップの生成:入力画像をconv layers(VGG16やZFNetなど)に食わせて特徴マップ(feature maps)を生成します。
  • 領域候補(Region proposal)の推定:feature mapsをRegion Proposal Network(RPN)に入力し領域候補を推定します。
  • RoI Pooling:推定した領域候補の範囲を特徴マップから抽出し、RoI Poolingによって固定サイズに変換します。
  • クラス分類:RoI Poolingによって固定サイズに変換された特定領域の特徴マップに対して、分類器(classifier)によってクラス分類します。

があります。そのためFaster R-CNNを学習する場合は、RPNの学習とクラス分類器の学習を行うことになります。

YOLO

one-stage型のアーキテクチャとしてはSSDやYoloが有名ですが、ここでは引き続きアップデートが盛んなYoloについて紹介したいと思います。

YOLOの特徴を簡潔に述べると以下になります。

  • 物体検出のコンポーネントを1つに統合
    • R-CNNで2段階に分かれていた領域候補の検出と分類を1つに統合し、画像全体の特徴を用いてBounding Box(BBox)とクラス分類を同時に実施
    • これにより高精度な検出を維持しつつend-to-end学習とリアルタイムな検出スピードを実現
  • グリッドセルの採用
    • 入力画像をS×Sのグリッドに分割し、各グリッドに、物体の中心がグリッド内に位置する物体を検出する責任を持たせる
    • グリッドセルは複数のBBoxを持つ(論文では2つ)
    • 各グリッドはBBoxの数に関わらず1つセットのクラス確率を持つ。つまり、グリッド毎に推論されるクラスは1つのみ。
  • YOLOの出力
    • YOLOはグリッドセル毎に、BBoxのConfidence、BBoxの位置情報(X, Y, H, W)、クラス毎の予測確率を出力する。
    • 例えば、グリッドセルS=7、グリッド毎のBBox数B=2、クラス数C=20の場合の出力サイズは、S×S×(B*(1+4)+C)=7×7×30
    • Confidence( = Pr(Object) * IOUTruthPred):BBoxに物体が含まれているかと、BBoxの予測がどの程度正しいかの信頼度
    • BBoxの位置情報(X, Y, H, W):
      •  X, Y:グリッドセルの境界を基準としたBBoxの中心座標
      • W, H:画像全体に対する相対値

こちらが論文で紹介されているYOLOのアーキテクチャです。入力として448×448のカラー画像(3次元)を受け取り、出力として7×7×30のグリッド毎の物体検出結果を出します。

YOLOのアーキテクチャ(引用元: You Only Look Once: Unified, Real-Time Object Detection)

参考リンク

[stack overflow]One stage vs two stage object detection
[Qiita]物体検出についてのまとめ(1)
[Medium]What do we learn from region based object detectors (Faster R-CNN, R-FCN, FPN)?
[Qiita]物体検出Faster R-CNN (Faster Region-based CNN)
物体検出の代表アルゴリズム YOLOシリーズを徹底解説!【AI論文解説】

セグメンテーション(Segmentation)

物体検出では矩形で画像内に存在する物体を検出していましたが、Segmentationでは画像のピクセル単位で分割します。Segmentationは大きく3種類のタスクに分類され、アーキテクチャの複雑さもタスク毎に変わるため用途に合わせて適切なアーキテクチャを選択する必要があります。

概要

  • Semantic Segmentation
    • 画像内の各ピクセルに対して、該当ピクセルがどのクラス(人、車、建物など)に分類されるかを推論する。同じクラス同士の区別をしないため、人や車が複数写っていてもそれぞれ人、車というクラスに分類される。
    • 特徴
      • セグメンテーションの中で最もシンプルなタスクであり、アーキテクチャも比較的わかりやすい。
      • 同じクラス同士での区別がされず、境界も分からない。
    • 代表的なアーキテクチャ:FCN(Fully Comvolutional Network), U-Net
  • Instance Segmentation
    • セマンティックセグメンテーションと物体検出を組み合わせ、インスタンス(物体)単位でのセグメンテーション(領域分割)を実現するタスク。
    • 特徴
      • インスタンスを区別するため、重なり合っている場合でも境界を認識できる。
    • 代表的なアーキテクチャ:Mask R-CNN,
  • Panoptic Segmentation
    • Panopticの意味は“including everything visible in one view"(論文より引用)
    • セマンティックセグメンテーションとインスタンスセグメンテーションを組み合わせたタスク。インスタンスだけでなく、背景といった物体検出でインスタンスとして検出されない範囲もセグメンテーション対象。
    • 特徴
      • Panoptic("全面的な"という意味)の名前の通り画像内の全てを対象とし、インスタンスも区別しつつセグメンテーションを行う
      • 画像全体のセグメンテーションと物体検出を行うため、セグメンテーションタスクの中で最も重たい
    • 代表的なアーキテクチャ:Efficient Panoptic Segmentation

Mask R-CNN

Mask R-CNNはFacebookのAI研究チームによって発表されました。Faster F-CNNに簡易なレイヤーを追加するだけでセグメンテーション機能を実現しています。

Mask R-CNNのフレームワーク(引用元: Mask R-CNN)

 Faster R-CNNにおける既存の物体検出/クラス分類ブランチと並行して、各RoI(画像中の注目領域)におけるセグメンテーションマスクを生成するブランチを処理します。ベースのFaster R-CNNの仕組みを流用しつつ、さらに追加のマスクブランチもCNNを2つ追加するだけの簡易な構成で、セグメンテーションへの拡張を実現しています。
 また、Mask R-CNNではRoIを特定するアルゴリズムを改善したRoI Alignが提案されており、位置情報の精度向上に貢献しています。

参考リンク

Image segmentation with Mask R-CNN
[Paper]EfficientPS: Efficient Panoptic Segmentation

終わりに

AIによる画像認識のうち最も定番なタスクである物体検出とセグメンテーションについて、概要と代表的なアーキテクチャを紹介しました。次はビジネスにおいても頻繁に登場する異常検知、姿勢推定、顔認証といったタスクについて紹介していきたいと思います。

The post [物体検出/セグメンテーション]AIによる画像処理タスク1 first appeared on .]]>
https://note-tech.com/image_ai_tasks/feed/ 0
【バックキャスト】理想の未来像を実現するためのフレームワーク https://note-tech.com/backcast/?utm_source=rss&utm_medium=rss&utm_campaign=backcast https://note-tech.com/backcast/#respond Sun, 30 Apr 2023 09:28:15 +0000 https://note-tech.com/?p=1371  バックキャスティングは、理想とする未来から考え、どのようなステップを踏んでいけば理想の未来を実現できるか逆算して考える手法です。VUCAと呼ばれ不確実性の高い時代において、理想の未来を実現に導く手法として注目されていま […]

The post 【バックキャスト】理想の未来像を実現するためのフレームワーク first appeared on .]]>
 バックキャスティングは、理想とする未来から考え、どのようなステップを踏んでいけば理想の未来を実現できるか逆算して考える手法です。VUCAと呼ばれ不確実性の高い時代において、理想の未来を実現に導く手法として注目されています。バックキャスティングの特徴として、現在の延長線上にはない理想の未来に行き着くためのアプローチを検討することができる点があります。逆に、現状を理解し積み上げ型で進めていく方法をフォアキャスティングといいます。決して、バックキャスティングがフォアキャスティングに対して優れているという訳ではなく、目的に応じて使い分ける必要があるのが注意点です。
 本記事では、バックキャスティングの特徴や事例、そしてバックキャスティングを活用するためのフレームワークを紹介します。

バックキャスティングの活用事例

 本題に入る前にバックキャスティングを活用している代表事例を紹介します。
 バックキャスティングで計画された有名なプロジェクトにアポロ計画があります。アポロ計画は1960年に米国のジョン・F・ケネディ大統領が1960年代中に人類を月に到達させるとの声明を発表したことから始まっており、大きな目標を最初に掲げそのために必要なアクションを検討し実行されました。

 他の事例としては最近注目されているSDGsも、2030年までに達成すべき理想的な未来をイメージし、そのために必要なアクションを具体化するバックキャスティング手法をとっている代表例です。

活用手順

バックキャスティングは、将来に向けてのプランニング手法として注目を集めています。企業や組織のビジョン設定、プロジェクト計画、SDGsのような世界規模の命題から、ダイエットといった個人の目標設定まで様々な場面で活用することができます。本章では、バックキャスティングのフレームワークを紹介し、ビジネスにおいてどのように活用するかを解説します。

 図はバックキャスティングを活用するためのフレームワークです。①の理想の未来像作成、②現状と課題の把握、③実現ステップの順に検討していきます。それでは詳細について見ていきましょう。

理想の未来像を作成

バックキャスティングではまず理想の未来像を明確に定義することから始めます。この理想の未来像から考えることがバックキャスティングの一番のポイントですので、なぜその未来を実現したいのかしっかり検討すると良いでしょう。実現したい未来像をイメージし、その未来を実現するために重要な要素(KSF)を考えます。

  • WHY:なぜその未来を目指すのか
    • 未来像を実現するための目的を明確にします。この目的があることで、計画を進める上での方向性が明確になり、各ステップの優先順位を決定することができます。
    • 未来像をしっかり検討するために5WHYで深掘りしていくのもおすすめです。
  • KSF(Key Success Factor):主要成功要因
    • 理想の未来が実現できているとする主要な要素を決めます。フレームワークでは3つのKSFを設定するようにしています。

現状と課題の把握

目指すべき理想の未来像が定義できたら次に現在の状況(As-Is)や課題(Issue)を把握します。ここで分析した現状から、理想の未来実現に向けてステップを進めていきます。

  • As-Is:企業や業界、個人の現状を分析
    • 自社や業界の現状を把握することが重要です。自社の強みや弱み、業界の動向、理想の未来像に関する自分の現状などを分析し、未来像を実現するための課題を明確にしていきます。
  • Issue:現状の課題
    • 理想の未来を実現するために解決すべき課題を洗い出します。大小様々な課題があると思いますが、理想の未来を実現するためという目的に沿って重要な項目を考えます。

実現ステップ

最後に、現状から未来像に至るための具体的なアクションを考えます。フレームワークでは実現までに3つの段階を区切っています。必ずしも3つである必要はありませんが、そのくらいが最初の検討としては調度良いと思います。

  • WHAT 未来像を実現するために必要な要素を検討します。
  • HOW WHATを実施するための、具体的な内容/手段を検討します。WHATであげた抽象度の高い要素を、実施するための具体的な施策に落としていくイメージです。

以上が、バックキャスティングの活用手順です。次の章では具体例を挙げて実際に活用する方法を紹介します。

バックキャスティングの具体例:ダイエット

バックキャスティングの活用手順を紹介したので、ここでは身近な例であるダイエットを題材に実際に活用してみます。

  • WHY:理想の未来像を描く
    • ダイエットによって実現したい理想の未来を描きます。ここでは、なぜなぜ分析(Five Whys)を用い具体化します。
      • なぜダイエットをしたい/体重を落としたいのか?
        • 健康的な身体にしたい
      • なぜ健康的な体にしたいのか?
        • いつまでも元気いっぱいでいたい
        • 見栄えの良い身体になりたい
      • なぜいつまでも元気いっぱいでいたいのか?
        • 美味しい食事を楽しんだり、元気に旅行したいから
      • なぜ見栄えの良い身体になりたいのか?
        • 同僚や友人、恋人からの注目を集めたいから
    • ダイエットの目的:体力があり、健康的でスタイルの良い身体作りをする

なぜなぜ分析によってダイエットの目的が深掘りできました。単純に体重を落とすではなく、体力を付けつつ他人に憧れられるようなスタイルの良い身体作り、と目的が明確になっています。

  • 主要成功要因(KSF)を考える
    • ハーフマラソンを完走できる体力
    • 適度に筋肉が付いた引き締まった身体(体脂肪率15%、筋肉量40%)
    • 健康診断で問題がない

体力基準としてハーフマラソン完走できれば十分だと考えました。スタイルとしては大き過ぎず細過ぎずに引き締まったラインとして、健康な一般男性の基準内で高めの数値を設定しました。健康の目標は健康診断で問題がないとしました。今回の目標に対しては過大/過小になることなく設定できたと思います。KSFを上手く設定するためにも、未来の理想像をしっかり考えるのが大事なのがわかると思います。
KSFを考えたら次は現状を分析し、KSFに対する課題を洗い出し解決への実行ステップを作ります。

  • 現状分析
    • 体力:連続して走れる距離は2km
    • 身体: 体脂肪率は25%
    • 健康診断: 健康診断で腹囲や尿酸値が基準値を超えている
  • 課題(Issue)
    • Issue1:トレーニングの継続
    • Issue2:知識(健康的な食事や必要な運動について)
    • Issue3:バランスの取れた食事と休養

現状を分析したら理想の未来像を実現するためのステップを考えます。フレームワークでは、WHAT:何を実現するのか、HOW:具体的にどうするのか、という項目を用意し抽象的な内容と具体的に内容を3ステップにわたって記載できるようにしています。

  • 実行ステップ
    • ステップ1
      • WHAT
        • 食事管理:今の食生活を振り返り、摂取カロリーや栄養素(脂質、タンパク質、ビタミンなど)のバランスを確認する
        • トレーニング:無理なく継続できるトレーニング内容を考え、まずは始める
        • 知識:バランスの良い食事、継続できるトレーニングメニューを調べる
      • HOW
        • 食事管理:あすけんなどのダイエットアプリを使い、日々の食事を見える化する
        • トレーニング:近場のジムに入会し、とにかく週1で通うようにする
        • 知識:健康系YouTuberのチャンネルを見て基礎知識を付ける。

理想の未来像実現に向け、最初にやるアクションを決めました。同様にしてステップ2、ステップ3のアクションを計画したら、実際に実行しながら振り返り、アップデートするというPDCAを回し目標達成に向けて邁進することができます。

終わりに

バックキャスティングの概要について説明し、フレームワークを用いてバックキャスティングを活用する手順と、ダイエットを題材にした具体例を紹介しました。
バックキャスティングを活用することで、理想の未来像を実現するために現状課題を踏まえた具体的なアクションプランを策定することができます。未来を見据え、戦略的にビジネスを展開するために、ぜひこのフレームワークを活用してみてください。

参考リンク

The post 【バックキャスト】理想の未来像を実現するためのフレームワーク first appeared on .]]>
https://note-tech.com/backcast/feed/ 0
ChatGPTができることを知ろう!5つの実践的な活用方法 https://note-tech.com/chatgpt-usage/?utm_source=rss&utm_medium=rss&utm_campaign=chatgpt-usage https://note-tech.com/chatgpt-usage/#respond Sat, 18 Feb 2023 09:20:22 +0000 https://note-tech.com/?p=1349 こんにちは!今回は、最近話題のChatGPTについてご紹介します。ChatGPTは、大量の自然言語データから学習された「言語モデル」を用いて、人間との自然な対話を可能にする技術です。本記事では、ChatGPTを使った実践 […]

The post ChatGPTができることを知ろう!5つの実践的な活用方法 first appeared on .]]>
こんにちは!今回は、最近話題のChatGPTについてご紹介します。ChatGPTは、大量の自然言語データから学習された「言語モデル」を用いて、人間との自然な対話を可能にする技術です。
本記事では、ChatGPTを使った実践的な活用方法を5つ紹介し、その活用例を通してChatGPTの魅力をお伝えしていきます。ぜひ、最後までご覧ください。

ちなみに、ブログのタイトル含め今回の記事の大半はChatGPTに書いてもらいました。自然な文章を短時間で書いてくれるのでとても便利です。

ChatGPTの使い方

ChatGPTは開発元のOpenAIのWebサイトから簡単に使用することができます。
OpenAIのサイトにアクセスし、ページ下のFEATURESの区分にあるChatGPTを選択すると左図のページに移ります。
ちなみに、ChatGPT以外にもテキスト文からリアルな画像を生成するDALL·E 2もWebサイトから無料で利用できるので、画像生成に興味がある方はそちらも試してみると良いと思います。

ChatGPTの活用パターン

オススメを訪ねる

ChatGPTを使って、オススメの映画を訪ねる方法をご紹介します。まず「今週末、見るべき天才が登場する名作映画を教えて」と尋ねた結果がこちらです。

 素晴らしいお題目ですね!天才が登場する名作映画といえば、まずは「グッド・ウィル・ハンティング」が挙げられます。主人公のウィル・ハンティング役を演じたマット・デイモンは、天才的な数学の才能を持つ青年を演じています。共演のロビン・ウィリアムズも素晴らしい演技を見せています。
 また、「アマデウス」も名作の一つです。ウォルフガング・アマデウス・モーツァルトを題材にした本作は、音楽の天才として知られる彼と、そのライバルであるアントニオ・サリエリとの対立を描いています。
 これらの作品は、天才的な才能を持つ人物たちの心の内に迫り、感動的なストーリー展開が見どころです。ぜひ楽しんでいただければと思います!

このように、様々な映画のタイトルやあらすじ、評価などを元に回答を生成してくれます。個別の映画について再度問い合わせれば、より詳細の情報を聞くこともできますし、次に紹介する方法で聞けばオススメ映画をリストで回答してくれます。

リストを作る

オススメ映画のリストを得る方法を例に、知りたい情報をリスト化として回答してもらう方法を紹介します。ChatGPTに「今週末、見るべき天才が登場する名作映画5選を教えて」と尋ねてみました。

 はい、こちらが天才が登場する名作映画のおすすめ5選です!
1. 「グッド・ウィル・ハンティング」:マット・デイモンが演じる数学の天才、ウィル・ハンティングの物語。ロビン・ウィリアムズも出演し、共に心に残る演技を見せています。
2. 「シャイン」:ピアニストとして天才的な才能を持つデヴィッド・ヘルフゴットの波乱万丈の人生を描いた実話を基にした映画。主演のジェフリー・ラッシュはアカデミー賞を受賞しました。
3. 「レインマン」:自閉症スペクトラムの天才的な数学者を演じたダスティン・ホフマンが、兄弟役のトム・クルーズとの絆を描いた感動作。
4. 「アマデウス」:音楽史に名を刻む天才作曲家、モーツァルトの才能と苦悩を描いた名作。監督のミロス・フォアマンがアカデミー賞を受賞しています。
5. 「ゴッドファーザー」:マフィアのボスとして天才的な頭脳を持つドン・コルレオーネを演じたマーロン・ブランドが、圧倒的な存在感を放つ名作中の名作です。

ChatGPT

このように、ChatGPTを使って知りたい情報をリスト化することができます。リスト化することで、効率的に情報を整理することができ、情報収集や意思決定のサポートとして大いに役立ちます。

メール文案を作る

ChatGPTは、ビジネスにおいても幅広い応用が期待されています。ここでは、一例としてイベント招待メールを作成してもらう方法を紹介します。
ChatGPTに「ChatGPTの活用事例を紹介するイベントを開催したいので、参加者を募る招待メールの文を書いて」と依頼しました。

件名: ChatGPT活用事例紹介イベントにご招待

いつもお世話になっております。○○社の○○と申します。

この度、当社ではChatGPTの活用事例紹介イベントを開催いたします。ChatGPTは、AI技術の1つで、文章生成や応答生成など様々な用途に使われています。本イベントでは、ChatGPTの活用事例をいくつかご紹介し、その実践的な活用方法についてご説明いたします。

当社では、このChatGPTを活用し、業務効率化やコスト削減などの効果を実感しております。ぜひ、この機会にChatGPTの活用事例を学び、皆様のビジネスにもご活用いただければ幸いです。

日時: 〇〇月〇日(〇)〇時〜〇時
場所: 〇〇会議室(詳細は参加確定者にのみご案内いたします)
定員: ○○名
参加費: 無料

ご参加いただくためには、以下のリンクより事前登録が必要です。なお、定員に達し次第、締め切らせていただきますので、お早めにお申し込みください。

(登録リンク)

多くの方々のご参加を心よりお待ちしております。
よろしくお願いいたします。
敬具

このように招待文を作成してくれます。あとは日時など固有情報を記載すればそのまま使えるほど自然な文章です。メール文以外にも記事の内容や感想文など、幅広い文章を書いてくれるので色々試してみると面白いです。

要約する

ChatGPTに文章の要約を依頼することができます。ここでは、先ほどのイベント招待メールを要約してもらいます。
ChatGPTに「以下の文章を100文字程度で要約して「〜〜要約する文章〜〜」」とすることで要約した文章を作成してくれます。

「ChatGPT活用事例紹介イベント」の案内メール。AI技術のChatGPTの様々な用途について説明し、実践的な活用方法を紹介する。業務効率化やコスト削減などの効果を紹介し、参加費無料で定員に達した場合は締め切るので、早めに登録することを呼びかけている。

このように要約文の長さを指定した依頼にも対応され、必要な要点をしっかり捉えた要約文が生成されます。注意点としては、特に、要約対象の文章が長い場合、自動生成された要約文に含まれる情報が不足していることがあるため、要約文の意味が明確であるかどうかを確認することが重要です。
また、長い文章でも要約が可能ですが、入力する文章の長さに制限があることも注意点です。

コーディングする

ChatGPTにはコーディングを依頼することもできます。ここでは「1〜1000の素数を出力するpythonコードを実装して」と依頼してみました。

def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

for num in range(1, 1001):
    if is_prime(num):
        print(num)

このコードでは、is_prime関数を使用して、特定の数が素数かどうかを判断します。
is_prime関数は、以下のように動作しています。

- nが1以下の場合は、素数ではないと判定しFalseを返す。
- 2からnの平方根までの整数を順番に調べ、nがその数で割り切れる場合は素数ではないと判定しFalseを返す。
- いずれの条件にも当てはまらない場合は素数であると判定しTrueを返す。

丁寧にコードの解説文まで付けて回答してくれました。より複雑な実装も依頼文次第では実装可能ですので、上手くChatGPTを使うことで、効率的にプログラミングすることができます。

ChatGPTの注意点

ここまでChatGPTの便利な活用方法を紹介してきました。最後にChatGPT活用の注意点を、ChatGPTに聞いてみた内容を紹介します。

  1. プライバシーの問題
    ChatGPTは、会話内容を学習するために大量のデータを必要とします。そのため、ChatGPTが会話内容を保存している可能性があります。
  2. モデルの品質による回答の信頼性
    ChatGPTは、学習データに基づいて応答を生成するため、そのモデルの品質によって回答の信頼性が異なります。特に、ChatGPTが対応していないトピックや、適切な回答を生成できない場合があります。
  3. 誤解を招く可能性がある回答
    ChatGPTは、機械学習に基づく自然言語処理技術を用いて応答を生成するため、場合によっては誤解を招くような回答を生成することがあります。そのため、ChatGPTの回答を利用する際には、その回答の文脈を正しく理解し、必要に応じて確認することが重要です。
  4. コンピュータリソースの要件
    ChatGPTは、多くのコンピュータリソースを必要とするため、大規模なデータセットを処理する場合には、高性能なハードウェアが必要になる場合があります。そのため、ChatGPTを使う前に、利用環境のハードウェア要件を確認することが重要です。

まとめ

 いかがでしたでしょうか?冒頭に記載した通り、このブログの大半はChatGPTに書いてもらってます。便利すぎて筆者も使いながら驚きと興奮が隠せません、そしてもうChatGPTがない世界に戻れない気がします。これでまだまだ発展途上であることを考えると、今後ますますAIを使い倒すスキルが重要になると実感させられます。
 記事の中で紹介した「xxxを教えて」のような単純な依頼以外にも、「ChatGPTの活用パターンとして、イベント招待文案を作成してもらう方法を紹介するブログ記事を書きたい。 「イベント招待メールを書いて」と問い合わせた結果を含めた記事を書いて。」とすれば導入文、主題、まとめ、まで含めた記事を書いてくれます。どのような依頼をすれば希望の結果が得られるのか、試行錯誤のしがいがありますね。

The post ChatGPTができることを知ろう!5つの実践的な活用方法 first appeared on .]]>
https://note-tech.com/chatgpt-usage/feed/ 0
統計検定2級の受験体験記(2022年) https://note-tech.com/%e7%b5%b1%e8%a8%88%e6%a4%9c%e5%ae%9a%ef%bc%92%e7%b4%9a%e3%81%ae%e5%8f%97%e9%a8%93%e4%bd%93%e9%a8%93%e8%a8%982022%e5%b9%b4/?utm_source=rss&utm_medium=rss&utm_campaign=%25e7%25b5%25b1%25e8%25a8%2588%25e6%25a4%259c%25e5%25ae%259a%25ef%25bc%2592%25e7%25b4%259a%25e3%2581%25ae%25e5%258f%2597%25e9%25a8%2593%25e4%25bd%2593%25e9%25a8%2593%25e8%25a8%25982022%25e5%25b9%25b4 https://note-tech.com/%e7%b5%b1%e8%a8%88%e6%a4%9c%e5%ae%9a%ef%bc%92%e7%b4%9a%e3%81%ae%e5%8f%97%e9%a8%93%e4%bd%93%e9%a8%93%e8%a8%982022%e5%b9%b4/#respond Sat, 26 Nov 2022 03:03:16 +0000 https://note-tech.com/?p=1326 2022年10月に統計検定2級(CBT方式)に合格したので、勉強方法と出題内容の要点を記載していきます。これから受験を考えている方の参考になれば幸いです。 勉強方法 統計検定2級の合格に向けては試験範囲について幅広く抑え […]

The post 統計検定2級の受験体験記(2022年) first appeared on .]]>
2022年10月に統計検定2級(CBT方式)に合格したので、勉強方法と出題内容の要点を記載していきます。これから受験を考えている方の参考になれば幸いです。

勉強方法

統計検定2級の合格に向けては試験範囲について幅広く抑えておくことが重要だと感じました。また、試験時間は基本的に足りないので、追い込み段階では時間を測りつつ、問題ごとにざっと見て方針が思い付かなかったらスキップするという判断力をつけた方が良いです。
勉強のステップは、教材を用い統計検定2級の全体像をざっくり把握する、過去問を解いて傾向を把握する、教材と過去問を往復し不明点を明確にしていく、時間を測って過去問を解く、という流れが良いと思います。
それでは、具体的に勉強する際のおすすめ教材を紹介します。

おすすめ教材

次の3つの教材がおすすめです。

  • 統計WEB:統計学の基礎から分かりやすく説明されているサイト。参考書や辞書代わりに利用
  • とけたろうチャンネル(YouTube)統計検定2級の範囲を網羅的に動画で解説しているチャンネル。単元ごとに過去問に沿った演習問題と解説がついている。このチャンネルの内容を全て理解すれば合格できるかと。
  • 公式問題集:日本統計学会が出版している公式の過去問集。傾向を掴むために過去問は一通り解くことをお勧めします。また、追い込み段階では時間を測り、難問はスキップするという判断力をつけることを推奨します。ちなみに解説は勉強し始めの段階では理解しにくいので、解説サイトを見た方が良いです。

序盤は統計WEBで統計学の用語や内容をざっくり理解し、中盤以降はとけたろうチャンネルと過去問を往復し問題の傾向を掴み、抜け漏れを補完していくのが良いと思います。

要点メモの作成

学習した内容の定着と復習のために要点メモを自作していましたが、個人的にこれは結構効果がありました。それは、試験範囲もそれなりに広いので一度学習した内容を忘れたり、どこで学んだかも分からなくなりがちだったからです。情報元もセットでメモしておけば詳細の確認もスムーズなのでオススメです。
参考までに自作の要点メモを一部公開します。

統計検定の要点

勉強方法の冒頭でも記載しましたが、統計検定2級の受験にあたっては試験範囲の内容について幅広く抑えておく事が重要です。
筆者は、先に上げた自作の要点メモを元に曖昧な部分を復習し内容を定着させていきました。メモを作るのは少し手間ではありますが、メモを作る過程で大分理解が進んだのと、復習する際にも自分が過去理解できていなかった部分が詳しく記載されるので最高の参考書になったと思います。
以下に統計検定2級範囲の項目を列挙しますので、チェックリスト代わりに参考にしてもらえれば幸いです。先に紹介した「おすすめ教材」でほぼ網羅できるはずです。

  • 度数
    • 四分位範囲、四分位数
  • ローレンツ曲線
    • ジニ係数
  • 標本抽出法
    • 層化(層別)抽出法: グループ分け+無作為
    • クラスタ(集落)抽出法: 無作為+全数
    • 多段抽出法: 無作為+無作為+...
    • 系統抽出法: ナンバリング+一定間隔
  • フィッシャーの3原則
    • 局所管理: ブロック内で均一な条件へ
    • 無作為化: 処理をランダムに割り当て
    • 繰り返し: 複数回実施。偶然誤差の大きさを評価
  • 移動平均(偶数項/奇数項の場合)
  • コレログラム
  • 物価指数(ラズパイレス、パーシェ)
  • 期待値・分散の公式
    • 定義、四則演算、係数、分散の算出、独立の場合
    • 変動係数
  • 共分散と相関係数
    • 定義と導出の公式
    • 線形変換した時の変化
    • 偏相関係数と擬相関の意味
  • 確率計算
    • 独立の場合、排反の場合
    • ベイズの定理
    • 条件付き確率
      • 事後確率
      • 事前確率
  • 確率変数の期待値と分散
  • 確率分布
    • 正規分布
      • 標準正規分布への変換
      • 正規分布の結合
      • 標準化得点
      • 歪度と尖度
    • 二項分布
      • 概要
      • 期待値と分散
      • 正規近似
        • 条件と近似式
    • ポアソン分布
      • 概要
      • 期待値と分散
    • 幾何分布
      • 概要
      • 期待値と分散
  • 標本平均と不偏分散(対数の法則、中心極限定理)
  • 推定
    • 母平均、母分散、母比率の推定
      • 母平均の推定
        • 正規母集団、母分散既知、95%区間
          • 正規分布 * (母分散/標本のルート)
        • 正規母集団、母分散未知、
          • T分布 * (不偏分散/標本のルート)
        • 母分散未知、大標本
          • 正規分布 * (不偏分散/標本のルート)
      • 母分散の推定
        • カイ二乗分布
      • 母比率の区間推定
        • 大標本:E=p, V=pq/nの正規分布で計算
    • 母数(母平均、母分散、母比率)の差の検定
  • 検定
    • 母平均、母分散、母比率の検定
      • 母平均の検定
        • 正規母集団、母分散既知:Z値(母分散)と棄却域の計算: N(0, 1)分布
        • 正規母集団、母分散未知:T値とT(n-1)分布
        • 母分散未知、大標本;Z値(不偏分散)とN(0, 1)
      • 母比率の検定
    • 差の検定
      • 母比率の差の検定
      • 母平均の差の検定(帰無仮説: μ=0)
        • 対応のある場合(正規母集団)
          • T値
        • 対応のない場合
          • 正規母集団、母分散既知 or 大標本→ Z値 or T値
          • (難): 正規母集団、母分散未知、等分散→ T(n1+n2-2)の検定
      • 二項分布の正規近似
    • 適合度の検定
      • カイ二乗分布
    • 独立性の検定(過去問: 2016-6)
      • クロス表+カイ二乗
    • 等分散性の検定
      • F分布: F=U1^2/U2^2
  • 一元配置分散分析(過去問 2019-11)
    • 水準間平方和、残差平方和の計算と自由度
    • F分布 F(水準数 - 1, 全標本 - 水準数)
  • 回帰
    • 残渣の自由度: 標本数N - 定数項を含む係数の数
    • 検定: 帰無仮説 係数=0か検定する
      • 検定量(T値): 回帰係数 / 標準誤差
      • 棄却域: t(残渣の自由度)から算出

終わりに

統計検定2級の合格までの道のりを振り返り、オススメの勉強手順や教材を紹介しました。これから受験される方の参考になれば幸いです。

The post 統計検定2級の受験体験記(2022年) first appeared on .]]>
https://note-tech.com/%e7%b5%b1%e8%a8%88%e6%a4%9c%e5%ae%9a%ef%bc%92%e7%b4%9a%e3%81%ae%e5%8f%97%e9%a8%93%e4%bd%93%e9%a8%93%e8%a8%982022%e5%b9%b4/feed/ 0
【datetime】pythonで日付/時刻を処理するdatetime型を扱う方法 https://note-tech.com/python-datetime/?utm_source=rss&utm_medium=rss&utm_campaign=python-datetime https://note-tech.com/python-datetime/#respond Wed, 15 Jun 2022 13:43:55 +0000 https://note-tech.com/?p=1284 データ分析を行なっていると"2022-6-11"や"2022-06-11-12-30"のような日付/日時情報を扱うことがよくあります。この記事ではpythonで日付/時刻を扱う際に利用するdatetime型の使い方を紹介 […]

The post 【datetime】pythonで日付/時刻を処理するdatetime型を扱う方法 first appeared on .]]>
データ分析を行なっていると"2022-6-11"や"2022-06-11-12-30"のような日付/日時情報を扱うことがよくあります。この記事ではpythonで日付/時刻を扱う際に利用するdatetime型の使い方を紹介します。

datetime型

pythonでは基本的な日付型および時間型としてdatetimeが用意されており、datetimeを用いることで年・月・日・曜日の取得や、日時同士の足し算/引き算など基本的な処理が簡単に行えます。

datetime型への変換

datetime型への変換にはdateutilライブラリを利用することをおすすめします。組み込みライブラリのdatetimeを使った変換もできますが、フォーマット指定が必要だったり柔軟に変換できないことが多いためです。
組み込み v.s. サードパーティの議論について興味がある方は、英語になりますがこちらの記事を参照ください。サードパーティのライブラリを使うメリットや、日時データをプログラミングで扱うのがなぜ難しのかについて記載されています。

日時を表した文字列をdatetime型に変換するサンプルコードを記載します。

from dateutil.parser import parse

# 日時の文字列
yymmdd1 = "2022-6-11"
yymmdd2 = "2022/6/11"
yymmdd3 = "June 11th 2022" # Human-Readableな形式

# datetime型へ変換
yymmdd1 = parse(yymmdd1)
yymmdd2 = parse(yymmdd2)
yymmdd3 = parse(yymmdd3)
print(yymmdd1) # datetime.datetime(2022, 6, 11, 0, 0)
print(yymmdd2) # datetime.datetime(2022, 6, 11, 0, 0)
print(yymmdd3) # datetime.datetime(2022, 6, 11, 0, 0)

3つの表現形式で変換を試しましたが、どの形式でも正しく変換されているのがわかります。

次に、標準規格として定義されているISO8601の表現形式を変換してみます。
ISO8601では基本形式と、拡張形式が定義されており、

  • 基本形式: 20210927T150810.78
  • 拡張形式: 2021-09-27T15:08:10.78

のように日付と時刻を「T記号」で区切って表現します。
また、タイムゾーンも併せて表現することが可能で、協定世界時(UTC)は末尾に「Z記号」を付加することで表現できます。UTCからの差分は「+記号」で表現でき、日本時間を表すJSTの場合は+0900を末尾に付けます。

# ISO8601形式の文字列
iso1 = "2021-09-27T15:08:10.78" # 拡張形式
iso2 = "20210927T150810.78" # 基本形式
iso3 = "2021-09-27T15:08:10.78Z" # 拡張形式(UTC)
iso4 = "2021-09-27T15:08:10.78+9:00" # 拡張形式(JST)

# datetime型へ変換
iso1 = parse(iso1) # 2021-09-27 15:08:10.780000
iso2 = parse(iso2) # 2021-09-27 15:08:10.780000
iso3 = parse(iso3) # 2021-09-27 15:08:10.780000+00:00
iso4 = parse(iso4) # 2021-09-27 15:08:10.780000+09:00

# 型を確認
type(iso1) # datetime.datetime

datetime型への変換ができたので、年月日や時刻の情報を抽出する方法を見ていきます。

datetimeで値の取得: 年月日、時刻、曜日、現在時刻

datetime型に変換できれば年や月といった個別の情報を抽出するのは簡単です。
以下の例で、各情報の取得方法を紹介します。

# 日付の取得
print(iso1.date()) # 2021-09-27

# 年・月・日の取得
print(iso1.year) # 2021
print(iso1.month) # 9
print(iso1.day) # 27

# 時・分・秒の取得
print(iso1.hour) # 15
print(iso1.minute) # 8
print(iso1.second) # 10

# 曜日の取得
print(iso1.weekday()) # 月曜日を0, 日曜日を6で取得
print(iso1.isoweekday()) # 月曜日を1, 日曜日を7で取得

# ISOカレンダーの取得
print(iso1.isocalendar()) # datetime.IsoCalendarDate(year=2021, week=39, weekday=1)

# 現在時刻の取得
now = datetime.datetime.now()
print(now) # datetime.datetime(2022, 6, 12, 12, 53, 1, 266546)

リファレンス: datetimeのインスタンス属性

タイムゾーンについて

国や地域ごとの時差を考慮した時刻設定を行うためにタイムゾーンが定義されています。先の例でも紹介しましたが、datetime型ではタイムゾーンを設定することができます。ここではdatetimeでタイムゾーンを確認/設定/削除する方法を紹介します。

タイムゾーンの確認/設定/削除: tzname()/astimezone/replace

タイムゾーンの確認/設定/削除はそれぞれ、tzname()、astimezone、replaceを用いて実現できます。サンプルコードを見ていきましょう。

# UTCタイムゾーンのdatetime
iso = parse("2021-09-27T15:08:10Z")
print(iso) # 2021-09-27 15:08:10+00:00

# timezoneを確認する
print(iso.tzname()) # UTC

# タイムゾーンを追加: astimezone
## UTCタイムゾーンを設定
iso = iso.astimezone(datetime.timezone.utc)
print(iso) # 2021-09-28 00:08:10+09:00

## JSTタイムゾーンを設定。時差が反映される。
iso = iso.astimezone(datetime.timezone(datetime.timedelta(hours=9)))
print(iso) # 2021-09-28 00:08:10+09:00

## 時差を反映したくない場合は、一度タイムゾーンを削除する
iso = parse("2021-09-27T15:08:10Z") # UTC
iso = iso.replace(tzinfo=None) # タイムゾーンを削除
iso = iso.astimezone(datetime.timezone(datetime.timedelta(hours=9)))
print(iso) # 2021-09-27 15:08:10+09:00

timezoneを確認/設定/削除する方法を紹介しました。注意点としてはastimezoneでタイムゾーンを変更する場合、変更前のdatetimeにタイムゾーンが設定されていると時差が考慮され時間が変更することです。それを避けたい場合はコードにある通り一度タイムゾーンを削除しましょう。

pytzを用いたタイムゾーンの設定

pytzを用いることで、'Asia/Tokyo'のように分かりやすい表現でタイムゾーンを設定できます。

iso = parse("2021-09-27T15:08:10Z") # UTC

jst = iso.astimezone(pytz.timezone('Asia/Tokyo'))
est = iso.astimezone(pytz.timezone('US/Eastern'))

print(jst) # 2021-09-28 00:08:10+09:00
print(est) # 2021-09-27 11:08:10-04:00

DataFrameでdatetimeを扱う

PandasのDataFrameでdatetime型へ変換する方法を2つ紹介します。

datetime型への変換: to_datetime

1つ目は、日付や日時を文字列として持つDataframeに対して変換する場合です。

import pandas as pd

# サンプルデータの用意
df_time = pd.DataFrame({'datetime':['2014-10-10', '2014-10-11', '2014-10-12']})
display(df_time)

#   datetime
# 0	2014-10-10
# 1	2014-10-11
# 2	2014-10-12

# datetime型へ変換
df_time['datetime'] = pd.to_datetime(df_time['datetime'])

# dtypeを確認
print(df_time.dtypes)

# datetime    datetime64[ns]
# dtype: object

pandas.to_datetimeに変換したいカラムを指定することで変換ができます。
2つ目が、year, month, dayのカラムをもつDataFrameに日付を追加する方法です。以下の例をご覧ください。

# サンプルデータ
display(df_date)

# year	month	day
# 0	2019	1	  1
# 1	2019	1	  2
# 2	2019	1	  3
# 3	2019	1	  4
# 4	2019	1	  5

## year, month, dayカラムをもつDataFrameを変換する。
df_date['datetime'] = pd.to_datetime(df_date)

display(df_date)

# 	year	month	day	datetime
# 0	2019	1	     1	2019-01-01
# 1	2019	1	     2	2019-01-02
# 2	2019	1	     3	2019-01-03
# 3	2019	1	     4	2019-01-04
# 4	2019	1	     5	2019-01-05

pd.to_datetimeにyear, month, dayカラムを持つDataFrameを渡すと自動的に日付を作成してくれます。

DataFrameで年月日、時刻、曜日、現在時刻の取得: dt

dtアクセサを用いることで、DataFrame(厳密にはSeries)でも年月日や曜日などの情報を取得できます。
以下のサンプルコードでは曜日を取得し、元のDataFrameに追加しています。

# 曜日を追加
df_date['dayofweek'] = df_date['datetime'].dt.dayofweek # 月曜: 0, 日曜:6

# 	year	month	day	datetime	dayofweek
# 0	2019	1	    1	 2019-01-01	 1
# 1	2019	1	    2	 2019-01-02	 2
# 2	2019	1	    3	 2019-01-03	 3
# 3	2019	1    	4	 2019-01-04	 4
# 4	2019	1	    5	 2019-01-05	 5

dtアクセサで取得できる情報はこちらのリファレンスから確認できます。

リファレンス: pandas.Series.dt.date

時系列特徴量を追加

ここまで紹介してきた内容をもとに時系列の特徴量を追加するコードを紹介します。
年/月/日のデータが与えられた際に、曜日/週末/季節/祝日といった時系列に依存した汎用的な特徴量を追加します。

曜日/週末/季節を追加

以下のサンプルコードを実行すると、曜日/週末/季節のカラムが追加されます。

# datetimeの追加
if 'datetime' not in df.keys():
    df['datetime'] = pd.to_datetime(df)

# 曜日(dayofweek)の追加
# Monday: 0 - Sunday: 6
if 'dayofweek' not in df.keys():
    df['dayofweek'] = df['datetime'].dt.dayofweek

# 週末(weekend)の追加
begin_weekend = 5 # 週末の定義。土曜日以降を週末とする
if 'weekend' not in df.keys():
    df['weekend'] = np.where(df['dayofweek'] >= begin_weekend, 1, 0)

# 季節(season)の追加
spring = [3,4,5]
summer = [6,7,8]
fall = [9,10,11]
winter = [12,1,2]
seasons = [spring, summer, fall, winter]

def which_season(month):
    for idx, season in enumerate(seasons):
        if month in season:
            return idx

    raise Exception("No season is match")

if 'season' not in df.keys():
    df['season'] = df['month'].apply(which_season)

国別の祝日を取得

国別の祝日情報を得るには、holidaysライブラリが便利です。pipで簡単にインストールできます。
ここではholidaysライブラリを使用して日本の祝日かどうか判定するカラム"national holiday"を追加します。

# holidays ライブラリを使って祝日を追加
import holidays

jp_holidays = holidays.JP() # 日本の祝日情報を取得
if 'national holiday' not in df.keys():
    df['national holiday'] = df['datetime'].apply(lambda x: int(x in jp_holidays))

当然日本以外の祝日データも取得できます。

us_holidays = holidays.US() # 米国の祝日
uk_holidays = holidays.UK() # イギリスの祝日
cn_holidays = holidays.CN() # 中国の祝日

カスタムした祝日を追加

国民の祝日以外にも、正月三が日のように特別な日を祝日として追加したいことがあると思います。その場合はベースとなる国祝日にカスタムの祝日を追加できます。
以下のサンプルコードでは日本の祝日をベースにカスタムの祝日(1/2, 2/3)を追加しています。

# カスタム祝日を追加する方法
class CorporateHolidays(holidays.JP): # 日本の祝日をベース
    def _populate(self, year):
        # 祝日を追加
        self[datetime.date(year, 1, 2)] = "Some Federal Holiday"
        self[datetime.date(year, 2, 3)] = "Another Federal Holiday"

custom_holiday = CorporateHolidays()
if 'custom holiday' not in df.keys():
    df['custom holiday'] = df['datetime'].apply(lambda x: int(x in custom_holiday))

ここまで実行すると曜日/週末/季節/祝日を追加したデータができます。

画像に alt 属性が指定されていません。ファイル名: image-1-1024x207.png

特徴量を追加するコードまとめ

最後に特徴量を追加するコードをパイプラインとしてまとめておきました。

class CorporateHolidays(holidays.JP):
    def _populate(self, year):
        # Populate the holiday list with the default US holidays
        # holidays.JP._populate(self, year)

        # 祝日を追加
        self[datetime.date(year, 1, 2)] = "Some Federal Holiday"
        self[datetime.date(year, 2, 3)] = "Another Federal Holiday"

def which_season(month):
    spring = [3,4,5]
    summer = [6,7,8]
    fall = [9,10,11]
    winter = [12,1,2]
    seasons = [spring, summer, fall, winter]

    for idx, season in enumerate(seasons):
        if month in season:
            return idx

    raise Exception("No season is match")


def pipeline_date_feature(df:pd.DataFrame) -> pd.DataFrame:
    """ 時系列の特徴量(曜日/週末/季節/祝日)を追加

    Args:
        df (pd.DataFrame): year, month, dayカラムをもつDataFrame

    Returns:
        pd.DataFrame: datetime, dayofweek, weekend, season, national holiday, custom holiday カラムを追加したDataFrame
    """
    if 'datetime' not in df.keys():
        df['datetime'] = pd.to_datetime(df)

    # 曜日(dayofweek)の追加
    # Monday: 0 - Sunday: 6
    if 'dayofweek' not in df.keys():
        df['dayofweek'] = df['datetime'].dt.dayofweek

    # 週末(weekend)の追加
    begin_weekend = 5 # 週末の定義。土曜日以降を週末とする
    if 'weekend' not in df.keys():
        df['weekend'] = np.where(df['dayofweek'] >= begin_weekend, 1, 0)

    # 季節(season)の追加
    if 'season' not in df.keys():
        df['season'] = df['month'].apply(which_season)

    # 日本の祝日(national holiday)を追加
    jp_holidays = holidays.JP()
    if 'national holiday' not in df.keys():
        df['national holiday'] = df['datetime'].apply(lambda x: int(x in jp_holidays))

    # カスタムの祝日(custom holiday)を追加
    custom_holiday = CorporateHolidays()
    if 'custom holiday' not in df.keys():
        df['custom holiday'] = df['datetime'].apply(lambda x: int(x in custom_holiday))

    return df

関連記事/参考リンク

【pathlib】Pythonのパス操作: 参照/変更、パスの検索、ファイル操作

6 Python datetime libraries

datetime --- 基本的な日付型および時間型

The post 【datetime】pythonで日付/時刻を処理するdatetime型を扱う方法 first appeared on .]]>
https://note-tech.com/python-datetime/feed/ 0
【pathlib】Pythonのパス操作: 参照/変更、パスの検索、ファイル操作 https://note-tech.com/python_pathlib/?utm_source=rss&utm_medium=rss&utm_campaign=python_pathlib https://note-tech.com/python_pathlib/#respond Tue, 22 Feb 2022 01:52:27 +0000 https://note-tech.com/?p=1241 pathlibはPython3.4で標準搭載された、Pythonでファイルやディレクトリのパスを参照、検索、作成などの操作をするライブラリです。パス操作は特定のタスクに限らず頻繁に使われるので、基本的な使い方を抑えておく […]

The post 【pathlib】Pythonのパス操作: 参照/変更、パスの検索、ファイル操作 first appeared on .]]>
pathlibはPython3.4で標準搭載された、Pythonでファイルやディレクトリのパスを参照、検索、作成などの操作をするライブラリです。
パス操作は特定のタスクに限らず頻繁に使われるので、基本的な使い方を抑えておくことで仕事効率を向上できます。

pathlibの頻出機能

pathlibはPython3.4で標準搭載されているため、利用にあたってインストールの必要はなく、importしてすぐに利用できます。
ここでは、パスの探索/変更及び検索方法が一目でわかるように、一覧でよく使う機能を紹介します。

パスの参照/変更

ファイルバスとして、"/top_dir/data/001.png"を例としてpathlibの機能を説明します。

from pathlib import Path

file_path = Path('/top_dir/data/001.png') # pathlibオブジェクトでパスを取得
dir_path = file_path.parent # ファイルの親ディレクトリのパス(/top_dir/data/)
実行形式結果説明
file_path.name001.pngファイル名を取得
file_path.stem001拡張子を除いたファイル名
file_path.suffix.png拡張子を取得
file_path.with_name(name)/top_dir/data/aaa.jpg
※ name=aaa.jpgとした場合
file_pathからname部分を変更
file_path.with_stem(stem)/top_dir/data/bbb.png
※ stem=bbbとした場合
file_pathからstem部分を更新
file_path.with_suffix(suffix)/top_dir/data/001.json
※ suffix=.jsonとした場合
file_pathからsuffix部分を更新
file_path.parent/top_dir/data親ディレクトリのパスを取得
file_path.parents[num]/top_dir
num=1の場合
numで指定した分の親ディレクトリのパスを取得
parets[0]はparent同じ結果になる。
file_path.relative_to(path)data/001.png
path=/top_dir/とした場合
pathからの相対パスを取得
file_path.resolve()/top_dir/data/001.png
※ Path('001.png').resolve()の実行結果
file_pathを絶対パスへ変換
dir_path.joinpath(name1, name2,…)/top_dir/data/AAA/BBB
※ joinpath('AAA', 'BBB')とした場合
指定したnameを繋げたパスを作成

リファレンス: pathlib --- オブジェクト指向のファイルシステムパス

パスの一覧取得/検索

ここでは以下のディレクトリ構成を例として、パスの一覧取得(iterdir)、検索(glob)の概要を紹介します。

 top_dir 
 ├── config.yaml
 ├── data
 │       ├── 001.png
 │       ├── 002.png
 │       ├── 003.yaml
 │       └── sample.txt
 ├── readme.md
 └── src
           ├── lib
           │   └── utils.py
           └── main.py 
機能説明
Path.iterdir()ディレクトリ直下のパス一覧をイタレータとして取得。
注: Pathはディレクトリである必要がある
Path.glob(pattern)patternに一致するパスを検索する。
patternには正規表現も利用可
Path.rglob(pattern)patternに一致するパスを再起的に検索する。
globに"**/"を付けて場合と同じ。

パスの一覧を取得: Path.iterdir()

Path.iterdir()は、指定されたパス直下のファイル/ディレクトリの一覧をイタレータとして取得します。
注意点として、iterdirではサブディレクトリまでは取得されない点です。(data配下は取得されていません。)
サブディレクトリまで取得したい場合は、後述のPath.glob()を用います。

top_dir = Path('./top_dir') # top_dirのパスを取得
print(type(top_dir.iterdir())) # <class 'generator'>

for文を使ってイタレータを出力してみます。

# iterdirの参照
for path in top_dir.iterdir():
    print(path)

### 実行結果
# top_dir/config.yaml
# top_dir/readme.md
# top_dir/data
# top_dir/src

top_dir直下のファイル/ディレクトリが参照されているのが分かります。

iterdirは、Pathがファイルを指している場合はNotADirectoryErrorとなります。

config_file = Path('./top_dir/config.yaml')
for path in config_file.iterdir():
    print(path)

### 実行結果
# NotADirectoryError: [Errno 20] Not a directory: 'top_dir/config.yaml'

パスの検索: Path.glob()

Path.glob()は、指定したパターンに一致するパスを検索します。検索には任意の文字列を意味するアスタリスク(*)などのワイルドカードが利用できます。また、iterdirと異なりサブディレクトリ配下を含めた再起的な検索も可能です。

top_dir = Path('./top_dir') # top_dirのパスを取得

# top_dir直下の全てのファイル/ディレクトリを検索
for path in top_dir.glob('*'):
    print(path)

### 実行結果
# top_dir/config.yaml
# top_dir/readme.md
# top_dir/data
# top_dir/src

サブディレクトリも含めて検索したい場合は、検索パターンに"**/"を追加します。
もしくはglobの代わりにrglobを用いても同じ結果が得られます。

# top_dir以下の.pngファイルを再起的に検索
for path in top_dir.glob('**/*.png'): # top_dir.rglob('*.png')でも同じ
    print(path)

### 実行結果
# top_dir/data/002.png
# top_dir/data/001.png

検索結果をリストとして取得したい場合は、内包表記が使えます。
また、検索結果をソートして取得したい場合は組み込み関数のsortedが使えます。

list_png = [path for path in top_dir.glob('**/*.png')] # .pngファイルのリスト
print(list_png)

### 実行結果
# [PosixPath('top_dir/data/002.png'), PosixPath('top_dir/data/001.png')]

# 昇順にソートする場合
sorted(list_png) # 降順にする場合は、reverse=Trueを指定。

### 実行結果
[PosixPath('top_dir/data/001.png'), PosixPath('top_dir/data/002.png')]

ファイルやディレクトリのみを検索したい場合は、Path.is_file(), Path.is_dir()が使えます。

list_file = [path for path in top_dir.glob('**/*') if path.is_file()] # ファイルのみ
print(list_file)

### 実行結果
# [PosixPath('top_dir/config.yaml'), PosixPath('top_dir/readme.md'), 〜〜略〜〜 PosixPath('top_dir/src/lib/utils.py')]

list_dir = [path for path in top_dir.glob('**/*') if path.is_dir()] # ディレクトリのみ
print(list_file)

### 実行結果
# [PosixPath('top_dir/data'), PosixPath('top_dir/src'), PosixPath('top_dir/src/lib')]

ファイルを開く:Path.open()

ファイルを開くときはopenメソッドが使えます。使い方は、組み込み関数のopenと同じように読み込み/書き込みのモードを指定して使います。

# ファイル操作
sample_file = Path('./top_dir/data/sample.txt')

# ファイルへ書き込み
with sample_file.open('w') as f:
    f.write('hello pathlib world\n')

# ファイルを読み込み
with sample_file.open('r') as f:
    buf = f.read()

print(buf) # 実行結果: hello pathlib world

存在しないファイルを開こうとするとFileNotFoundErrorとなるため、ファイルが存在する場合だけopenしたいときはexistsメソッドが使えます。existsメソッドはPathが既存のファイルかディレクトリを指している場合にTrueを返します。
existsメソッドを使って、ファイルが存在する場合だけopenを実行する方法は次のとおりです。

sample_file = Path('./top_dir/data/not_exists_file.txt')

if sample_file.exists(): # ファイルが存在する場合
    with sample_file.open('r') as f:
        buf = f.read()

    print(buf)

参考リンク

The post 【pathlib】Pythonのパス操作: 参照/変更、パスの検索、ファイル操作 first appeared on .]]>
https://note-tech.com/python_pathlib/feed/ 0
【OpenCV】直線/白線を検出する方法【自動運転】 https://note-tech.com/white_line_detect/?utm_source=rss&utm_medium=rss&utm_campaign=white_line_detect https://note-tech.com/white_line_detect/#respond Sat, 05 Feb 2022 07:26:53 +0000 https://note-tech.com/?p=1212 OpenCVを用いた直線を検出する方法を紹介します。 直線検出を行う画像は、走行中の車から見える景色を用います。この画像の特徴は、走行時と同じく道路をまっすぐ見た画像であることと、中央に点線が含まれるところがポイントです […]

The post 【OpenCV】直線/白線を検出する方法【自動運転】 first appeared on .]]>
OpenCVを用いた直線を検出する方法を紹介します。

直線検出を行う画像は、走行中の車から見える景色を用います。この画像の特徴は、走行時と同じく道路をまっすぐ見た画像であることと、中央に点線が含まれるところがポイントです。
ただし、今回紹介する手法は白線に限らず、一般的な画像の直線検出にも応用できる内容になっています。

白線検出までの流れ

次のステップに従って白線を検出していきます。

  1. ガウシアンフィルタ(cv2.GaussianBlur)を用いた平滑化
  2. (option)指定した色でフィルタリング(cv2.inRange)
  3. エッジ検出(cv2.Canny)
  4. (option)領域選択
  5. ハフ変換を用いた直線検出(cv2.HoughLinesP)

optionとなっている2番と4番は車における白線検出用の処理なので、一般的な直線検出の場合は不要です。

また今回使用する道路の画像はこちらのフリー写真をお借りしました。

1. ガウシアンフィルタ(cv2.GaussianBlur)を用いた平滑化

初めに画像にガウシアンフィルタを適用し、平滑化することでノイズとなる成分を除去します。

img = cv2.imread('./road.jpg') # 道路の画像を読み込み
blur_img = cv2.GaussianBlur(img, (3,3), 0) # ガウシアンフィルタ
  • cv2.GaussianBlur
    • 第2引数: カーネル(フィルタ)サイズ。奇数である必要がある。
    • 第3引数: ガウシアンの標準偏差値。0指定で自動的に計算されるため、基本は0で良い。

フィルタをかけると僅かにぼやけた画像が生成され、ドットのようなノイズ成分が弱まります。
フィルタの強さはカーネルサイズで変更できますが、強くしすぎると必要な情報も落ちてしまうので用途に合わせた調整が必要です。

2. (option)指定した色でフィルタリング(cv2.inRange)

次に色情報を活用して画像をフィルタリングします。検出したい直線の色が特定の範囲に収まっている場合は、この手法によりノイズの除去ができます。
検出したい直線の色が定まっていない場合は、この手法は使えないのでスキップしてください。

# カラーコード(180,180,180) ~ 白(255,255,255)を抽出
bin_blur_img = cv2.inRange(blur_img, (180,180,180), (255,255,255)) # 抽出する色の範囲を選択する
  • cv2.inRange
    • 第2引数: 下限値を指定
    • 第3引数: 上限値を指定
    • 返り値: 入力と同じサイズかつCV_8Uタイプの2値化(0 or 255)されたndarray。

RGB(180,180,180) ~ (255,255,255)の範囲の色情報をでフィルタリングした結果は次のとおりです。
白に近い値(180以上)だけが抽出されているのがわかります。

3. エッジ検出(cv2.Canny)

エッジの検出にはcv2.Cannyを使います。Cannyエッジ検出は2つの閾値を用い、エッジの検出を行います。

# エッジ検出
edges = cv2.Canny(img, minVal=150, maxVal=250)
  • cv2.Canny
    • minVal: エッジと見なす最小値となる閾値。この値を下回る場合はエッジと見なさない。
    • maxVal: エッジと見なす最大値となる閾値。この値を上回る場合はエッジと見なす。最小値と最大値の間にくる値は、それが最大値を上回るエッジと接続されている場合はエッジと見做される。

検出されるエッジは、minVal, maxValの値によって大きく変わるため、cv2.Cannyを用いる場合パラメータの調整は重要です。
Cannyエッジ検出の詳細はこちらのリファレンスが参考になります。
リファレンス: Canny Edge Detection

4. (option)領域選択

次に検出したい画像領域を選択します。これは車で白線検出する際に用いられる処理のため、画像全体から直線を検出したい場合はスキップしてください。
車に取り付けたカメラから白線を検出する状況では、白線が映る領域はおおよそアタリがつきます。具体的には、画像の上半分は遠くの景色を写しているので白線検出においてその範囲のエッジ情報はノイズとなるため不要です。

領域選択には、多角形の領域内を塗り潰すcv2.fillPolyと、重複する領域をピクセル単位で取得するcv2.bitwise_andを使用します。

# 画像shapeに対する取得領域(4点)を、縦横の比率で指定
imshape = np.array(edges.T.shape).T # 画像のshape(W, H)
left_bottom = imshape * np.array([0,0.8]) # 左下の座標
left_top = imshape * np.array([0.3, 0.3]) # 左上の座標
right_top = imshape * np.array([0.7, 0.3]) # 右上の座標
right_bottom = imshape * np.array([1, 0.8]) # 右下の座標
region_coord = np.array([[left_bottom, left_top, right_top, right_bottom]], dtype=np.int32) # 先行車領域の座標4点(左下から時計回り)

# マスク画像の作成
mask = np.zeros_like(edges)
cv2.fillPoly(mask, region_coord, color=255)

作成したマスク画像と、3.で検出したエッジ画像の重複部分を取得します。

masked_edges = cv2.bitwise_and(edges, mask)

背景となる画像の上半分の情報が削除され、必要な白線部分の情報が取得できています。

5. ハフ変換を用いた直線検出(cv2.HoughLinesP)

最後に直線検出を行います。直線検出は、エッジ検出画像に対してcv2.HoughLinesPを適用することで実現できます。

# cv2.HoughLinesPによる直線検出
lines = cv2.HoughLinesP(masked_edges, rho, theta, threshold, np.array([]), minLineLength=min_line_len, maxLineGap=max_line_gap)
  • cv2.HoughLinesP
    • threshold: 直線を検出するための交点の最小数
    • minLineLength: 検出する直線の最小の長さ
    • maxLineGap: 2つの直線を1つの直線と見なす際に許容する最大ギャップ
    • rho: パラメータ$rho$のピクセル単位の解像度。基本は1。
    • theta: パラメータ$theta$のラジアン単位の解像度。基本はnp.pi/180。

cv2.HoughLinesPを用いる際は、min_line_lenおよびmax_line_gapが重要なパラメータです。
点線も一つの直線として検出したい場合はmax_line_gapの値を大きくすることで、短い直線も検出したい場合は、min_line_lenを小さくすることで、より幅広く直線を検出できます。
ただし、どちらも適切に設定しないと不要なエッジも直線として検出されてしまうので注意が必要です。

cv2.HoughLinesPによる直線検出の原理についてより詳しく知りたい方は下記のチュートリアルが分かりやすいので、ご参照ください。
チュートリアル: ハフ変換による直線検出

検出した直線を、画像に描画して、元画像と重ね合わせた結果は次のとおりです。

# 直線をimgに描画する関数
def draw_ext_lines(img, lines, color=[255, 0, 0], thickness=2):
    d = 300 # required extend length
    for line in lines:
        for x1,y1,x2,y2 in line:
            if (x2 != x1):
                slope = (y2-y1)/(x2-x1)
                sita = np.arctan(slope)
                if (slope > 0): # 傾きに応じて場合分け
                    if (x2 > x1):
                        x3 = int(x2 + d*np.cos(sita))
                        y3 = int(y2 + d*np.sin(sita))
                        cv2.line(img, (x3, y3), (x1, y1), color, thickness)
                    else:
                        x3 = int(x1 + d*np.cos(sita))
                        y3 = int(y1 + d*np.sin(sita))
                        cv2.line(img, (x3, y3), (x2, y2), color, thickness)
                elif (slope < 0):
                    if (x2 > x1):
                        x3 = int(x1 - d*np.cos(sita))
                        y3 = int(y1 - d*np.sin(sita))
                        cv2.line(img, (x3, y3), (x2, y2), color, thickness)
                    else:
                        x3 = int(x2 - d*np.cos(sita))
                        y3 = int(y2 - d*np.sin(sita))
                        cv2.line(img, (x3, y3), (x1, y1), color, thickness)

line_img = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)

# 直線が検出された場合は画像に描画する
if (not isinstance(lines,type(None))):
    draw_ext_lines(line_img, lines) # 自作の直線描画関数

overlay_img = cv2.addWeighted(img, a=0.6, line_img, b=1, c=0) # 元画像に直線画像を重ね合わせ

以上で、中央にある点線も含めて全ての白線が検出できました。

参考リンク

白線検出について参考になるリンクをまとめておきます。

The post 【OpenCV】直線/白線を検出する方法【自動運転】 first appeared on .]]>
https://note-tech.com/white_line_detect/feed/ 0
【Python】scikit-learnによる正規化/標準化/スケーリングの実装方法 https://note-tech.com/python_scaling_standardize/?utm_source=rss&utm_medium=rss&utm_campaign=python_scaling_standardize https://note-tech.com/python_scaling_standardize/#respond Sun, 21 Nov 2021 05:32:45 +0000 https://note-tech.com/?p=1167 機械学習を行う際、学習や予測に用いるデータの統計的性質は近しい方が学習効率や予測精度が良くなる傾向があります。この記事では、scikit-learnを用いた標準化及びスケーリングの実装方法を紹介します。 正規化/標準化/ […]

The post 【Python】scikit-learnによる正規化/標準化/スケーリングの実装方法 first appeared on .]]>
機械学習を行う際、学習や予測に用いるデータの統計的性質は近しい方が学習効率や予測精度が良くなる傾向があります。この記事では、scikit-learnを用いた標準化及びスケーリングの実装方法を紹介します。

正規化/標準化/スケーリングという言葉は、サイトによって色んな意味で使われがちですので、初めに言葉の認識を合わせておきます。

  • 標準化(Standardize)
    • 分布の標準偏差が1になるようにデータを変換すること
  • スケーリング(Scale)
    • データが分布する範囲を変換すること。
      分布の形状は変化しない。0〜1の範囲に変換することが多い。
  • 正規化(Normalize)
    • 標準化やスケーリングの両方を指していることが多い。曖昧さ回避のため本記事では用いない。

参考リンク: Scale, Standardize, or Normalize with Scikit-Learn

スケーリング

MinMaxScaler:

MinMaxScalerは、データを指定した範囲(デフォルトでは0〜1の範囲)に収まるようにスケーリングします。範囲が変換されるだけなので、分布rの形状は変わりません。また、スケーリングは列単位で実行されます。

from sklearn.preprocessing import MinMaxScaler

data = np.array([[1,2,3], 
                [4,5,6], 
                [7,8,9]])

scaler = MinMaxScaler()
scaler.fit(data)

scaler.transform(data)
# array([[0. , 0. , 0. ],
#        [0.5, 0.5, 0.5],
#        [1. , 1. , 1. ]])

リファレンス: sklearn.preprocessing.MinMaxScaler

MinMaxScalerは直接データ全体への一括した適用や、1次元配列に対して適用することはできません。
もしデータ全体や、1次元配列への適用を行いたい場合は、reshapeを活用することで実現できます。

### データ全体へ適用
data = np.array([[1,2,3], 
                [4,5,6], 
                [7,8,9]])
data_one_column = data.reshape([-1,1])

scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(data_one_column)
scaled_data.reshape(data.shape)

# array([[0.   , 0.125, 0.25 ],
#        [0.375, 0.5  , 0.625],
#        [0.75 , 0.875, 1.   ]])


### 1次元配列への適用
data = np.array([1,2,3,4,5]).reshape([-1,1])
print(data.shape)
# (5, 1)

scaler = MinMaxScaler()
scaler.fit_transform(data)
# array([[0.  ],
#        [0.25],
#        [0.5 ],
#        [0.75],
#        [1.  ]])

参考: How to use MinMaxScaler on all columns?

参考: Python/sklearn - preprocessing.MinMaxScaler 1d deprecation

MaxAbsScaler

MaxAbsScalerは、各列毎のデータが [-1〜1]の範囲内に収まるようにスケーリングされます。
このスケーリングは列毎の絶対値の最大値で除算することで実現されます。

from sklearn.preprocessing import MaxAbsScaler

data = np.array([[5, 10, 3], 
                 [0, 5, -6], 
                [-10, -1, -3]])

scaler = MaxAbsScaler()
scaler.fit_transform(data)
# array([[ 0.2,  1. ,  0.5],
#        [ 0. ,  0.4, -1. ],
#        [-1. , -0.1, -0.5]])

リファレンス: sklearn.preprocessing.MaxAbsScaler

RobustScaler

RobustScalerは、中央値と四分位範囲を用いたスケーリングを行います。
元データに外れ値が含まれている場合、これまで紹介したスケーリング手法や、平均/分散を用いた標準化手法では上手く機能しないことがあります。そのような場合はRobustScalerを用いるとよりロバストな変換が可能です。

四分位範囲とは、データを昇順にソートしデータ数で4等分した際に、中央にくる2つを合わせた範囲。4等分した際の区切りを四分位数と呼ぶ。

from sklearn.preprocessing import RobustScaler
data = np.array([[0, 0, 1], 
                 [0, 0, 3], 
                [100, 10, 5],
                [100, 10, 7],
                [100, 100, 9]])

scaler = RobustScaler()
scaler.fit_transform(data)
# array([[-1. , -1. , -1. ],
#        [-1. , -1. , -0.5],
#        [ 0. ,  0. ,  0. ],
#        [ 0. ,  0. ,  0.5],
#        [ 0. ,  9. ,  1. ]])

RobustScalerでは、データの中央値を減算し、四分位範囲で除算することでスケーリングします。そのためスケーリングの範囲は固定ではなくデータに依存します。

リファレンス: sklearn.preprocessing.RobustScaler

標準化

StandardScaler

StandardScalerは、データを平均0、分散1となるように標準化します。
数式で表現すると次の通りです。

$$z = \frac{x - u}{s}$$

ここで、$z$は変換後の値、$u$は平均、$s$は標準偏差です。

data = np.array([[2, 10, 3], 
                 [0, 4, -6], 
                [-10, -1, -3]])
                
scaler = StandardScaler()
scaler.fit_transform(data)
# array([[ 0.88900089,  1.26012384,  1.33630621],
#        [ 0.50800051, -0.07412493, -1.06904497],
#        [-1.3970014 , -1.18599891, -0.26726124]])

0を中心とするように値が変換されているのが分かります。

非線形変換

ここまで紹介したスケーリングや標準化はデータの範囲を変換しますが、分布の形状は変化させない方法でした。記事の冒頭でも述べましたが、データの統計的性質は近いことで分析精度が上がることがあります。そこで、ここでは正規分布ではないデータを正規分布に近づける変換手法として、Box-Cox変換Yeo-Johnson変換を紹介します。

Box-Cox変換

Box-Cox変換は、以下の式で表されます。

$x_{\lambda} = \begin{cases} \frac{x^{\lambda}-1}{\lambda} & {\rm if} \quad \lambda \neq 0 \\
\log x & {\rm if} \quad \lambda =0
\end{cases}
$

Box-Cox変換のポイントは、次の通りです。

  • パラメータ$\lambda$が用意されており、scikit-learnでは特徴毎に歪度を小さくする$\lambda$が自動で選択される
  • 正のデータにしか使用できない
    • 負の値を含むデータを扱う場合は、絶対値を取った後に変換を行い、元の符号を付けるなどの工夫が必要

対数正規分布に従う乱数をBox-Cox変換した例を記載します。

from sklearn.preprocessing import PowerTransformer

data = np.random.lognormal(0, 1, 1000) # 対数正規分布に従う乱数

# Box-Cox変換
pt = PowerTransformer(method='box-cox', standardize=False)
box_cox = pt.fit_transform(data.reshape(-1,1))

# ヒストグラムで変換結果を確認
fig, ax = plt.subplots(1,2, figsize=(12,6))
fig.suptitle('Histogram', fontsize=24, color='black')
n_bins = 100

ax[0].hist(var, bins=n_bins, density=True) # density=Trueを追加すると確率密度になる。
ax[0].set_title('Lognormal')

ax[1].hist(box_cox, bins=n_bins, density=True)
ax[1].set_title('Box-Cox')

plt.show()

リファレンス: sklearn.preprocessing.PowerTransformer

対数正規分布のデータ(左)に、Box-Cox変換を適用(右)することで、データの分布が正規分布に近づいていることが確認できます。

Yeo-Johnson変換

負の値を含むデータにも対応できるようにしたのが、Yeo-Johnson変換です。
Yeo-Johnson変換は次の式で表されます。一見複雑ですが、負の値を扱えるように場合分けが増えている以外はBox-Cox変換と非常に似ています。

$
x_{\lambda} =
\begin{cases}
[(x+1)^{\lambda}-1]/\lambda & {\rm if} \quad \lambda \neq 0, x \geq 0 \\
\ln(x+1) & {\rm if} \quad \lambda = 0, x \geq 0 \\
-[(-x+1)^{2 - \lambda}-1]/(2 - \lambda) & {\rm if} \quad \lambda \neq 2, x \lt 0 \\
-\ln(-x+1) & {\rm if} \quad \lambda = 2, x \lt 2 \\
\end{cases}
$

from sklearn.preprocessing import PowerTransformer

data = np.random.lognormal(0, 1, 1000) # 対数正規分布に従う乱数

# Yeo-Johnson変換
pt = PowerTransformer(method='yeo-johnson', standardize=False)
yeo_johnson = pt.fit_transform(data.reshape(-1,1))

リファレンス: sklearn.preprocessing.PowerTransformer

まとめ 

 機械学習を行う際に欠かせない要素となる標準化や、スケーリングをPythonで実装する方法について紹介しました。各手法に向いているタスクやデータセットがあるので、やりたいことに合わせ各手法を選択できると良い思います。例えば、画像処理では0~255の範囲にスケーリングすることが多いのでMinMaxScalingを使う、外れ値の影響を低減したい場合はRobustScalerを使うなどです。

 最後に、機械学習の精度向上する際のポイントがまとまっている書籍「Kaggleで勝つデータ分析の技術」を紹介したいと思います。この本では、日本を代表するようなTop Kagglerの方々がコンペで通用するデータ分析の手法を、コンペでの実績を踏まえて解説/紹介してくれています。この記事で紹介した標準化や、スケーリング以外にも様々な手法が紹介されているので、データ分析精度を向上させたい方は持っておいて損は1冊だと思います。

参考リンク

scikit-learn: 6.3.1. Standardization, or mean removal and variance scaling

The post 【Python】scikit-learnによる正規化/標準化/スケーリングの実装方法 first appeared on .]]>
https://note-tech.com/python_scaling_standardize/feed/ 0
【テーブルデータ】pythonにおける定番の前処理【欠損値/型変換/結合】 https://note-tech.com/table_preprocess_summary/?utm_source=rss&utm_medium=rss&utm_campaign=table_preprocess_summary https://note-tech.com/table_preprocess_summary/#respond Sat, 06 Nov 2021 01:47:52 +0000 https://note-tech.com/?p=1115 PandasのDataFrameとScikit-Learnを用いたテーブルデータの前処理を紹介します。具体的には、以下の処理について順番に紹介していきます。 テーブルの結合: pd.DataFrame.merge pd. […]

The post 【テーブルデータ】pythonにおける定番の前処理【欠損値/型変換/結合】 first appeared on .]]>
PandasのDataFrameとScikit-Learnを用いたテーブルデータの前処理を紹介します。
具体的には、以下の処理について順番に紹介していきます。

テーブルの結合: pd.DataFrame.merge

pd.DataFrame.mergeメソッドでは特定の列をキーとして、基準となるDataFrameに別のDataFrameを結合します。

リファレンス:pandas.DataFrame.merge

ここでは、具体例として売上履歴データ(sales_history)商品カテゴリデータ(categories)を用い、2つのテーブルデータを結合します。

# 売上履歴データ: sales_history
type(sales_history) # pandas.core.frame.DataFrame
print(sales_history)
#           日付  店舗ID  商品ID  商品カテゴリID   商品価格    売上個数
# 0  2021-10-01      1       1             1    10000        2.0
# 1  2021-10-01      1       2             1    20000        NaN
# 2  2021-10-01      1       3             1    15000        1.0
# 3  2021-10-01      1       4             2     1000        3.0
# 4  2021-10-01      1       5             2     5000     9999.0
# 5  2021-10-01      1       6             3     3000        2.0
# 6  2021-10-01      1       7             4     5000        1.0
# 7  2021-10-01      1       8             5     2000        3.0

# 商品カテゴリデータ: categories
type(categories) # pandas.core.frame.DataFrame
print(categoris)
#    商品カテゴリID     商品カテゴリ名
# 0             1  ギフト - ゲーム機
# 1             2   ギフト - 記念品
# 2             3    映画 - DVD
# 3             4  映画 - ブルーレイ
# 4             5     本 - 教育用

結合列の指定: on引数

商品カテゴリIDをキーとして、売上履歴データに商品カテゴリ名を追加します。
キーは引数onで指定できます。

df_data = sales_history.merge(categories, on='商品カテゴリID')

# pd.merge関数を使った以下の記述も可能
# df_data = pd.merge(sales_history, categories, on='商品カテゴリID')

print(df_data)
#            日付  店舗ID  商品ID  商品カテゴリID   商品価格    売上個数     商品カテゴリ名
# 0   2021-10-01      1       1             1    10000        2.0  ギフト - ゲーム機
# 1   2021-10-01      1       2             1    20000        NaN  ギフト - ゲーム機
# 2   2021-10-01      1       3             1    15000        1.0  ギフト - ゲーム機
# 3   2021-10-01      1       4             2     1000        3.0   ギフト - 記念品
# 4   2021-10-01      1       5             2     5000     9999.0   ギフト - 記念品
# 5   2021-10-01      1       6             3     3000        2.0    映画 - DVD
# 6   2021-10-01      1       7             4     5000        1.0  映画 - ブルーレイ
# 7   2021-10-01      1       8             5     2000        3.0     本 - 教育用

売上履歴データに商品カテゴリ名を統合したテーブルデータが作成できました。

結合方法の指定: how引数

引数howでテーブルの結合方法を指定できます。結合方法には、互いのテーブルでカラムが一致する部分を取得する内部結合(inner)と、一致しない部分も取得する外部結合(left, right, outer)、直積(cross)があります。
ここではサンプルデータを用いて、内部結合と外部結合の違い確認していきます。

# サンプルデータ
ages = pd.DataFrame([['Taro', 25], ['Jiro', 20], ['Hanako', 18]], columns=['名前', '年齢'])
birthplace = pd.DataFrame([['Taro', 'Tokyo'], ['Jiro', 'Osaka'], ['Saburo', 'Fukuoka']], columns=['名前', '出身'])

print(ages)
#        名前  年齢
# 0     Taro   25
# 1     Jiro   20
# 2   Hanako   18

print(birthplace)
#        名前       出身
# 0     Taro      Tokyo
# 1     Jiro      Osaka
# 2   Saburo    Fukuoka

内部結合: inner

print(ages.merge(birthplace, on='名前', how='inner'))
#      名前  年齢     出身
# 0   Taro   25    Tokyo
# 1   Jiro   20    Osaka

on引数でキーとして指定した「名前」が、双方のテーブルで一致する「Taro」「Jiro」の行が結合されています。

外部結合: left, right, outer


# 外部結合left
print(ages.merge(birthplace, on='名前', how='left'))

#        名前  年齢     出身
# 0     Taro   25    Tokyo
# 1     Jiro   20    Osaka
# 2   Hanako   18      NaN

外部結合leftでは、agesのキーに該当する値が、birthplaceから追加されます。
そのため、"名前"カラムにはagesテーブルにある要素が表示され、Hanakoの出身はbirthplaceテーブルにないためNaNとなってります。

print(ages.merge(birthplace, on='名前', how='right'))
#        名前    年齢       出身
# 0     Taro   25.0      Tokyo
# 1     Jiro   20.0      Osaka
# 2   Saburo    NaN    Fukuoka

外部結合rightでは、birthplaceのキーに該当する値が、agesから追加されます。
そのため、"名前"のカラムにはbirthplaceテーブルにある要素が表示され、Saburoの年齢はagesテーブルにないためNaNとなっています。

print(ages.merge(birthplace, on='名前', how='outer'))
#        名前    年齢       出身
# 0     Taro   25.0      Tokyo
# 1     Jiro   20.0      Osaka
# 2   Hanako   18.0        NaN
# 3   Saburo    NaN    Fukuoka

外部結合outerでは、agesもしくはbirthrateに存在する要素をキーとして、統合します。
そのため、"名前"のカラムにはいずれかのテーブルに存在する要素が表示され、年齢、出身の情報がない箇所はNaNとなります。

カラムの並べ替え

テーブルデータを統合した後にカラムの並びを変更したい場合は、DataFrameにカラム名のリストを渡せばリストの順番で並べ替わります。

var_xs = ['日付', '店舗ID', '商品ID', '商品カテゴリID', '商品カテゴリ名', '商品価格', '売上個数']
df_data = df_data[var_xs]
print(df_data)
#            日付  店舗ID  商品ID  商品カテゴリID     商品カテゴリ名   商品価格    売上個数
# 0   2021-10-01       1      1             1  ギフト - ゲーム機    10000        2.0
# 1   2021-10-01       1      2             1  ギフト - ゲーム機    20000        NaN
# 2   2021-10-01       1      3             1  ギフト - ゲーム機    15000        1.0
# 3   2021-10-01       1      4             2   ギフト - 記念品     1000        3.0
# 4   2021-10-01       1      5             2   ギフト - 記念品     5000     9999.0
# 5   2021-10-01       1      6             3       映画 - DVD     3000        2.0
# 6   2021-10-01       1      7             4  映画 - ブルーレイ     5000        1.0
# 7   2021-10-01       1      8             5       本 - 教育用     2000        3.0

欠損値の確認/置換/削除

この章では、結合したテーブルデータの概要を確認するメソッドを紹介したのち、欠損値の置換/削除を行います。

統計情報の確認: describe

describeメソッドでは、カラム単位の要素数、平均値、最大/最小値といった統計情報を確認できます。

df_data.describe()

#        店舗ID     商品ID  商品カテゴリID          商品価格         売上個数
# count    8.0    8.00000     8.000000         8.000000        7.000000
# mean     1.0    4.50000     2.375000      7625.000000     1430.142857
# std      0.0    2.44949     1.505941      6802.048011     3778.510925
# min      1.0    1.00000     1.000000      1000.000000        1.000000
# 25%      1.0    2.75000     1.000000      2750.000000        1.500000
# 50%      1.0    4.50000     2.000000      5000.000000        2.000000
# 75%      1.0    6.25000     3.250000     11250.000000        3.000000
# max      1.0    8.00000     5.000000     20000.000000     9999.000000

リファレンス: pandas.DataFrame.describe

簡潔なサマリーを出力: info

infoメソッドでは、カラム名、欠損していないエントリ数、dtypeといった簡潔なサマリーを確認できます。

df_data.info()

# Int64Index: 8 entries, 0 to 7
# Data columns (total 7 columns):
#  #   Column    Non-Null Count  Dtype  
# ---  ------    --------------  -----  
#  0   日付        8 non-null      object 
#  1   店舗ID      8 non-null      int64  
#  2   商品ID      8 non-null      int64  
#  3   商品カテゴリID  8 non-null      int64  
#  4   商品カテゴリ名   8 non-null      object 
#  5   商品価格      8 non-null      int64  
#  6   売上個数      7 non-null      float64

infoメソッドの結果から、テーブルデータは8エントリ(行)あるのに、売上個数は7 non-nullとなっているので、欠損値が1つあることがわかります。

リファレンス: pandas.DataFrame.info

欠損値の確認/欠損率の取得

infoメソッドを用いることで、カラム毎の欠損値数を確認できましたが、
isnullメソッドを用いると、要素毎に欠損値かどうかを判定した結果を得ることができます。

# 欠損値の確認
df_data.isnull()

#  	  日付	 店舗ID	 商品ID	商品カテゴリID	商品価格	売上個数	商品カテゴリ名
# 0	False   False   False        False   False      False           False
# 1	False   False   False        False   False       True           False
# 2	False   False   False        False   False      False           False
# 3	False   False   False        False   False      False           False
# 4	False   False   False        False   False      False           False
# 5	False   False   False        False   False      False           False
# 6	False   False   False        False   False      False           False
# 7	False   False   False        False   False      False           False

これを利用し、カラム毎の欠損率を計算した関数calc_missing_rateを作りました。
任意のDataFrameを渡すとカラム毎の欠損率を降順で返します。

# 欠損率を確認する関数
def calc_missing_rate(df: pd.DataFrame):
    """ データフレームの列毎の欠損率を降順で出力 """
    print((df.isnull().sum()/len(df)).sort_values(ascending=False))

calc_miss_rate(df_data)
# 売上個数        0.125
# 日付           0.000
# 店舗ID         0.000
# 商品ID         0.000
# 商品カテゴリID   0.000
# 商品カテゴリ名   0.000
# 商品価格        0.000

欠損値の削除: dropna

dropnaメソッドでは、欠損値を含む行/列を削除できます。

  • 引数
    • axis:{0 or ‘index’, 1 or ‘columns’}, default 0
      欠損値を含む行を削除するか、列を削除するかを指定
    • how: {‘any’, ‘all’}, default ‘any’
      削除条件を指定。行もしくは列に1つ以上欠損値を含む(any)か、全てが欠損値(all)か
    • thresh: int
      欠損値ではない要素数を閾値として指定。要素数が閾値以下の場合に削除
# 欠損値を1つ以上含む行を削除
df_data.dropna()

# 	       日付	店舗ID	商品ID	  商品カテゴリID  商品価格	   売上個数    商品カテゴリ名
# 0	2021-10-01      1      1             1   10000        2.0   ギフト - ゲーム機
# 2	2021-10-01      1      3             1   15000        1.0   ギフト - ゲーム機
# 3	2021-10-01      1      4             2    1000        3.0   ギフト - 記念品
# 4	2021-10-01      1      5             2    5000     9999.0   ギフト - 記念品
# 5	2021-10-01      1      6             3    3000        2.0   映画 - DVD
# 6	2021-10-01      1      7             4    5000        1.0   映画 - ブルーレイ
# 7	2021-10-01      1      8             5    2000        3.0   本 - 教育用

リファレンス: pandas.DataFrame.dropna

欠損値の置換: fillna

fillnaメソッドでは、欠損値を置換できます。

  • 引数
    • value: scalar, dict, Series, or DataFrame
      置換する値を指定。scalar(数値や文字)を指定すると全ての欠損値がその値で置換される。
      要素毎に置換する値を変更する場合は、辞書やSeriesで指定できる。
    • method: {‘backfill’, ‘bfill’, ‘pad’, ‘ffill’, None}, default None
      欠損値の置換方法決める。'backfill', 'bfill'ではindexの順番に見ていき直前の値で置換する。'pad', 'ffill'ではindexの直後の要素で置換する。

fillnaメソッドを用いて、欠損値を0で置換する方法とカラム毎の中央値で置換する方法は次の通りです。

# 欠損値を0で置換
df_data.fillna(0)

# 欠損値を要素毎の中央値で置換
df_data.fillna(df_data.median())

リファレンス: pandas.DataFrame.fillna

dtypeの変換(キャスト): astype, pandas.to_datetime

astypeメソッドを用いることで、dtypeを変換できます。
また、pandas.to_datetimeを用いると日付データをdatetime型に変換できます。datetime型にしておくと日数計算が容易になり、不当な日付が入らなくなるため便利です。

# np.int64型への変換
df_data['売上個数'] = df_data['売上個数'].astype(np.int64)

# datetime型への変換
df_data['日付'] = pd.to_datetime(df_data['日付'])

df_data.dtypes
# 日付          datetime64[ns]
# 店舗ID                 int64
# 商品ID                 int64
# 商品カテゴリID             int64
# 商品価格                 int64
# 売上個数                 int64
# 商品カテゴリ名             object

datetime型では、年月日や曜日の取得、datetime同士の演算など、日付に関する便利な機能が利用できます。

date = df_data['日付'][0]

print(date)
# 2021-10-01 00:00:00

# %% 年月日時分秒の取得
print(date.year)
print(date.month)
print(date.day)
print(date.hour)
print(date.minute)
print(date.second)
# 2021
# 10
# 1
# 0
# 0
# 0

# 曜日の取得 0(月曜)~6(日曜)
date.weekday()
# 4

datetime型の使い方や便利な機能については別途まとめて記事にする予定です。

カテゴリカル変数の分割

テーブルデータを確認すると「商品カテゴリ名」にはメインカテゴリ(ギフト、英語、本)とサブカテゴリ(ゲーム機、記念品など)が含まれています。
テーブルデータでは、1つのカラムに複数の要素が含まれていることはよくあるため、カラムを分割する関数add_split_categoryを作成しました。

def add_sub_categories(input, main_category, sub_categories, sep='-'):
    """ カテゴリカル変数を複数のサブカテゴリへ分割する
    Args:
        input (DataFrame): 入力
        main_category (str): 分割対象のカラム名
        sub_categories (list): 分割後のカラム名
        sep (str, optional): 区切り文字. Defaults to '-'.

    Returns:
        [DataFrame]: 分割後のカラムを追加したDataFrame
    """
    buf = input[main_category].str.split(sep, expand=True)
    buf.columns = sub_categories
    input = input.join(buf)

    return input

df_data = add_sub_categories(df_data, '商品カテゴリ名', ['メインカテゴリ', 'サブカテゴリ'], sep=' - ')
df_data
#         日付  店舗ID  商品ID  商品カテゴリID     商品カテゴリ名   商品価格  売上個数 メインカテゴリ サブカテゴリ
# 0 2021-10-01      1      1             1  ギフト - ゲーム機    10000        2        ギフト    ゲーム機
# 1 2021-10-01      1      2             1  ギフト - ゲーム機    20000        0        ギフト    ゲーム機
# 2 2021-10-01      1      3             1  ギフト - ゲーム機    15000        1        ギフト    ゲーム機
# 3 2021-10-01      1      4             2   ギフト - 記念品      1000        3        ギフト     記念品
# 5 2021-10-01      1      6             3       映画 - DVD      3000        2         映画       DVD
# 6 2021-10-01      1      7             4  映画 - ブルーレイ      5000        1         映画  ブルーレイ
# 7 2021-10-01      1      8             5       本 - 教育用      2000        3          本     教育用
  • add_sub_categories関数
    • DataFrameにおける特定のカラムを分割する
    • 引数
      • input (pd.DataFrame): 分割対象のカラムを含むDataFrame
      • main_category(str): 分割対象のカラム名
      • sub_categories(list): 分割後のカラム名
      • sep (str, optional): 区切り文字. デフォルトは'-'.
    • 返り値
      • (pd.DataFrame): 分割後のカラムを追加したDataFrame

add_sub_categories関数では、入力したDataFrameに、分割したカラムを追加して値を返します。
上の例では、df_dataのカラム「商品カテゴリ名」を対象に、区切り文字「' - '」で分割し、分割後のカラム名を「'メインカテゴリ', 'サブカテゴリ'」としています。

カテゴリカル変数を数値へ

カテゴリカル変数を数値に変換する様々な手法が提案されていますが、ここではLabelEncoderTargetEncoderについて紹介します。

LabelEncoder: sklearn.preprocessing.LabelEncoder

LabelEncoderは文字列のラベルを、[0 ~ クラス数-1]の数値へ変換します。
scikit-learnのLabelEncodeを利用すると簡単に実現でき、その手順は次のとおりです。

  1. LabelEncoderのインスタンス生成: LabelEncoder()
  2. 変換対象のラベルの種類を定義: fit()メソッド
    • fitメソッドで変換テーブルが作成されます。'ギフト'は'0'にするなど
  3. 変換テーブルに従って、ラベルを数値に変換: transform()メソッド
    • 変換テーブルにないラベルを入力するとValueErrorします。

リファレンス: sklearn.preprocessing.LabelEncoder

from sklearn.preprocessing import LabelEncoder 

le = LabelEncoder() # 
le.fit(df_data['メインカテゴリ']) # ラベルの一覧を定義
encoded_label = le.transform(df_data['メインカテゴリ'])

### LabelEncode前
print(df_data['メインカテゴリ'].values.tolist()) 
# ['ギフト', 'ギフト', 'ギフト', 'ギフト', '映画', '映画', '本']

### LabelEncode後
print(encoded_label)
# [0 0 0 0 1 1 2]

ギフト = 0、映画 = 1、本 = 2とそれぞれエンコードされたことが分かります。
LabelEncoderを機械学習に用いる場合の注意点として、学習データと評価データで同じ具変換されるように「ラベルの一覧」には互いのラベルを含める必要があります。

変換結果を元のDataFrameに代入すれば、LabelEncodeは完了です。

def apply_le(series:pd.Series, labels=[]):
    """ LabelEncoderの適用
    Args:
        input (pd.Series): 変換対象のラベル
        labels (list, optional): ラベルの種類。指定しない場合はinputから生成する。

    Returns:
        [list]: 変換後の値
    """
    le = LabelEncoder()

    if not labels:
        labels = series.unique()

    le.fit(labels)
    encoded_label = le.transform(series)

    return encoded_label

df_data['メインカテゴリ'] = apply_le(df_data['メインカテゴリ'])
df_data['サブカテゴリ'] = apply_le(df_data['サブカテゴリ'])

print(df_data)
#           日付  店舗ID  商品ID  商品カテゴリID     商品カテゴリ名   商品価格  売上個数  メインカテゴリ  サブカテゴリ
# 0  2021-10-01       1      1             1  ギフト - ゲーム機  10000          2            0           1
# 1  2021-10-01       1      2             1  ギフト - ゲーム機  20000          0            0           1
# 2  2021-10-01       1      3             1  ギフト - ゲーム機  15000          1            0           1
# 3  2021-10-01       1      4             2    ギフト - 記念品   1000          3            0           4
# 5  2021-10-01       1      6             3       映画 - DVD   3000          2            1           0
# 6  2021-10-01       1      7             4  映画 - ブルーレイ   5000          1            1           2
# 7  2021-10-01       1      8             5       本 - 教育用   2000          3            2           3

メインカテゴリおよびサブカテゴリがそれぞれ数値に変換しているのが分かります。

TargetEncoder

Target EncoderはCategory _encodersライブラリで実装されています。利用するにはまず、category_encodersライブラリをpipを使用してインストールします。

$ pip install category_encoders

次に、以下はcategory_encodersを使用してターゲットエンコーディングを実装する例です。

import pandas as pd
import category_encoders as ce

# サンプルデータ
data = pd.DataFrame({
    'Category': ['A', 'B', 'A', 'C', 'B', 'A'],
    'Target': [1, 2, 1, 3, 2, 3]
})

# ターゲットエンコーダーの初期化
encoder = ce.TargetEncoder(cols=['Category'])

# データの適合と変換
encoded_data = encoder.fit_transform(data['Category'], data['Target'])

print(encoded_data)

エンコードした出力結果は次のとおりです。同じカテゴリは同じ値に変換されているのがわかります。
元のデータ(Category)をエンコードデータで置き換えたい場合は、data['Category'] = encoded_dataで置換できます。

   Category
0  1.948512
1  2.000000
2  1.948512
3  2.130108
4  2.000000
5  1.948512

終わりに

今回紹介した機能はテーブルデータを扱う際には必ずと言って良いほど利用するので、必要な際に参照できるようにしておくと良いと思います。
また、テーブルデータ向けの定番アルゴリズムの使い方はこちらの記事で、

機械学習モデル構築までの流れはこちらの記事でまとめていますので、併せて参考にしてください。

The post 【テーブルデータ】pythonにおける定番の前処理【欠損値/型変換/結合】 first appeared on .]]>
https://note-tech.com/table_preprocess_summary/feed/ 0