2013-10-11 39 views
48

Dữ liệu của tôi có thể có nhiều sự kiện vào một ngày cụ thể hoặc KHÔNG có sự kiện nào vào một ngày. Tôi lấy những sự kiện này, đếm theo ngày và vẽ chúng. Tuy nhiên, khi tôi vẽ chúng, hai bộ phim của tôi không phải lúc nào cũng phù hợp.Thêm ngày bị thiếu vào khung dữ liệu gấu trúc

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

Trong mã ở trên idx trở thành một loạt các nói 30 ngày. 09-01-2013 đến 09-30-2013 Tuy nhiên S chỉ có thể có 25 hoặc 26 ngày vì không có sự kiện nào xảy ra trong một ngày nhất định. Sau đó tôi nhận được một AssertionError như các kích thước không phù hợp khi tôi cố gắng âm mưu:

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

Cách thích hợp để giải quyết vấn đề này là gì? Tôi có muốn xóa ngày không có giá trị từ IDX hoặc (mà tôi muốn làm) thêm vào chuỗi ngày bị thiếu với số lượng là 0. Tôi muốn có biểu đồ đầy đủ 30 ngày với 0 giá trị . Nếu phương pháp này là đúng, bất kỳ đề xuất về cách bắt đầu? Tôi có cần một số chức năng động reindex không?

Dưới đây là một đoạn S (df.groupby(['simpleDate']).size()), chú ý không có mục cho 04 và 05.

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

Trả lời

115

Bạn có thể sử dụng 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) 

sản lượng

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 
... 
+2

wow cảm ơn! Tôi không hoàn toàn hiểu được reindex hoạt động tốt như thế nào. – KHibma

+12

'reindex' là một chức năng tuyệt vời. Nó có thể (1) sắp xếp lại dữ liệu hiện có để phù hợp với một bộ nhãn mới, (2) chèn các hàng mới mà không có nhãn nào tồn tại trước đó, (3) điền dữ liệu cho các nhãn bị thiếu, (bao gồm cả điền/lùi) (4) chọn hàng theo nhãn! – unutbu

+0

@unutbu Câu trả lời này cũng là một phần của câu hỏi tôi cảm ơn! Nhưng đã tự hỏi nếu bạn biết làm thế nào để tự động tạo ra một danh sách với những ngày có sự kiện? –

2

Đây là một phương pháp hay để điền vào các ngày thiếu một dataframe, với sự lựa chọn của bạn của fill_value, days_back để điền vào, và sắp xếp theo thứ tự (date_order) mà theo đó để sắp xếp các dataframe:

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 
11

Một vấn đề là reindex sẽ thất bại nếu có giá trị nhân bản. Nói rằng chúng tôi đang làm việc với dữ liệu ghi lại ngày tháng, mà chúng tôi muốn đánh chỉ mục theo ngày:

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 

mang

  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 

Do ngày trùng lặp 2016-11-16, một nỗ lực để reindex:

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

không thành công với:

... 
ValueError: cannot reindex from a duplicate axis 

(bằng cách này nó có nghĩa là chỉ số có bản sao, không phải là nó là chính nó một dup)

Thay vào đó, chúng ta có thể sử dụng .loc để tìm kiếm mục cho tất cả các ngày trong khoảng:

df.loc[all_days] 

sản lượng

  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 có thể được sử dụng trên hàng loạt cột để điền vào chỗ trống nếu cần.

6

Giải pháp nhanh hơn là sử dụng asfreq(). Điều này không yêu cầu tạo chỉ mục mới để gọi trong vòng reindex(). *

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 

* Ít nhất không phải bởi người dùng. Điều đó rất tốt có thể được gọi là dưới mui xe.

2

Trong nhiều trường hợp, resample(see documentation here) cung cấp giải pháp chung có thể xử lý cả ngày bị thiếu và trùng lặp. Ví dụ:

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

resample là một hoạt động chậm như groupby vì vậy bạn cần phải làm theo nó với hoạt động khác. Trong trường hợp này mean hoạt động tốt, nhưng bạn cũng có thể sử dụng nhiều phương pháp gấu trúc tiêu chuẩn có như max, sum vv

Đây là dữ liệu gốc, nhưng với một mục bổ sung cho '2013/09/03':

  val 
date   
2013-09-02 2 
2013-09-03 10 
2013-09-03 20 
2013-09-06 5 
2013-09-07 1 

Và đây là kết quả:

   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 

Lưu ý rằng sau này bạn có thể sử dụng các phương pháp như fillna hoặc interpolate để điền vào các giá trị thiếu như mong muốn.

Các vấn đề liên quan