Переиндексация Pandas для заполнения пропущенных дат или лучший метод для заполнения?

Мои данные - это записи об отсутствии с завода. В некоторые дни нет пропусков, поэтому для этого дня нет данных или даты. Однако, и там, где это становится неуместным с другими показанными примерами, в любой день может быть несколько отсутствий по разным причинам. Соотношение даты и записи в данных не всегда равно 1:1.

Результат, на который я надеюсь, выглядит примерно так:

(index)    Shift        Description     Instances (SUM)
01-01-14   2nd Baker    Discipline      0
01-01-14   2nd Baker    Vacation        0
01-01-14   1st Cooks    Discipline      0
01-01-14   1st Cooks    Vacation        0
01-02-14   2nd Baker    Discipline      4
01-02-14   2nd Baker    Vacation        3
01-02-14   1st Cooks    Discipline      3
01-02-14   1st Cooks    Vacation        3

И так далее. Идея заключается в том, что все смены и описания будут иметь значения для всех дней периода времени (в этом примере с 01.01.2014 по 31.12.2014).

Я прочитал несколько примеров, и ближе всего к этой работе я подошел к здесь.

ts = pd.read_csv('Absentee_Data_2.csv'
                , encoding = 'utf-8'
                ,parse_dates=[3]
                ,index_col=3
                ,dayfirst=True
                )

idx =  pd.date_range('01.01.2009', '12.31.2017')

ts.index = pd.DatetimeIndex(ts.index)
# ts = ts.reindex(idx, fill_value='NaN')
df = pd.DataFrame(index = idx)
df1 = df.join(ts, how='left')

Но когда я раскомментирую ts = ts.reindex(idx, fill_value='NaN'), я получаю сообщения об ошибках. Я пробовал как минимум 10 других способов добиться того, что я пытаюсь сделать, поэтому я не уверен на 100%, что это правильный путь, но, похоже, он приблизил меня к какому-либо прогрессу.

Вот некоторые примеры данных:

Description Unexcused   Instances   Date        Shift
Discipline  FALSE              1    Jan 2 2014  2nd Baker
Vacation    TRUE               2    Jan 2 2014  1st Cooks
Discipline  FALSE              3    Jan 2 2014  2nd Baker
Vacation    TRUE               1    Jan 2 2014  1st Cooks
Discipline  FALSE              2    Apr 8 2014  2nd Baker
Vacation    TRUE               3    Apr 8 2014  1st Cooks
Discipline  FALSE              1    Jun 1 2014  2nd Baker
Vacation    TRUE               2    Jun 1 2014  1st Cooks
Discipline  FALSE              3    Jun 1 2014  2nd Baker
Vacation    TRUE               1    Jun 1 2014  1st Cooks
Vacation    TRUE               2    Jul 5 2014  1st Cooks
Discipline  FALSE              3    Jul 5 2014  2nd Baker
Vacation    TRUE               2    Dec 3 2014  1st Cooks

Заранее спасибо за помощь, я новичок и уже 2 дня без особого прогресса. Я очень ценю то, как люди здесь помогают с ответами, но самое главное — с инструкциями о том, почему решения работают. Такие новички, как я, очень благодарны за то, что поделились мудростью.


person Python_Learner_DK    schedule 04.08.2017    source источник


Ответы (2)


Я думаю, у вас просто проблема с использованием даты и времени, этот подход сработал для меня

ts.set_index(['Date'],inplace=True)
ts.index = pd.to_datetime(ts.index,format='%b %d %Y')
d2 = pd.DataFrame(index=pd.date_range('2014-01-01','2014-12-31'))

print ts.join(d2,how='right')
person DJK    schedule 04.08.2017
comment
Оба ответа сработали, но этот мне было легче понять и прокрутить с моими реальными данными. Мне действительно пришлось провести некоторые дальнейшие манипуляции и обдумать, но в конечном итоге я использовал именно этот ответ. - person Python_Learner_DK; 08.08.2017
comment
У меня тоже сработало! У меня был фрейм данных smeidum с 900 000 строк, и я хотел добавить недостающие даты перед поворотом. Спасибо! - person Linwoodc3; 26.05.2019

На самом деле вы были довольно близки к тому, что хотели (при условии, что я правильно понял результат, который вы, кажется, ищете). Смотрите мои дополнения к вашему коду выше:

import pandas as pd

ts = pd.read_csv('Absentee_Data_2.csv', encoding = 'utf-8',parse_dates=[3],index_col=3,dayfirst=True, sep=",")

idx =  pd.date_range('01.01.2009', '12.31.2017')

ts.index = pd.DatetimeIndex(ts.index)
#ts = ts.reindex(idx, fill_value='NaN')
df = pd.DataFrame(index = idx)
df1 = df.join(ts, how='left')
df2 = df1.copy()
df3 = df1.copy()
df4 = df1.copy()
dict1 = {'Description': 'Discipline', 'Instances': 0, 'Shift': '1st Cooks'}
df1 = df1.fillna(dict1)
dict1["Description"] = "Vacation"
df2 = df2.fillna(dict1)
dict1["Shift"] = "2nd Baker"
df3 = df3.fillna(dict1)
dict1["Description"] = "Discipline"
df4 = df4.fillna(dict1)
df_with_duplicates = pd.concat([df1,df2,df3,df4])
final_res = df_with_duplicates.reset_index().drop_duplicates(subset=["index"] + list(dict1.keys())).set_index("index").drop("Unexcused", axis=1)

В основном, что бы вы добавили:

  • Скопируйте 4 раза почти пустой df, созданный с помощью ts (df1)
  • fillna(dict1) позволяет заполнить статическими значениями все NaN в столбцах
  • Объедините 4 dfs, нам все еще нужно удалить некоторые дубликаты, так как исходные значения из csv дублируются 4 раза.
  • Отбросьте дубликаты, нам нужен индекс, чтобы сохранить добавленные значения, поэтому reset_index следует за `set_index("index")
  • Наконец, удалите столбец Unexcused.

Напоследок несколько выводов:

In [5]: final_res["2013-01-2"]
Out[5]: 
           Description  Instances      Shift
index                                       
2013-01-02  Discipline        0.0  1st Cooks
2013-01-02    Vacation        0.0  1st Cooks
2013-01-02    Vacation        0.0  2nd Baker
2013-01-02  Discipline        0.0  2nd Baker

In [6]: final_res["2014-01-2"]
Out[6]: 
           Description  Instances       Shift
index                                        
2014-01-02  Discipline        1.0   2nd Baker
2014-01-02    Vacation        2.0   1st Cooks
2014-01-02  Discipline        3.0   2nd Baker
2014-01-02    Vacation        1.0   1st Cooks
1
person Adonis    schedule 04.08.2017
comment
пробую это решение, но продолжаю получать следующую ошибку: «Ошибка типа: можно только объединить список (не dict_keys) со списком» в следующей строке кода: final_res = (df_with_duplicates.reset_index() .drop_duplicates(subset=[index] + dict1.keys()) .set_index(index).drop(Unexcused, axis=1)) Любые предложения? Спасибо и вам за объяснение тоже :) - person Python_Learner_DK; 07.08.2017
comment
@SDS Плохо, небольшая опечатка, вам нужно преобразовать ключи dict1 в список, поэтому он должен быть subse‌​t=["index"] + list(dict1.keys()), я отредактировал свой пост - person Adonis; 07.08.2017
comment
@SDS Если вы считаете, что ответ был предоставлен, отметьте его как принятый. Это помогает сосредоточиться на оставшихся без ответа вопросах. Если ответы не помогли, можете ли вы дать отзыв о том, чего не хватает? - person Adonis; 08.08.2017