これはしばらくの間作業していますが、解決策がありますが最適には機能しません。ここではデータフレームがどのように見えるかの例です:pandasデータフレーム内のchange-in-stateカラムで集計する方法
print(month_df[['timestamp','date','hvac_state']].head(100))
timestamp date hvac_state
0 2017-11-09 18:43:45 12-09-17 off
1 2017-11-09 20:15:27 12-09-17 heating
2 2017-11-09 22:29:00 12-09-17 heating
3 2017-11-09 23:42:34 12-09-17 off
4 2017-11-10 00:09:40 12-10-17 heating
5 2017-11-10 00:23:14 12-10-17 heating
6 2017-11-10 03:32:17 12-10-17 off
7 2017-11-10 10:59:24 12-10-17 heating
8 2017-11-10 11:12:59 12-10-17 off
9 2017-11-10 13:49:09 12-10-17 off
10 2017-11-10 16:58:11 12-10-17 heating
11 2017-11-10 17:11:45 12-10-17 heating
12 2017-11-10 17:25:19 12-10-17 off
13 2017-11-10 23:53:44 12-10-17 off
14 2017-11-11 00:25:22 12-11-17 off
15 2017-11-11 03:29:53 12-11-17 heating
16 2017-11-11 03:43:26 12-11-17 heating
17 2017-11-11 04:01:31 12-11-17 off
ありmonth_dfのデータフレームの他のフィールドがありますが、これらは私が使用しています3です。何かが変更されると、行が追加されます。時には項目がhvac_stateに変更されることがあります。時にはそれは別の列です。そういうわけで、ときどき国家は変わらないが、別のエントリがあることがわかる。
すべての「時間数」とhvac_stateの状態を1日ごとに集計する必要があります。私はgroupbyに関するいくつかの記事を見つけ、シフトを使用しました(this oneなど)。それは私が実装したものですが、完璧ではありません。毎日のカットオフは00:00:00〜23:59:59です。私は集計データでこれを知ることができます。なぜなら、24時間を少し上回る量になるからです。また、これを実行するために「タイムスタンプ」と「日付」列を使用しているので、明らかに効率的ではありません。
これは私が現在使用している方法である:
def remove_consecutive_duplicates(a):
return a.loc[a.shift() != a]
# Get the left data frame ready, with timestamps associated specifically with state changes.
left = remove_consecutive_duplicates(month_df.set_index('timestamp')['hvac_state']).reset_index()
# Then delta from change to change and shift by negative 1.
left['delta'] = left.timestamp.diff().fillna(0).astype(int).shift(-1).fillna(0)
# Now prep the right dataframe by hurling the hvac_state so we don't end up with two.
right = month_df.drop(['hvac_state'], axis=1)
# Perform the merge, dropping the stuff that isn't in the left side.
result = pd.merge(left, right, how='left', on='timestamp')
# Now we can store that month's hourly usage by day.
grouped = (result.groupby(['date','hvac_state'])[['delta']].sum()/3600000).round(2)
results = defaultdict(lambda: defaultdict(dict))
for index, value in grouped.itertuples():
for i, key in enumerate(index):
if i == 0:
nested = results[key]
elif i == len(index) - 1:
nested[key] = value
else:
nested = nested[key]
results
defaultdict(<function __main__.<lambda>>,
{'12-09-17': defaultdict(dict, {'heating': 3.84, 'off': 10.24}),
'12-10-17': defaultdict(dict, {'heating': 8.36, 'off': 14.39}),
'12-11-17': defaultdict(dict, {'heating': 10.17, 'off': 14.91}),
'12-12-17': defaultdict(dict, {'heating': 9.34, 'off': 13.56}),
'12-13-17': defaultdict(dict, {'heating': 10.49, 'off': 13.59}),
'12-14-17': defaultdict(dict, {'heating': 9.58, 'off': 14.72}),
'12-15-17': defaultdict(dict, {'heating': 6.03, 'off': 24.38}),
'12-16-17': defaultdict(dict, {'heating': 0.0})})
を「加熱」の時間があるときあなたは、15日に私の「オフ」時間は24.38時間であることを、この例から見ることができます6.03時間。
日付をキーとして、各状態で費やされた時間を示すサブキーとして標準辞書を(json用に)使いたいと思っています。状態値は24時間に追加する必要があります。理想的には、このような何か:
{
'12-12-17': {'heating': 5.23, 'off': 18.77},
'12-13-17': {'heating': 7.85, 'off': 16.15},
'12-14-17': {'heating': 7.91, 'off': 16.09},
'12-15-17': {'heating': 6.22, 'off': 17.78},
'12-16-17': {'heating': 5.11, 'off': 18.89},
'12-17-17': {'heating': 9.17, 'off': 14.83}
}
あなたは@Parfaitありがとう!それは優れた説明と方法です!私は間違いなくそれを使用しています。 –
私は実際には '日付'列を削除して少し修正したので、 'タイムスタンプ'だけが必要です。私はタイムゾーンを修正した後に問題を引き起こしていたので、pd.DateOffset(days = 1)をmidnights_dfに移動しました。 @パルフェット、あなたは紳士と学者です! –
ハハ... StackOverflowは、OPが投稿されたソリューションから学び、実際のニーズに合わせて拡張する場所を提供する贈り物です(多くのポスターは正確なプラグアンドチャグの回答が必要です)。あなたの興味深い質問にお役に立ててうれしいです。ハッピーコーディング! – Parfait