Могу ли я построить линейную регрессию с датой и временем по оси X с Seaborn?

Мой объект DataFrame выглядит так

            amount
date    
2014-01-06  1
2014-01-07  1
2014-01-08  4
2014-01-09  1
2014-01-14  1

Мне нужен своего рода точечный график со временем по оси X и суммой по оси Y, с линией, проходящей через данные, чтобы направлять взгляд зрителя. Если я использую сюжет panadas df.plot(style="o"), это не совсем правильно, потому что линии там нет. Я хотел бы что-то вроде примеров здесь.


person theQman    schedule 27.03.2015    source источник
comment
В общем, даты не очень хорошо поддерживаются в Seaborn. Тем не менее, вы можете получить некоторые ответы с хорошими способами сделать это несколько косвенно.   -  person mwaskom    schedule 27.03.2015
comment
Да, я заметил, что df.plot(style="o") дает мне даты, хорошо обозначенные по оси x, а sns.tsplot(s) - нет.   -  person theQman    schedule 27.03.2015
comment
Ссылка на ваши примеры мертва: '|   -  person waterproof    schedule 19.12.2017


Ответы (2)


примечание: это имеет много общего с ответом Яна Томпсона, но подход достаточно отличается, чтобы сделать его отдельным ответом. Я использую формат DataFrame, указанный в вопросе, и не меняю индекс.

Seaborn и другие библиотеки не так хорошо работают с осями даты и времени, как вам хотелось бы. Вот как я обойду это:

Начните с добавления столбца порядковых номеров дат

Seaborn справится с этим лучше, чем с финиками. Это удобный трюк для выполнения всевозможных математических операций с датами и библиотеками, которые не любят даты.

from datetime import date

df['date_ordinal'] = pd.to_datetime(df['date']).apply(lambda date: date.toordinal())

dataframe с порядковыми номерами

Сделайте график с порядковыми номерами на оси даты

ax = seaborn.regplot(
    data=df,
    x='date_ordinal',
    y='amount',
)
# Tighten up the axes for prettiness
ax.set_xlim(df['date_ordinal'].min() - 1, df['date_ordinal'].max() + 1)
ax.set_ylim(0, df['amount'].max() + 1)

Замените порядковые метки оси X красивыми, читаемыми датами.

ax.set_xlabel('date')
new_labels = [date.fromordinal(int(item)) for item in ax.get_xticks()]
ax.set_xticklabels(new_labels)

график с линией регрессии

та-даа!

person waterproof    schedule 18.12.2017
comment
Это круто! Я бы просто добавил, что мне пришлось использовать new_labels = [dt.date.fromordinal(int(item)) for item in ax.get_xticks()], так как у меня было import datetime as dt в верхней части моего скрипта. Я предполагаю, что этот ответ предполагает, что пользователь уже сделал from datetime import date. - person Tom Bush; 30.04.2020

Поскольку у Сиборна проблемы с датами, я собираюсь найти обходной путь. Во-первых, я сделаю столбец Date своим индексом:

# Make dataframe
df = pd.DataFrame({'amount' : [1,
                               1,
                               4,
                               1,
                               1]},
                  index = ['2014-01-06',
                           '2014-01-07',
                           '2014-01-08',
                           '2014-01-09',
                           '2014-01-14'])

Во-вторых, преобразуйте индекс в pd.DatetimeIndex:

# Make index pd.DatetimeIndex
df.index = pd.DatetimeIndex(df.index)

И замените им оригинал:

# Make new index
idx = pd.date_range(df.index.min(), df.index.max())

В-третьих, переиндексируйте с новым индексом (idx):

# Replace original index with idx
df = df.reindex(index = idx)

Это создаст новый фрейм данных со значениями NaN для дат, когда у вас нет данных:

редактировать дф

В-четвертых, поскольку Seaborn плохо работает с датами и линиями регрессии, я создам столбец количества строк, который мы можем использовать в качестве оси X:

# Insert row count
df.insert(df.shape[1],
          'row_count',
          df.index.value_counts().sort_index().cumsum())

В-пятых, теперь мы должны иметь возможность построить линию регрессии, используя «row_count» в качестве нашей переменной x и «amount» в качестве нашей переменной y:

# Plot regression using Seaborn
fig = sns.regplot(data = df, x = 'row_count', y = 'amount')

В-шестых, если вы хотите, чтобы даты располагались по оси x вместо row_count, вы можете установить метки x-тиков на индекс:

# Change x-ticks to dates
labels = [item.get_text() for item in fig.get_xticklabels()]

# Set labels for 1:10 because labels has 11 elements (0 is the left edge, 11 is the right
# edge) but our data only has 9 elements
labels[1:10] = df.index.date

# Set x-tick labels
fig.set_xticklabels(labels)

# Rotate the labels so you can read them
plt.xticks(rotation = 45)

# Change x-axis title
plt.xlabel('date')

plt.show();

изменить график 2

Надеюсь это поможет!

person Ian Thompson    schedule 21.09.2017