复制前一天的行所有失踪日期数据帧

问题描述 投票:5回答:2

下面是输入数据帧大熊猫的样品:

**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日,是根据现有数据的最后一天。

我做了一些研究,并与resampleffillreset_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(这完全是有道理的),但我真的不能想出一个办法来实现我想要做的事。让我知道如果有不清楚的地方,或者如果你需要更多的附加信息,任何帮助,将不胜感激

python pandas dataframe
2个回答
3
投票

Setup

# 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

Solution

使用set_index + unstack,然后reindexstack一次。

# 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

Details

首先,设置索引。使用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

在此之后,它的清理指数。


2
投票

以下是我做到了。我会用一个稍微复杂一点的例子,这是我从您的样品输入延伸,以证明我的方法满足所有要求:

  • 在数据丢失的日子简单重复前一天的行(S)
  • 所有的连续丢失的日子充满了属于最新的非缺失当天所有的行(S)
  • 支持多列
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
  1. 设置LastUpdate列作为DF的指数,并设置索引类型的DatetimeIndex:
df.set_index('LastUpdate', drop=True, inplace=True)
df.index = pd.to_datetime(df.index)
  1. 创建包括在原始DF索引的最小值和最大值之间的所有时间(两者都存在和缺失)的日期范围。
all_days = pd.date_range(df.index.min(), df.index.max(), freq='D')

  1. 创建代表的日期从原来的DF指数失踪时间戳列表:
missing_dates = [i for i in all_days if i not in df.index]

  1. 创建的每一个失踪日期新dataframes列表。有些会有多行,而其他人将有一行。每个数据帧将在给定的缺失日期索引:
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)
  1. 最后一步。对于要插入每一个新的数据框,我们我们原来的DF分成上下两部分,并使用pd.concat的上半部分,一个部分缺失数据的新数据框,和下半部分结合:
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
© www.soinside.com 2019 - 2024. All rights reserved.