упорядочение данных по дате (формат месяц/день)

#python #pandas #sorting #time-series #pandas-groupby

Вопрос:

После того, как я добавлю 4 разных кадра данных в:

 list_1 = [ ]
 

У меня есть следующие данные, хранящиеся в list_1:

 | date       | 16/17 | 
| --------   | ------|
| 2016-12-29 | 50    | 
| 2016-12-30 | 52    | 
| 2017-01-01 | 53    | 
| 2017-01-02 | 51    |
[4 rows x 1 columns],
             16/17

| date       | 17/18 | 
| --------   | ------| 
| 2017-12-29 | 60    | 
| 2017-12-31 | 62    | 
| 2018-01-01 | 64    | 
| 2018-01-03 | 65    | 
[4 rows x 1 columns],
             17/18

| date       | 18/19 |
| --------   | ------| 
| 2018-12-30 | 54    | 
| 2018-12-31 | 53    | 
| 2019-01-02 | 52    | 
| 2019-01-03 | 51    | 
[4 rows x 1 columns],
             18/19

| date       | 19/20 |
| --------   | ------| 
| 2019-12-29 | 62    | 
| 2019-12-30 | 63    | 
| 2020-01-01 | 62    | 
| 2020-01-02 | 60    | 
[4 rows x 1 columns],
             19/20
 

Для изменения формата даты на месяц/день я использую следующий код:

 pd.to_datetime(df['date']).dt.strftime('%m/%d')
 

Но проблема в том, что я хочу упорядочить данные по месяцам/дням таким образом:

 | date     | 16/17 | 17/18 | 18/19 | 19/20 |
| -------- | ------| ------| ------| ------|
| 12/29    | 50    | 60    | NaN   | 62    |
| 12/30    | 52    | NaN   | 54    | 63    |
| 12/31    | NaN   | 62    | 53    | NaN   |
| 01/01    | 53    | 64    | NaN   | 62    |
| 01/02    | 51    | NaN   | 52    | 60    |
| 01/03    | NaN   | 65    | 51    | NaN   |
 

Я попробовал следующее:

 df = pd.concat(list_1,axis=1)
 

тоже:

 df = pd.concat(list_1)
df.reset_index(inplace=True)
df = df.groupby(['date']).first()
 

тоже:

 df = pd.concat(list_1)
df.reset_index(inplace=True)
df = df.groupby(['date'] sort=False).first()
 

но все равно не удается достичь желаемого результата.

Комментарии:

1. Вы пытаетесь pivot создать свой фрейм данных?

2. Я не уверен в повороте, Люк. Я просто хочу сравнить данные за разные годы по месяцам/дням (следовательно, формат месяц/день), сохраняя при этом порядок дат (начиная с 12/29 и заканчивая 01/03, как в примере).

Ответ №1:

Вы можете использовать sort=False в groupby и создать новый столбец для вычитания по первому значению DatetimeIndex и использовать его для сортировки:

 def f(x):
    x.index = pd.to_datetime(x.index)
    return x.assign(new =  x.index - x.index.min())

L = [x.pipe(f) for x in list_1]
df = pd.concat(L, axis=0).sort_values('new', kind='mergesort')

df = df.groupby(df.index.strftime('%m/%d'), sort=False).first().drop('new', axis=1)
print (df)
       16/17  17/18  18/19  19/20
date                             
12/29   50.0   60.0    NaN   62.0
12/30   52.0    NaN   54.0   63.0
12/31    NaN   62.0   53.0    NaN
01/01   53.0   64.0    NaN   62.0
01/02   51.0    NaN   52.0   60.0
01/03    NaN   65.0   51.0    NaN
 

Комментарии:

1. Спасибо тебе, израэль, за предложение! Проблема, когда я пытаюсь это сделать, заключается в том, что новый кадр данных начинается с 01/01, а не с 12/29, как хотелось бы. Есть ли какой-либо способ сохранить порядок дат (чтобы начать с 12/29 и закончить 01/03, как в примере для желаемого результата)?

2. Я тоже пробовал это сделать. Он сохраняет порядок, но группирует данные по первому столбцу (16/17), а строки, такие как 12/31 (где значение 16/17 равно NaN), перемещаются вниз и не остаются на месте. @израэль

3. @kobo — Ответ был отредактирован.

4. Это работает идеально, спасибо! И какие-нибудь советы, если у меня будет больше месяцев? Например, если данные начинаются с 09/30 и заканчиваются 03/30, соблюдая ту же логику. @израэль