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

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

新規登録して質問してみよう
ただいま回答率
85.51%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

243閲覧

pythonでログの分析(時間)が出来ません。

fuzball_yumi

総合スコア13

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2017/08/24 05:08

###前提・実現したいこと
pythonのプログラムで質問です。
以下のログがあります。

2012/01/02 13:00 0
2012/01/02 14:00 1
2012/01/02 14:01 1
2012/01/02 14:30 0
2012/01/02 14:31 0
2012/01/02 14:40 1
2012/01/03 01:00 0

このログの0と1の時間を日にちごとに集計を行いたいのです。
途中、0と1の間に1が入ったり、0が入ったりしたときは、無視をして、
(上のログの場合、14:00の1、14:31の0)です。
2012/01/02と2012/01/03で日にちをまたいだときは、23:59まで前日
00:00から2012/01/03に入れるようにしたいのですが方法が解りません。

プログラムのサンプルをお願いします。

###発生している問題・エラーメッセージ

エラーメッセージ

###該当のソースコード

#!/usr/bin/env python # -*- coding: utf-8 -*- import csv import datetime #CSVファイルを読み込んで、各行毎のリストにする。 f = open("/usr/local/bin/log.csv") reader= csv.reader(f, delimiter=",", quotechar='"') records = list(reader) f.close() #2列目が0の行と1の行に分ける from_list = [datetime.datetime.strptime(record[0], "%Y/%m/%d %H:%M:%S") for record in records if record[1]=='1'] to_list = [datetime.datetime.strptime(record[0], "%Y/%m/%d %H:%M:%S") for record in records if record[1]=='0'] #日毎の結果を格納する辞書を用意 result_dic = {} #to - from を行い、間の経過時間を取得して日付をkeyにした辞書に加算していく。 for from_dt, to_dt in zip(from_list, to_list): if result_dic.get(str(from_dt.date())) is None: result_dic[str(from_dt.date())] = (to_dt - from_dt).total_seconds() / 60 else: result_dic[str(from_dt.date())] += (to_dt - from_dt).total_seconds() / 60 #日付をkeyにした辞書のままだと日付で昇順に表示する時に面倒なのでリストに変換。 results = [{"date": date_str, "min": total_min} for date_str, total_min in result_dic.items()] results.sort(key=lambda x:x['date']) #日付でソート for result in results: #表示 print("{0}, TOTAL{1}min".format(result['date'], int(result['min'])))

###試したこと
0と1で分けて実行したのですが、0が連続したり1が連続したときにおかしくなります。
日付をまたぐと前日に入ってしまいます。

###補足情報(言語/FW/ツール等のバージョンなど)
より詳細な情報

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんな感じでどうでしょうか?

pythonだと、日付でgroupbyできるので、それでまず日付で分けて、次に、1日の中で
集計しています。

また、その日の終わりを23:59としてしまうと、1分中途半端になってしまうので、
その日の最後の24:00までで計算してみました。

python

1# -*- coding: utf-8 -*- 2 3import csv 4import datetime 5from itertools import groupby 6 7#CSVファイルを読み込んで、各行毎のリストにする。 8f = open("log.csv") 9reader= csv.reader(f, delimiter=",", quotechar='"') 10records = list(reader) 11f.close() 12 13records = [ { "datetime": datetime.datetime.strptime(record[0],"%Y/%m/%d %H:%M") , 14 "state" : record[1] } for record in records ] 15 16 17group = groupby( records, lambda record:record["datetime"].date() ) 18 19results_dict = {} 20state = "0" 21 22for day,daily_records in group: 23 day_text = str(day) 24 results_dict[day_text] = 0 25 daily_records = sorted(daily_records,key=lambda record:record["datetime"]) 26 prev = datetime.datetime.combine(day,datetime.time(0,0)) 27 for record in daily_records: # その日のレコードを計算 28 now = record["datetime"] 29 if state == "1": 30 results_dict[day_text] += (now - prev).total_seconds() / 60 31 prev = now 32 state = record["state"] 33 if state == "1": # その日の最後までを計算 34 next_day = day + datetime.timedelta(days=1) 35 next_datetime = datetime.datetime.combine(next_day,datetime.time(0,0)) 36 results_dict[day_text] += (next_datetime - prev).total_seconds() / 60 37 38results = [{"date": day_text, "min": total_min} for day_text , total_min in results_dict.items()] 39 40results.sort(key=lambda x:x['date']) #日付でソート 41 42for result in results: #表示 43 44 print("{0}, TOTAL {1} min".format(result['date'], int(result['min'])))

投稿2017/08/24 07:30

編集2017/08/24 08:17
KNaito

総合スコア376

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuzball_yumi

2017/08/25 08:26 編集

上のプログラムを実行したらエラーが出ました。 Traceback (most recent call last): File "ptime_3.py", line 13, in <module> records = [ { "datetime": datetime.datetime.strptime(record[0],"%Y/%m/%d %H:%M:%S") ,"state" : record[1] } for record in records ] IndexError: list index out of range これを試すのに使ったCSVファイルはこちらです。 2017/08/24 13:38:11,0, 2017/08/24 13:39:44,1, 2017/08/24 14:09:03,0, 2017/08/24 14:18:42,1, 2017/08/24 14:50:40,0, 2017/08/24 14:51:07,0, 2017/08/24 14:53:05,1, 2017/08/24 15:05:06,0, 2017/08/24 15:11:17,0, 2017/08/24 15:13:14,1, 2017/08/24 15:31:32,0, 2017/08/24 15:31:31,0, 2017/08/24 15:31:31,0, お手数お掛けします。
KNaito

2017/08/25 10:26

csv.readerの引数を見直みてしてください 質問されたときのcsvは区切りが空白で分単位、コードでは区切りがカンマで秒単位(集計は分単位) となっていたため、どちらに合わせるべきかわからないため、 csvは区切りをカンマ、分単位のレコードと仮定しています。 秒単位なら、集計ロジックも秒単位にした方が良いと思いますが
fuzball_yumi

2017/08/25 23:26

いろいろとありがとうございました。 CSVを分に直したら出来ました。 ご丁寧にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問