#python #pandas #dataframe #datetime #matplotlib
Вопрос:
Я пытаюсь определить время дня, когда я ложился спать каждый день.
Мне было интересно, существует ли элегантное решение, чтобы моя ось y (время суток) менялась с 20 ч (или 10 вечера) до 12 ч или (12 вечера)
По сути, мои галочки были бы [20, 21, 22, 23, 00, 01, 02, …, 09, 10, 11, 12]
Вот часть моей базы данных :
Дата | Начать | Конец |
---|---|---|
2019-09-21 | 23:26:01 | 05:40:01 |
2019-09-22 | 22:45:42 | 05:58:04 |
2019-09-23 | 22:56:40 | 05:55:23 |
2019-09-24 | 22:35:47 | 06:05:07 |
2019-09-25 | 00:23:13 | 06:03:08 |
Вот что я хотел бы сделать :
И вот что я попробовал :
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import dates as mdates
data = pd.read_csv("sleepdata.csv", sep=";")
plt.plot(mdates.date2num(data.Date), mdates.datestr2num(data.Start))
Ответ №1:
Я полагаю, у вас есть данные, хранящиеся в csv
файле, который можно прочитать с помощью pandas:
df = pd.read_csv(r'data/data.csv')
Date Start End
0 2019-09-21 23:26:01 05:40:01
1 2019-09-22 22:45:42 05:58:04
2 2019-09-23 22:56:40 05:55:23
3 2019-09-24 22:35:47 06:05:07
4 2019-09-25 00:23:13 06:03:08
Прежде всего, вы должны внести некоторые изменения в фрейм данных.
По оси y вам нужно время из двух разных дней: вечера того дня, когда вы начинаете спать, и утра следующего дня. Однако 'Start'
'End'
столбцы и не содержат информации о дате, только время.
Кроме того, вы хотите построить график времени в разные дни. Итак, если я выведу дату из 'Date'
столбца, по оси y у вас будут данные от 2019-09-21 20:00:00
до 2019-09-25 12:00:00
(или последняя дата в ваших данных), и вы не сможете сравнивать только время, потому что каждое время относится к другому дню. Таким образом, вы должны назначить свидание 'Start'
и 'End'
столбцы, и вы должны выбрать всегда одну и ту же дату, чтобы иметь возможность сравнивать только время, независимо от даты. Это причина, по которой я вменяю даты 2000-01-01
или 2000-01-02
в 'Start'
и 'End'
столбцы через start
и end
функции.
Затем вам нужно преобразовать 'Date'
тип столбца из str
в datetime
.
На данный момент у вас есть этот фрейм данных:
Date Start End
0 2019-09-21 2000-01-01 23:26:01 2000-01-02 05:40:01
1 2019-09-22 2000-01-01 22:45:42 2000-01-02 05:58:04
2 2019-09-23 2000-01-01 22:56:40 2000-01-02 05:55:23
3 2019-09-24 2000-01-01 22:35:47 2000-01-02 06:05:07
4 2019-09-25 2000-01-02 00:23:13 2000-01-02 06:03:08
Обратите внимание на дату 'Start'
и 'End'
столбцы: если 'Start'
час позже полудня, значит, вы легли спать 1-го числа , вкл 2000-01-01
., в противном случае на следующий день, вкл 2000-01-02
. В любом случае вы всегда просыпаетесь на 2-й день, вкл 2000-01-02
.
Теперь вы можете строить кадр данных изо дня в день. Я использую df.iterrows
цикл, который не самый лучший, я открыт для предложений по улучшению процесса построения графика.
Наконец, вам нужно настроить формат и метки по осям x и y.
Полный Код
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import matplotlib.dates as md
df = pd.read_csv(r'data/data.csv')
def start(x):
H, M, S = list(map(int, x['Start'].split(':')))
Y, m, d = 2000, 1, 1
if H > 12:
return datetime(year = Y, month = m, day = d, hour = H, minute = M, second = S)
else:
return datetime(year = Y, month = m, day = d, hour = H, minute = M, second = S) timedelta(days = 1)
def end(x):
H, M, S = list(map(int, x['End'].split(':')))
Y, m, d = 2000, 1, 1
return datetime(year = Y, month = m, day = d, hour = H, minute = M, second = S) timedelta(days = 1)
df['Start'] = df.apply(start, axis = 1)
df['End'] = df.apply(end, axis = 1)
df['Date'] = pd.to_datetime(df['Date'], format = '%Y-%m-%d')
fig, ax = plt.subplots()
for i, row in df.iterrows():
ax.plot([row['Date'], row['Date']], [row['Start'], row['End']], linewidth = 10, color = 'blue')
ax.xaxis.set_major_locator(md.DayLocator(interval = 1))
ax.xaxis.set_major_formatter(md.DateFormatter('%Y-%m-%d'))
plt.setp(ax.xaxis.get_majorticklabels(), rotation = 90)
ax.yaxis.set_major_locator(md.HourLocator(interval = 1))
ax.yaxis.set_major_formatter(md.DateFormatter('%H:%M'))
ax.set_ylim(datetime(year = 2000, month = 1, day = 1, hour = 20, minute = 0, second = 0),
datetime(year = 2000, month = 1, day = 2, hour = 12, minute = 0, second = 0))
plt.show()