下面是输入数据帧大熊猫的样品:
**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
(这完全是有道理的),但我真的不能想出一个办法来实现我想要做的事。让我知道如果有不清楚的地方,或者如果你需要更多的附加信息,任何帮助,将不胜感激
# 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个数据分配给丢失的日期的相应位置。
_.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
与南,和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
在此之后,它的清理指数。
以下是我做到了。我会用一个稍微复杂一点的例子,这是我从您的样品输入延伸,以证明我的方法满足所有要求:
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])
所得到的数据框看起来是这样的。所有丢失的日期,单次和连续的,已经充满了行(S)等同于/那些属于最近的非缺失日期:
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