以下是输入熊猫数据框的示例:
**LastUpdate** **Whatever** ...
2017-12-30 xxx ...
2017-12-30 yyy ...
2017-12-30 zzz ...
2018-01-01 yyy ...
2018-01-03 zzz ...
这是预期的DF(输出):
**LastUpdate** **Whatever** ...
2017-12-30 xxx ...
2017-12-30 yyy ...
2017-12-30 zzz ...
2017-12-31 xxx ...
2017-12-31 yyy ...
2017-12-31 zzz ...
2018-01-01 yyy ...
2018-01-02 yyy ...
2018-01-03 zzz ...
如您所见,数据中的丢失日期将仅重复前一天的行,以便我用(所有)前一天数据填充缺失的日期。事实是,每天的行数可能会有所不同,所以这实际上并没有帮助。
重要提示:两天之内可能会缺少 多于一天 (它可能会在2018年1月1日至2018年1月5日,因此我需要将这两天之间所有缺少的日期相加,并使用与2018年1月1日相同的数据(行/内容的行数完全相同),即有可用数据的最后一天
我已经进行了一些研究,并提出了resample,ffill和reset_index方法,但由于它需要唯一的日期,因此它似乎不适合我的具体情况索引,这里不是这种情况,因为一天可能会关联几行。
到目前为止,我已经尝试过:
df['Last Update'] = pd.to_datetime(df['Last Update'])
df.set_index("Last Update", inplace=True)
dfResult = df.resample('D').ffill().reset_index()
产生cannot reindex a non-unique index with a method or limit
(这完全是有道理的),但我真的想不出一种方法来实现自己的目标。
让我知道是否有任何不清楚的地方,或者如果您需要更多其他信息,我们将不胜感激
答案 0 :(得分:3)
# This solution should also work for multiple columns.
# Setup.
df['Whatever2'] = df['Whatever'].map({'xxx':'a', 'yyy':'b', 'zzz':'c'})
df
LastUpdate Whatever Whatever2
0 2017-12-30 xxx a
1 2017-12-30 yyy b
2 2017-12-30 zzz c
3 2018-01-01 yyy b
4 2018-01-05 zzz c
5 2018-01-06 xxx a
6 2018-01-06 xxx a
7 2018-01-09 yyy b
使用set_index
+ unstack
,然后再次使用reindex
和stack
。
# If required, convert "LastUpdate" to `datetime`.
# df['LastUpdate'] = pd.to_datetime(df['LastUpdate'], errors='coerce')
(df.set_index(['LastUpdate', df.groupby('LastUpdate').cumcount()])
.unstack(1, fill_value='')
.reindex(pd.date_range(df['LastUpdate'].min(), df['LastUpdate'].max()))
.ffill()
.replace('', np.nan)
.stack(1)
.reset_index(level=1, drop=True)
.rename_axis('LastUpdate').reset_index())
LastUpdate Whatever Whatever2
0 2017-12-30 xxx a
1 2017-12-30 yyy b
2 2017-12-30 zzz c
3 2017-12-31 xxx a
4 2017-12-31 yyy b
5 2017-12-31 zzz c
6 2018-01-01 yyy b
7 2018-01-02 yyy b
8 2018-01-03 yyy b
9 2018-01-04 yyy b
10 2018-01-05 zzz c
11 2018-01-06 xxx a
12 2018-01-06 xxx a
13 2018-01-07 xxx a
14 2018-01-07 xxx a
15 2018-01-08 xxx a
16 2018-01-08 xxx a
17 2018-01-09 yyy b
首先,设置索引。使用cumcount
获取重复日期的计数。这是确定新日期必须重复多少次所必需的。
df.groupby('LastUpdate').cumcount().to_numpy()
# array([0, 1, 2, 0, 0, 0, 1, 0])
df.set_index(['LastUpdate', df.groupby('LastUpdate').cumcount()])
Whatever Whatever2
LastUpdate
2017-12-30 0 xxx a
1 yyy b
2 zzz c
2018-01-01 0 yyy b
2018-01-05 0 zzz c
2018-01-06 0 xxx a
1 xxx a
2018-01-09 0 yyy b
接下来,使用unstack
。我使用fill_value=''
作为下一步(向前填充)的方块。
_.unstack(1, fill_value='')
Whatever Whatever2
0 1 2 0 1 2
LastUpdate
2017-12-30 xxx yyy zzz a b c
2018-01-01 yyy b
2018-01-05 zzz c
2018-01-06 xxx xxx a a
2018-01-09 yyy b
您现在可以使用reindex
来添加缺少的日期:
_.reindex(pd.date_range(df['LastUpdate'].min(), df['LastUpdate'].max()))
Whatever Whatever2
0 1 2 0 1 2
2017-12-30 xxx yyy zzz a b c
2017-12-31 NaN NaN NaN NaN NaN NaN
2018-01-01 yyy b
2018-01-02 NaN NaN NaN NaN NaN NaN
2018-01-03 NaN NaN NaN NaN NaN NaN
2018-01-04 NaN NaN NaN NaN NaN NaN
2018-01-05 zzz c
2018-01-06 xxx xxx a a
2018-01-07 NaN NaN NaN NaN NaN NaN
2018-01-08 NaN NaN NaN NaN NaN NaN
2018-01-09 yyy b
现在,向前填充可将昨天的i th 数据分配给缺失日期中的相应位置。
_.ffill()
Whatever Whatever2
0 1 2 0 1 2
2017-12-30 xxx yyy zzz a b c
2017-12-31 xxx yyy zzz a b c
2018-01-01 yyy b
2018-01-02 yyy b
2018-01-03 yyy b
2018-01-04 yyy b
2018-01-05 zzz c
2018-01-06 xxx xxx a a
2018-01-07 xxx xxx a a
2018-01-08 xxx xxx a a
2018-01-09 yyy b
用NaN和stack
替换填充值。
_.replace('', np.nan).stack(1)
Whatever Whatever2
2017-12-30 0 xxx a
1 yyy b
2 zzz c
2017-12-31 0 xxx a
1 yyy b
2 zzz c
2018-01-01 0 yyy b
2018-01-02 0 yyy b
2018-01-03 0 yyy b
2018-01-04 0 yyy b
2018-01-05 0 zzz c
2018-01-06 0 xxx a
1 xxx a
2018-01-07 0 xxx a
1 xxx a
2018-01-08 0 xxx a
1 xxx a
2018-01-09 0 yyy b
在那之后,它正在清理索引。
答案 1 :(得分:2)
这就是我的做法。我将使用一个稍微复杂些的示例,该示例是从您的示例输入中扩展而来的,目的是证明我的方法满足所有要求:
df = pd.DataFrame(columns = ['LastUpdate', 'Whatever', 'Column2'],
data = [['2017-12-30', 'xxx', 'a'],
['2017-12-30', 'yyy', 'b'],
['2017-12-30', 'zzz', 'c'],
['2018-01-01', 'yyy', 'b'],
['2018-01-05', 'zzz', 'c'],
['2018-01-06', 'xxx', 'a'],
['2018-01-06', 'xxx', 'a'],
['2018-01-09', 'yyy', 'b']])
df
LastUpdate Whatever Column2
0 2017-12-30 xxx a
1 2017-12-30 yyy b
2 2017-12-30 zzz c
3 2018-01-01 yyy b
4 2018-01-05 zzz c
5 2018-01-06 xxx a
6 2018-01-06 xxx a
7 2018-01-09 yyy b
LastUpdate
列设置为df的索引,并将索引类型设置为DatetimeIndex:df.set_index('LastUpdate', drop=True, inplace=True)
df.index = pd.to_datetime(df.index)
all_days = pd.date_range(df.index.min(), df.index.max(), freq='D')
missing_dates = [i for i in all_days if i not in df.index]
new_dfs = []
most_recent = df.index[0]
for i in missing_dates:
if i-1 in df.index:
most_recent = i-1
to_insert = pd.DataFrame(df.loc[most_recent])
print(to_insert.shape)
print(to_insert)
if to_insert.shape[1] == 1: # Ensure new df's row-index contains the date if most recent non-missing date had only one row
to_insert = to_insert.T
shift_amt = i - most_recent
to_insert = to_insert.shift(shift_amt.days, freq='D')
new_dfs.append(to_insert)
for i in new_dfs:
top_idx = pd.date_range(df.index.min(), i.shift(-1, freq='D').index.min(), freq='D')
top = df.loc[top_idx]
bottom_len = len(df.index) - len(top)
bottom = df.iloc[-bottom_len:]
df = pd.concat([top, i, bottom])
结果数据框如下所示。所有缺少的日期(包括单次和连续的)都填充了与属于最近的非缺失日期的那一行相同的行:
df
Whatever Column2
2017-12-30 xxx a
2017-12-30 yyy b
2017-12-30 zzz c
2017-12-31 xxx a
2017-12-31 yyy b
2017-12-31 zzz c
2018-01-01 yyy b
2018-01-02 yyy b
2018-01-03 yyy b
2018-01-04 yyy b
2018-01-05 zzz c
2018-01-06 xxx a
2018-01-06 xxx a
2018-01-07 xxx a
2018-01-07 xxx a
2018-01-08 xxx a
2018-01-08 xxx a
2018-01-09 yyy b