有条件地向后填充python中的列

时间:2019-05-01 17:33:43

标签: python

我有一个如下的数据集(样本)

Date             Value
2019-05-01        0
2019-05-02        0
2019-05-03        0
2019-05-04        0
2019-05-05        0
2019-05-06        0
2019-05-07        0
2019-05-08        1
2019-05-09        0

我想对其进行转换,以便在遇到Value = 1时,将2天前的3个值取为1。并将当前值设置为0。 换句话说,转换后的数据集应该看起来像这样

Date             Value
2019-05-01        0
2019-05-02        0
2019-05-03        1
2019-05-04        1
2019-05-05        1
2019-05-06        0
2019-05-07        0
2019-05-08        0
2019-05-09        0

请注意,在上面的示例中,转换后将2019-05-08设置为0,并将2019-05-03至2019-05-05设置为1(最后设置为1的值是在转换前2天2019-05-08和2019-05-05之前的3天也设置为1)。 如果两个连续的值显示为1,我们将从显示为1的最后一个值开始日期计算。 我想我可以通过for循环来做到这一点,但一直在寻找是否有任何内置函数可以帮助我解决这个问题。 谢谢!

3 个答案:

答案 0 :(得分:1)

可能有更精确的方法来解决此问题。但是,我只能考虑使用索引值(例如i),其中Value==1来解决此问题,然后在之前的位置获取索引值(前2个日期表示i-3,然后在其上方的两个值表示i- 4,i-5),并将Value分配给1。最后,将Value最初找到的索引位置的Value==1设置回0。

In [53]: df = pd.DataFrame({'Date':['2019-05-01','2019-05-02', '2019-05-03','2019-05-04','2019-05-05', '2019-05-06','20
    ...: 19-05-07','2019-05-08','2019-05-09'], 'Value':[0,0,0,0,0,0,0,1,0]})
    ...:
    ...:

In [54]: val_1_index = df.loc[df.Value == 1].index.tolist()

In [55]: val_1_index_decr = [(i-3, i-4, i-5) for i in val_1_index]

In [56]: df.loc[df['Value'].index.isin([i for i in val_1_index_decr[0]]), 'Value'] = 1

In [57]: df.loc[df['Value'].index.isin(val_1_index), 'Value'] = 0

In [58]: df
Out[58]:
         Date  Value
0  2019-05-01      0
1  2019-05-02      0
2  2019-05-03      1
3  2019-05-04      1
4  2019-05-05      1
5  2019-05-06      0
6  2019-05-07      0
7  2019-05-08      0
8  2019-05-09      0

答案 1 :(得分:1)

一种解决方案,假设df是您的原始数据帧:

df['Value'] = pd.Series([1 if 1 in df.iloc[i+3:i+6].values else 0 for i in df.index])

在这里,我处理索引而不是日期,所以我假设您每行有一天,并且天是连续的,如示例所示。

也适合此请求:

  

如果两个连续的值显示为1,我们将从显示为1的最后一个值开始日期计算。

我可以提出两行解决方案:

validones = [True if df.iloc[i]['Value'] == 1 and df.iloc[i+1]['Value'] == 0 else False for i in df.index]
df['Value'] = pd.Series([1 if any(validones[i+3:i+6]) else 0 for i in range(len(validones))])

基本上,我首先建立一个布尔值列表,以检查df['Value']中的1是否后面没有另一个1,然后使用该布尔值列表进行替换。

答案 2 :(得分:0)

不确定该解决方案的效率,因为一个人需要创建三个新列,但这也行得通:

df['shiftedValues'] = \
           df['Value'].shift(-3, fill_value=0) + \
           df['Value'].shift(-4, fill_value=0) + \
           df['Value'].shift(-5, fill_value=0)

请注意,转换是按行而不是按天完成的。

要按实际天数移动,我首先要按日期编制索引

df['Date'] = pd.to_datetime(df['Date'])
df = df.set_index('Date')

df['shiftedValues'] = \
df['Value'].shift(-3, freq='1D', fill_value=0).asof(df.index) + \
df['Value'].shift(-4, freq='1D', fill_value=0).asof(df.index) + \
df['Value'].shift(-5, freq='1D', fill_value=0).asof(df.index)
# Out:
#             Value  shiftedValues
# Date                            
# 2019-05-01      0            0.0
# 2019-05-02      0            0.0
# 2019-05-03      0            1.0
# 2019-05-04      0            1.0
# 2019-05-05      0            1.0
# 2019-05-06      0            0.0
# 2019-05-07      0            0.0
# 2019-05-08      1            0.0
# 2019-05-09      0            0.0

现在,这对于日期是正确的,例如,如果df是(请注意缺少和重复的日期)

         Date  Value
0  2019-05-01      0
1  2019-05-02      0
2  2019-05-03      0
3  2019-05-04      0
4  2019-05-05      0
5  2019-05-05      0
6  2019-05-07      0
7  2019-05-08      1
8  2019-05-09      0

那么你就得到

            Value  shiftedValues
Date                            
2019-05-01      0            0.0
2019-05-02      0            0.0
2019-05-03      0            1.0
2019-05-04      0            1.0
2019-05-05      0            1.0
2019-05-05      0            1.0
2019-05-07      0            0.0
2019-05-08      1            0.0
2019-05-09      0            0.0