質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.57%

配列から特定の曜日と時間帯のデータを抽出し,計算する

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 350

TKWTsan

score 8

プログラミング初心者です.
現在,pythonを用いてcsv形式のデータの分析を行っております.
前提として,csv,numpy,pandasなどのモジュールを使用しないプログラムを組んでおります.

ある要素を持つデータをすべて抽出した後,特定の曜日(平日)と,
特定の時間帯(8:00~18:00)のみのデータを抜き出し,その中のある要素の平均値を算出するプログラムを自分なりに組んでみたのですが,以下のように長くなってしまいました.
elif部分の重複をなくす,あるいはほかにプログラムを簡潔に示す方法があれば
ご指摘よろしくお願いします.

読み込むcsvファイルは2018/09/01(Sat)から2018/09/30(Sun)です.

import datetime

filepath = 'aaa.csv'

with open(filepath,encoding='shift-jis') as f:

    data2 = []
    for line in f:
        line = line.replace('\n','')
        data = line.split(',')
        data2.append(data)

    data3=[]
    for i in data2:
        if i[2] =='1':
            data3.append(i)
    for i in data3:
        tmdata=(datetime.datetime.strptime(i[0],'%Y/%m/%d %H:%M'))
        i[0]=tmdata
sum=0
n=0
a=1
b=0

for i in data3:
    if i[0] < datetime.datetime.strptime('2018/09/01 18:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*b and i[0] >= datetime.datetime.strptime('2018/09/01 8:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*b\
       and not i[0].strftime('%a') == 'Sat' and not i[0].strftime('%a') == 'Sun':
        sum = sum + int(i[7])
        n += 1
    elif i[0] < datetime.datetime.strptime('2018/09/01 18:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*a and i[0] >= datetime.datetime.strptime('2018/09/01 8:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*a\
         and not i[0].strftime('%a') == 'Sat' and not i[0].strftime('%a') == 'Sun':
         sum = sum + int(i[7])
         a += 1
         b += 1
         n += 1
    elif i[0] < datetime.datetime.strptime('2018/09/01 18:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+1) and i[0] >= datetime.datetime.strptime('2018/09/01 8:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+1)\
         and not i[0].strftime('%a') == 'Sat' and not i[0].strftime('%a') == 'Sun':
         sum = sum + int(i[7])
         a += 1
         b += 1
         n += 1
    elif i[0] < datetime.datetime.strptime('2018/09/01 18:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+2) and i[0] >= datetime.datetime.strptime('2018/09/01 8:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+2)\
         and not i[0].strftime('%a') == 'Sat' and not i[0].strftime('%a') == 'Sun':
         sum = sum + int(i[7])
         a += 1
         b += 1
         n += 1
    elif i[0] < datetime.datetime.strptime('2018/09/01 18:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+3) and i[0] >= datetime.datetime.strptime('2018/09/01 8:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+3)\
         and not i[0].strftime('%a') == 'Sat' and not i[0].strftime('%a') == 'Sun':
         sum = sum + int(i[7])
         a += 1
         b += 1
         n += 1
    elif i[0] < datetime.datetime.strptime('2018/09/01 18:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+4) and i[0] >= datetime.datetime.strptime('2018/09/01 8:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+4)\
         and not i[0].strftime('%a') == 'Sat' and not i[0].strftime('%a') == 'Sun':
         sum = sum + int(i[7])
         a += 1
         b += 1
         n += 1
    elif i[0] < datetime.datetime.strptime('2018/09/01 18:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+5) and i[0] >= datetime.datetime.strptime('2018/09/01 8:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+5)\
         and not i[0].strftime('%a') == 'Sat' and not i[0].strftime('%a') == 'Sun':
         sum = sum + int(i[7])
         a += 1
         b += 1
         n += 1
    elif i[0] < datetime.datetime.strptime('2018/09/01 18:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+6) and i[0] >= datetime.datetime.strptime('2018/09/01 8:00','%Y/%m/%d %H:%M')+datetime.timedelta(days=1)*(a+6)\
         and not i[0].strftime('%a') == 'Sat' and not i[0].strftime('%a') == 'Sun':
         sum = sum + int(i[7])
         a += 1
         b += 1
         n += 1

print(sum/n)
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Akihito_Jv

    2019/10/24 23:02

    失礼します。
    csvファイルのデータをご提示いただけませんでしょうか。

    キャンセル

  • TKWTsan

    2019/10/24 23:29

    ご質問ありがとうございます.
    http://public-data.jartic-raws.durasite.net/opendata.html
    このサイトの「一般道路の「断面交通量情報」 (2019年8月分)」がほぼ同じ形式のデータになります.
    プログラムでは2018年9月ですが,用意できたデータは2019年8月のみでした.
    よろしくお願いします.

    キャンセル

回答 2

checkベストアンサー

+1

失礼します。
ご提示いただいたサイトから、
北海道函館市のデータを取得しました。
取得したデータの一部が以下となります。

2019/08/01 00:00,3002,1,110,36,4,27,25,8,,201800
2019/08/17 17:55,3002,11,115,47,3,11,31,8,,201800
2019/08/17 18:50,3002,20,105,37,13,35,15,,,201800
2019/08/30 08:15,3002,13,120,29,7,34,23,7,,201800

そして、記載されていたコードを書き直したのが以下となります。

書き直したポイントとして、

  1. 同じ条件で指定されているデータを定数化した
  2. 処理を順番に分けて処理させた
    となります。

私自身まだまだ未熟者でございますので、
実際には、もっといいコードが存在すると思います。
Pythonには、リスト内包表記というものがありますので、
そちらで記載することも可能かと思いますが、
条件が複雑な場合は、単純に記載した方が、冗長にはなってしまいますが、
可読性の高いコードになると思います。

今回書き直したことで、小数点の計算のズレが生じる可能性があり、
リファクタリングが完全に成功しているわけではありませんので、
ご了承ください。

import datetime

filepath = 'abc.csv'
# 定数
TIME18 = datetime.datetime.strptime('2018/09/01 18:00','%Y/%m/%d %H:%M').time()
TIME8 = datetime.datetime.strptime('2018/09/01 8:00','%Y/%m/%d %H:%M').time()

with open(filepath,encoding='shift-jis') as f:

    data2 = []
    for line in f:
        line = line.replace('\n','')
        data = line.split(',')
        data2.append(data)

    data3=[]
    for i in data2:
        if i[2] == "1":
            data3.append(i)

    for i in data3:
        tmdata=(datetime.datetime.strptime(i[0],'%Y/%m/%d %H:%M'))
        i[0]=tmdata
sum=0

# 平日(土,日を除いたデータ)を格納するリストを宣言する
weekdays = []
# データを回して、平日だけを格納する
for weekday in data3:
    if not weekday[0].strftime('%a') == 'Sat' and not weekday[0].strftime('%a') == 'Sun':
        weekdays.append(weekday)

# 特定の時間(8:00~18:00)のデータを格納するリストを宣言する
specifiedDate = []
# データを回して、特定の時間だけのデータを格納する
for Specified_time in weekdays:
    if TIME8 <= Specified_time[0].time() and Specified_time[0].time() <= TIME18:
        specifiedDate.append(Specified_time)

# 残りのデータは、平日8:00から18:00までのデータになっているので、その中の要素を計算する。
for i in specifiedDate:
    sum = sum + int(i[7])

print(sum/len(specifiedDate))

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/25 09:46

    ご指摘の通り,特定の曜日のリストを新しく作成して、計算したほうが分かりやすいですね.
    ありがとうございました.

    キャンセル

+1

datatime.weekday()で曜日が取得できるのとdatetime.hourでhourの部分が取得できます。
これを活用して受け入れる曜日、時間帯をテーブル化し、それに基づいてデータをフィルタします。

import datetime

filepath = 'aaa.csv'

with open(filepath,encoding='shift-jis') as f:

    data2 = []
    for line in f:
        line = line.replace('\n','')
        data = line.split(',')
        data2.append(data)

    data3=[]
    for i in data2:
        if i[2] =='1':
            data3.append(i)
    for i in data3:
        tmdata=(datetime.datetime.strptime(i[0],'%Y/%m/%d %H:%M'))
        i[0]=tmdata

accept_weekday = [ 
    True,  # 月曜日
    True,  # 火曜日
    True,  # 水曜日
    True,  # 木曜日
    True,  # 金曜日
    False, # 土曜日
    False  # 日曜日
]

accept_hour = [
#   0       1       2       3       4       5       6       7       8       9       10      11
    False,  False,  False,  False,  False,  False,  False,  False,  True ,  True ,  True ,  True ,
#   12      13      14      15      16      17      18      19      20      21      23      23
    True ,  True ,  True ,  True ,  True ,  True ,  False,  False,  False,  False,  False,  False,
]


sum = 0
n = 0

for i in data3:

    # 曜日判定
    if accept_weekday[i[0].weekday()] == False:
        continue

    # 時間帯判定
    if accept_hour[i[0].hour] == False:
        continue

    sum = sum + int(i[7])
    n   = n + 1

print(sum/n)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/25 09:50

    ご指摘ありがとうございます.
    参考にさせていただきます.

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.57%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る