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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

3回答

6508閲覧

DataFrameで登録時刻の平均を出したい

cozy52

総合スコア7

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2020/02/08 03:21

pandas,DataFrameで以下のように登録時刻のデータがあります。
日付は無視して、時間(hour,min,second)の平均を出したいのですが、簡単な方法はありますか?

In [2]:dfres['登録時刻']
Out[2]:
0 2020-01-06 09:01:44
1 2020-01-06 09:00:29
2 2020-01-06 09:00:29
3 2020-01-06 09:09:07
4 2020-01-06 09:21:14

364 2020-01-25 09:02:08
365 2020-01-25 09:02:08
366 2020-01-25 09:05:05
367 2020-01-25 09:13:29
368 2020-01-25 09:17:45
Name: 登録時刻, Length: 299, dtype: datetime64[ns]

よろしくお願いします。

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

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

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

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

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

guest

回答3

0

ベストアンサー

ある日の0時0分からの時間差を「1日」で除した余りを平均します。

Python

1base_time = pd.Timestamp(0) 2avg_time = ((dfres['登録時刻'] - base_time) % pd.Timedelta(1, 'D')).mean() 3 4print(avg_time) 5# Timedelta('0 days 09:07:21.800000')

追記:NumPyで処理させると計算が速くなります。

Python

1base_time = np.datetime64(0, 'ns') 2avg_time = ((dfres['登録時刻'].to_numpy() - base_time) % np.timedelta64(1, 'D')).mean() 3 4print(pd.Timedelta(avg_time)) 5# Timedelta('0 days 09:07:21.800000')

投稿2020/02/10 05:08

編集2020/02/10 05:40
kirara0048

総合スコア1399

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

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

cozy52

2020/02/13 04:19

こんなやり方があるんですね! ありがとうございます!
guest

0

こんにちは

はじめに、以下のような補助的な関数を作っておきます。

python3

1def sec_to_time(s): 2 ''' 3 引数 s で与えられる秒数を、0時0分0秒からの経過秒数として、 4 対応する time オブジェクトを作成して返す。 5 (引数 s は np.float64 の小数を想定) 6 ''' 7 s = int(round(s)) 8 h = s // 3600 9 s -= 3600 * h 10 m = s // 60 11 s -= 60 * m 12 return datetime.time(hour=h, minute=m, second=s) 13 14 15def time_to_sec(dt): 16 ''' 17 引数 dt で与えられるdatetimeオブジェクトの示す日時の 18 時刻部分について、0時0分0秒からの経過秒数を返す 19 ''' 20 return 3600 * dt.hour + 60 * dt.minute + dt.second

上記の time_to_sec を使って、所与のデータフレームに、平均計算ののための一時的な列時刻(秒)を追加します。

python3

1dfres.loc[:,'時刻(秒)'] = [*map(lambda t: time_to_sec(t), dfres['登録時刻'])]

上記によって、データフレームに、下記のような 時刻(秒)列が追加されます。

登録時刻     時刻(秒) 0 2020-01-06 09:01:44 32504 1 2020-01-06 09:00:29 32429 ・・・

時刻(秒) 列の平均を求めて、これを先に作った sec_to_time に与えて、時刻を得ます。

python3

1sec_to_time(dfres['時刻(秒)'].mean())

追記

上記の回答コードは、補助的な関数の中で、360060 という数字を使って、時刻オブジェクトと数値の変換を行っており、煩雑でした。これらを使わない方法を考えたので追記します。

考え方としては、

① 所与のデータフレームの全行について、 登録時刻列の日時の日付部分を 1970-01-01 に置き換えた日時を作り、それらに対して timestamp() によってエポック秒を取得
② 上記で得られた、全行の秒数の平均値を算出
③ 上記で得られた平均値をエポック秒として日時を作る。
④ 上記で作成した日時の時刻部分が、求めたい平均としての時刻になる。

以下は上記の考え方によるコードです。

python3

1 2timestamps = dfres['登録時刻'].apply(lambda dt: dt.replace(year=1970, month=1, day=1).timestamp()) # ① 3 4avg_timestamp = round(timestamps.mean()) # ② 5 6avg_date = datetime.datetime.fromtimestamp(avg_timestamp).astimezone(datetime.timezone.utc) # ③ 7 8print(avg_date.time()) # ④

投稿2020/02/08 05:26

編集2020/02/08 08:01
jun68ykt

総合スコア9058

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

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

cozy52

2020/02/13 04:19

ありがとうございます!
guest

0

簡単とは言えないかもですが、以下のようにtimedeltaを使うと平均時刻を求めることができます。

Python

1import pandas as pd 2import datetime 3 4df = pd.DataFrame({'dt':['2020-01-01 15:00:00', '2020-01-02 16:00:10']}) 5df['dt'] = pd.to_datetime(df['dt']) 6print(df) 7# dt 8#0 2020-01-01 15:00:00 9#1 2020-01-02 16:00:10 10 11# 時刻部分のみを抽出しtimedeltaを作成 12sr = df['dt'].map(lambda v: datetime.timedelta(hours=v.hour, minutes=v.minute, seconds=v.second)) 13td = sr.sum() / len(sr) # 平均 14 15# (経過)時間[sec] -> 時分秒 16h, m, s = td.seconds//3600, (td.seconds//60)%60, td.seconds%60 17print( h,m,s) 18# 15 30 5

投稿2020/02/08 04:14

can110

総合スコア38341

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

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

cozy52

2020/02/13 04:20

ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問