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


127

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

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

답변:


256

다음을 사용할 수 있습니다 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
...

23
reindex놀라운 기능입니다. (1) 새 레이블 집합과 일치하도록 기존 데이터의 순서를 다시 지정하고, (2) 이전에 레이블이없는 새 행을 삽입하고, (3) 누락 된 레이블에 대한 데이터를 채울 수 있습니다. (앞 / 뒤 채우기 포함) (4) 행 선택 라벨로!
unutbu

@unutbu 이것은 내가 가진 질문의 일부에 대답합니다, 감사합니다! 그러나 이벤트가있는 날짜로 목록을 동적으로 만드는 방법을 알고 있는지 궁금하십니까?
Nick Duddy

2
reindex에는 한 가지 문제 (또는 버그)가 있습니다. 1970 년 1 월 1 일 이전의 날짜에서는 작동하지 않으므로이 경우 df.resample ()이 완벽하게 작동합니다.
세르게이 Gulbin

2
대신 idx가 시작 및 종료 날짜를 수동으로 입력하는 것을 건너 뛸 수 있습니다.idx = pd.date_range(df.index.min(), df.index.max())
Reveille

검색 내용을 저장하려면 여기에 문서 링크를 놓으세요
Harm te Molder

40

더 빠른 해결 방법은 .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

1
저는이 방법을 정말 선호합니다. date_range첫 번째와 마지막 인덱스를 시작과 끝으로 암시 적으로 사용하므로 호출 할 필요가 없습니다 (거의 항상 원하는 것입니다).
Michael Hays

매우 깨끗하고 전문적인 방법. 나중에 보간을 사용할 때도 잘 작동합니다.
msarafzadeh

26

한 가지 문제는 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 필요한 경우 공백을 채우기 위해 열 시리즈에 사용할 수 있습니다.


날짜 열에 Blanks또는 포함 된 경우 수행 할 작업에 대한 아이디어가 NULLS있습니까? df.loc[all_days]이 경우 작동하지 않습니다.
Furqan Hashim

1
누락 된 레이블이있는 .loc 또는 []에 list-likes를 전달하면 나중에 KeyError가 발생합니다. 대신 .reindex ()를 사용할 수 있습니다. 여기에 문서를 참조하십시오 : pandas.pydata.org/pandas-docs/stable/...
Dmitrii 마 가스

19

대체 방법은 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이 아닌 값으로 채우는 것과 같은 것을 사용할 수 있습니다.


6

여기에 좋은의 선택과 더불어, 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.