LoginSignup
2
3

More than 5 years have passed since last update.

タイムズカープラスで最安プランを選ぶ

Last updated at Posted at 2018-08-15

はじめに

カーシェアリングサービス「タイムズカープラス」のプラン料金を計算し,最安プランを選びます.

予約作業について

タイムズカープラスで車を予約をする際には,WEBページ上で次のような作業をする必要があります.

  1. 借りたい車を選択する
  2. 料金プランを選択する
  3. 利用開始時刻と返却予定時刻を入力する
  4. 料金を確認して問題なければ予約を確定する

ここで「料金プラン」には選択肢が幾つかあるのですが,それぞれの料金を確認するには画面遷移が発生します.また,距離に応じた料金がかかるプランとかからないプランがあるのですが,想定走行距離は入力できないため,確認する際の料金には含まれていないことになります.

ということで,想定走行距離を含めた全プランの料金を計算し,最も小さな金額を自動的に選ぶ,というコードを書いてみます.

料金プランについて

タイムズカープラスで,「ベーシック」と呼ばれる車種を借りる場合の利用料金は,次の表のようになっています.

プラン名 料金 距離料金 延長料金
ショート 0円 0円/km 206円/15分
6時間パック 4,020円 0円/km 206円/15分
12時間パック 6,690円 16円/km 206円/15分
24時間パック 8,230円 16円/km 206円/15分
アーリーナイトパック 18-0時 2,060円 16円/km 206円/15分
レイトナイトパック 0-9時 2,060円 16円/km 206円/15分
ダブルナイトパック 18-9時 2,580円 16円/km 206円/15分

「ショート」のプランは,「延長料金が206円/15分の0時間(0円)パック」と言う風に捉えると,他の「○時間パック」と同じように計算できます.

なお,複数のプランを組み合わせることはできません1.また,延長時間には上限があり,ショートの場合は72時間まで,パックの場合は6時間までです.

(別途,初期費用や基本料金がかかる場合があります.また,36時間パック,48時間パック,60時間パックというプランが選択可能な車両もあります.詳細は公式サイトを参照してください)

Pythonコード

各プランの定義

まず,pandasのDataFrameを使って金額を定義します.plansはプラン名の配列で,今後計算時のキーとして使います.

import math
import datetime as dt
import pandas as pd

# plan names
plans = ['short', 'hour6', 'hour12', 'hour24', 'early', 'late', 'double']

# fare amount
a = {'base':[0, 4020, 6690, 8230, 2060, 2060, 2580], 
     'extra':[206, 206, 206, 206, 206, 206, 206],
     'distance':[0, 0, 16, 16, 16, 16, 16]}
amount = pd.DataFrame(data=a, index=plans)

続いて,各プランを計算するための条件もDataFrameにして,金額と結合します.

# fare condition
c = {'type':['length', 'length', 'length', 'length', 'time', 'time', 'time'],
     'length':[0, 6, 12, 24, 6, 9, 15],
     'start':['', '', '', '', 18, 0, 18],
     'by':['', '', '', '', 24, 9, 24],
     'max':[72, 6, 6, 6, 6, 6, 6]}
condition = pd.DataFrame(data=c, index=plans)

fare = pd.concat([amount, condition], axis=1)

ちょっと分かりづらいですが,各列の意味は次のようにしました.

列名 説明
type プランが時間の長さを持つか(length),開始時刻と終了時刻を持つか(time)
length typeがlengthの場合は時間の長さ,timeの場合はパックの開始時刻〜終了時刻まで.単位は[hour]
start typeがtimeの場合のパックの開始時刻
by typeがtimeの場合,利用開始時刻はstart以降で,byよりも前でなければならない
max 延長時間の上限.単位は[hour]

料金を計算するクラス

「計算機(Calculator)」を表すクラスを1つ作ります.コンストラクタに利用開始時刻,返却予定時刻,距離をセットし,calc_fareメソッドにプラン名を与えると,料金を計算します.なお,下記のような場合にはmath.infを返します.

  • プランのtypeがtimeで,かつ,そのプランが使えない時間帯である
  • 延長時間が上限を超えている
class FareCalculator():
    def __init__(self, start, end, distance):
        self.s = start
        self.e = end
        self.d = distance

    def __calc_extra(self, plan):
        if fare.at[plan, 'type'] == 'length':
            extra = self.e - self.s - dt.timedelta(
                hours=int(fare.at[plan, 'length']))
        elif fare.at[plan, 'type'] == 'time':
            plan_start = dt.datetime(year=self.s.year, 
                                     month=self.s.month, 
                                     day=self.s.day, 
                                     hour=fare.at[plan, 'start'])
            plan_end = plan_start + dt.timedelta(
                hours=int(fare.at[plan, 'length']))
            extra = self.e - plan_end
        else:
            extra = math.inf
        return max(0, math.ceil((extra.total_seconds()/3600)*4))

    def calc_fare(self, plan):
        if (fare.at[plan, 'type'] == 'time') and (
                self.s.hour < fare.at[plan, 'start'] or
                self.s.hour >= fare.at[plan, 'by']):
            return math.inf
        else:
            extra_qnum = self.__calc_extra(plan)
        if extra_qnum > fare.at[plan, 'max']*4:
            return math.inf
        else:
            return (fare.at[plan, 'base'] + 
                    fare.at[plan, 'extra'] * extra_qnum + 
                    fare.at[plan, 'distance'] * self.d)

__calc_extraメソッドについて少し説明します.

このメソッドは,延長時間を15分単位で計算するためのものです(例えば延長時間が1時間なら,戻り値は4).延長時間の計算方法は,typeがlengthかtimeかで変わります.どちらにしても,datetime.timedelta型で延長時間(extra)を求めて,total_secondsプロパティを3600で割って時間[hour]にして,さらに4を乗じて15分単位に直しています.

if文を使って色々と処理をしちゃってますが,まあとりあえず良しとします.

計算してみる

これで料金を計算する準備が整いました.利用開始時刻,返却予定時刻,距離を与えてみましょう.例として,

  • 利用開始時刻 2018年8月15日 15:30
  • 返却予定時刻 2018年8月16日 08:00
  • 距離 120km

を与えます.時刻はdatetime.datetime型を利用します.

start = dt.datetime(year=2018, month=8, day=15, hour=15, minute=30)
end = dt.datetime(year=2018, month=8, day=16, hour=8, minute=0)
distance = 120

これをFareCalculatorクラスに与えた後,各プランの料金を計算して,最安値となるプランを選びます.結果はresultに書き込むことにします.

calculator = FareCalculator(start, end, distance)
result = pd.DataFrame(columns=[], index=plans)
for plan in plans:
    result.at[plan, 'amount'] = calculator.calc_fare(plan)

最安プランの選択には,pandasのidxminを使います.

print('Plan:', result.amount.idxmin(), ', Amount: ', result.amount.min())

答えはこんな感じになります.
Plan: hour24 , Amount: 10150.0

環境

Python 3.6.3
pandas 0.20.3

終わりに

Pythonの勉強がてら書いてみました.今後は別の勉強も兼ねて,WEBサービスにでもして公開してみたいと思っています2


  1. 組み合わせが可能なら,最適化問題の良い題材になりそうです. 

  2. 公式サイトに最安プラン計算機能があっても良いと思うのですが. 

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3