设定值给定两栏

时间:2018-12-21 18:44:08

标签: python pandas

我有2个时间序列的数据帧。两者都只包含值[0,1]。第一个称为init_signal,第二个称为end_signal。这个想法是在init_signal有一个1时创建一个新的数据帧,它将在end_signal中找到NEXT 1。

下面的示例将init_signal和end_signal合并为一个数据帧。第一列是init_signal,第二列是end_signal。

例如:

2016-06-13  1  0
2016-06-14  0  0
2016-06-15  0  1
2016-06-16  0  0

将成为:

2016-06-13  1  
2016-06-14  1  
2016-06-15  1  
2016-06-16  0  

例如2:

2016-06-13  1  1
2016-06-14  0  0
2016-06-15  0  1
2016-06-16  0  0

将成为:

2016-06-13  1  
2016-06-14  1  
2016-06-15  1  
2016-06-16  0  

在第二个示例中,如果在与init_signal相同的行中也有一个1,它将被忽略。

我一直在使用复杂的循环。有非循环方式吗?

4 个答案:

答案 0 :(得分:3)

我希望这会有所帮助并涵盖所有边界条件。

onChange

输出:

import pandas as pd
import datetime as dt

# Dummy data
df = pd.DataFrame()
df['init_signal'] = [0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0]
df['end_signal']  = [0,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,1,0]
df.index = [dt.date.today()+dt.timedelta(-i) for i in reversed(range(len(df)))]

# Cumsum for calculation
df['init_c'] = df['init_signal'].cumsum()
df['end_c']  = df['end_signal'].cumsum()

# result calculation
func = lambda x: (x==x.min()).shift().fillna(True)
df['result'] = df.groupby('init_c')['end_c'].transform(func)
df['result'] = df['result']&df['init_c'].astype(bool)
df['result'] = df['result'].astype(int)

# dropping temp columns
df.drop(['init_c','end_c'], axis=1, inplace=True)

print(df)

答案 1 :(得分:0)

让我们尝试一下:

df1 = df.assign(end_signal = df['end_signal'].where(df['init_signal'].values != 1, 0))
df1 = df1.set_index('time')
(df1['init_signal'] + df1['end_signal'].shift().bfill()*-1).cumsum()

输出:

         time    0
0  2016-06-13  1.0
1  2016-06-14  1.0
2  2016-06-15  1.0
3  2016-06-16  0.0

答案 2 :(得分:0)

这可以通过三个步骤和0个循环来实现:

  1. 使用init_signalend_signal创建单个列。 (两者的记录默认都仅是启动信号。)
  2. 填写日期 没有活动。
  3. 将结束信号重新添加为活动状态。

注意:我不确定一开始如何处理案件。我假设在init_signal之前总是 一个end_signal。如果不是这样,则需要为此构建一个处理程序,但这将是这些步骤结束时的简单条件。

第1步:单列

在这一步中,我们创建一个只有几天的地方,其中有init_signalend_signal

 import numpy as np
 df['result'] = np.nan
 #Add end dates
 mask = (df['end_signal'] == 1)
 df.loc[mask,'result'] = 0
 #Add init_signals.
 #Note: This will overwrite days that already have an end_signal
 mask = (df['init_signal'] == 1)
 df.loc[mask,'result'] = 1

步骤2:填充列

这将获取na值,并将其替换为最近发生的状态。

 df.fillna(method='ffill',inplace=True)

第3步:将end_signal设置为有效。

在定义中,我们说带有end_signal的日期应为1,因此我们需要将其添加回数据框。

 mask = (df['end_signal'] == 1)
 df.loc[mask,'result'] = 1

答案 3 :(得分:-1)

我认为没有一种非循环的方式可以合并您想要的逻辑(如果有的话,它不比循环简单)。见下文...

df['status'] = 0
for i in df.index:
    if df.xs(i)['init_signal'] == 1:
        df.at[i,'status'] = 1
    elif i != 0 and df.xs(i-1)['status'] == 1 and df.xs(i)['end_signal'] != 1:
        df.at[i,'status'] = 1
    else:
        df.at[i,'status'] = 0

这将创建一个“状态”列,该列将一直为零,直到init_signal设置为“ on”为止,并且在init_signal也不等于1的一天(根据您的示例2)将保持为“ on”状态,直到end_signal = 1为止。当连续给出多个结束/初始化信号时,其他非循环解决方案似乎也会遇到麻烦。