[python] Pandas 데이터 프레임에 누락 된 날짜 추가

내 데이터는 특정 날짜에 여러 이벤트를 포함하거나 특정 날짜에 이벤트가 없을 수 있습니다. 나는이 사건들을 가지고 날짜별로 카운트를 얻고 그것들을 플로팅합니다. 그러나 내가 그들을 플로팅 할 때 두 시리즈가 항상 일치하지는 않습니다.

idx = pd.date_range(df['simpleDate'].min(), df['simpleDate'].max())
s = df.groupby(['simpleDate']).size()

위의 코드에서 idx 는 30 일의 범위가됩니다. 2013 년 1 월 9 일 ~ 2013 년 9 월 30 일 그러나 S 는 주어진 날짜에 이벤트가 발생하지 않았기 때문에 25 일 또는 26 일 밖에 없을 수 있습니다. 그런 다음 플롯하려고 할 때 크기가 일치하지 않기 때문에 AssertionError가 발생합니다.

fig, ax = plt.subplots()    
ax.bar(idx.to_pydatetime(), s, color='green')

이 문제를 해결하는 적절한 방법은 무엇입니까? IDX 에서 값이없는 날짜를 제거하고 싶 습니까? 아니면 (차라리 수행하고 싶습니다) 계수가 0 인 누락 된 날짜를 시리즈에 추가합니다. 차라리 값이 0 인 30 일의 전체 그래프를 갖고 싶습니다. 이 접근 방식이 맞다면 시작하는 방법에 대한 제안이 있습니까? 일종의 동적 reindex기능이 필요 합니까?

다음은 S ( df.groupby(['simpleDate']).size() ) 의 스 니펫입니다 . 04와 05에는 항목이 없습니다.

09-02-2013     2
09-03-2013    10
09-06-2013     5
09-07-2013     1



답변

다음을 사용할 수 있습니다 Series.reindex.

import pandas as pd

idx = pd.date_range('09-01-2013', '09-30-2013')

s = pd.Series({'09-02-2013': 2,
               '09-03-2013': 10,
               '09-06-2013': 5,
               '09-07-2013': 1})
s.index = pd.DatetimeIndex(s.index)

s = s.reindex(idx, fill_value=0)
print(s)

수확량

2013-09-01     0
2013-09-02     2
2013-09-03    10
2013-09-04     0
2013-09-05     0
2013-09-06     5
2013-09-07     1
2013-09-08     0
...


답변

더 빠른 해결 방법은 .asfreq(). 내에서 호출하기 위해 새 색인을 만들 필요가 없습니다 .reindex().

# "broken" (staggered) dates
dates = pd.Index([pd.Timestamp('2012-05-01'), 
                  pd.Timestamp('2012-05-04'), 
                  pd.Timestamp('2012-05-06')])
s = pd.Series([1, 2, 3], dates)

print(s.asfreq('D'))
2012-05-01    1.0
2012-05-02    NaN
2012-05-03    NaN
2012-05-04    2.0
2012-05-05    NaN
2012-05-06    3.0
Freq: D, dtype: float64


답변

한 가지 문제는 reindex중복 값이 ​​있으면 실패 한다는 것입니다. 날짜별로 인덱싱하려는 타임 스탬프 데이터로 작업하고 있다고 가정 해 보겠습니다.

df = pd.DataFrame({
    'timestamps': pd.to_datetime(
        ['2016-11-15 1:00','2016-11-16 2:00','2016-11-16 3:00','2016-11-18 4:00']),
    'values':['a','b','c','d']})
df.index = pd.DatetimeIndex(df['timestamps']).floor('D')
df

수확량

            timestamps             values
2016-11-15  "2016-11-15 01:00:00"  a
2016-11-16  "2016-11-16 02:00:00"  b
2016-11-16  "2016-11-16 03:00:00"  c
2016-11-18  "2016-11-18 04:00:00"  d

중복 2016-11-16날짜 로 인해 재색 인 시도 :

all_days = pd.date_range(df.index.min(), df.index.max(), freq='D')
df.reindex(all_days)

실패 :

...
ValueError: cannot reindex from a duplicate axis

(이로써 인덱스 자체가 중복이 아니라 중복이 있음을 의미합니다)

대신 .loc다음과 같은 범위의 모든 날짜에 대한 항목을 조회하는 데 사용할 수 있습니다 .

df.loc[all_days]

수확량

            timestamps             values
2016-11-15  "2016-11-15 01:00:00"  a
2016-11-16  "2016-11-16 02:00:00"  b
2016-11-16  "2016-11-16 03:00:00"  c
2016-11-17  NaN                    NaN
2016-11-18  "2016-11-18 04:00:00"  d

fillna 필요한 경우 공백을 채우기 위해 열 시리즈에 사용할 수 있습니다.


답변

대체 방법은 resample누락 된 날짜 외에도 중복 날짜를 처리 할 수있는입니다. 예를 들면 :

df.resample('D').mean()

resample지연된 작업 groupby이므로 다른 작업을 따라야합니다. 이 사건에서 mean잘 작동하지만 당신은 또한 같은 많은 다른 팬더 방법을 사용할 수 있습니다 max, sum

다음은 원본 데이터이지만 ‘2013-09-03’에 대한 추가 항목이 있습니다.

             val
date           
2013-09-02     2
2013-09-03    10
2013-09-03    20    <- duplicate date added to OP's data
2013-09-06     5
2013-09-07     1

결과는 다음과 같습니다.

             val
date            
2013-09-02   2.0
2013-09-03  15.0    <- mean of original values for 2013-09-03
2013-09-04   NaN    <- NaN b/c date not present in orig
2013-09-05   NaN    <- NaN b/c date not present in orig
2013-09-06   5.0
2013-09-07   1.0

이것이 어떻게 작동하는지 명확하게하기 위해 누락 된 날짜를 NaN으로 남겨 두었지만 fillna(0)OP에서 요청한대로 NaN을 0으로 대체하도록 추가 하거나 interpolate()이웃 행을 기반으로 0이 아닌 값으로 채우는 것과 같은 것을 사용할 수 있습니다.


답변

여기에 좋은의 선택과 더불어, dataframe에 날짜를 누락 채우는 방법이다 fill_value, days_back기입하고, 정렬 순서 ( date_orderdataframe을 정렬하는이) :

def fill_in_missing_dates(df, date_col_name = 'date',date_order = 'asc', fill_value = 0, days_back = 30):

    df.set_index(date_col_name,drop=True,inplace=True)
    df.index = pd.DatetimeIndex(df.index)
    d = datetime.now().date()
    d2 = d - timedelta(days = days_back)
    idx = pd.date_range(d2, d, freq = "D")
    df = df.reindex(idx,fill_value=fill_value)
    df[date_col_name] = pd.DatetimeIndex(df.index)

    return df


답변