多个 .shift() 操作相互覆盖



是否可以只对数据帧的某个子集应用移位?目前,下面的内容将覆盖 df['End'],因为我直接将其分配给 df['End'],但我不太清楚如何仅将其应用于较小的选择。

本质上,我有一个日期列的数据,结束日期是下一行的开始日期,但前提是它是某种类型。最后一行应该使用相同的开始/结束。

对如何做到这一点的任何其他想法也持开放态度!

示例数据

Start   Field
2018-05-22T19:03:30+0000    Product
2018-05-22T19:09:30+0000    Size
2018-05-22T19:09:30+0000    Category
2018-05-22T19:25:39+0000    Product
2018-05-22T19:42:41+0000    Size
2018-05-22T20:57:30+0000    Category
# First Shift
df['End'] = df.loc[df['Field'].isin(['Product', 'Category'])]['Start'].shift(periods=-1)
# Update last row  
shift_rows = df.loc[df['Field'].isin(['Product', 'Category'])]
df.iloc[-1, shift_rows.columns.get_loc('End')] = shift_rows.iloc[-1, df.columns.get_loc('Start')] 
# Second shift        
df['End'] = df.loc[df['Field'].isin(['Size'])['Start'].shift(periods=-1)
# Update last row
shift_rows = df.loc[df['Field'].isin(['Size'])]
df.iloc[-1, shift_rows.columns.get_loc('End')] = shift_rows.iloc[-1, df.columns.get_loc('Start')]

预期输出

Start   Field   End
2018-05-22T19:03:30+0000    Product 2018-05-22T19:09:30+0000
2018-05-22T19:09:30+0000    Size    2018-05-22T19:42:41+0000
2018-05-22T19:09:30+0000    Category    2018-05-22T19:25:39+0000
2018-05-22T19:25:39+0000    Product 2018-05-22T20:57:30+0000
2018-05-22T19:42:41+0000    Size    2018-05-22T19:42:41+0000
2018-05-22T20:57:30+0000    Category    2018-05-22T20:57:30+0000

一个想法可能是创建一个列Field_group为不同的字段组提供一个数字。使用您的样品:

df['Field_group'] = df['Field'].apply(lambda field: 1 if field in ['Product', 'Category'] else 2)

如果您有 2 组以上的字段,您可以执行以下操作:

def associate_group_number (field):
if field in ['Product', 'Category']: return 1
if field in ['Size','blabla']: return 2
if field in ['blo','bli','blu']: return 3
df['Field_group'] = df['Field'].apply(associate_group_number)

现在您有了组号,您可以使用groupbyshift来创建"结束"列,例如:

df['End'] = df.groupby('Field_group')['Start'].shift(-1)

而且因为你想用Start中这一行对应的时间填充每个组End的最后一行(如果我理解得很好(,你可以使用fillna

df['End'] = df['End'].fillna(df['Start'])

您甚至可以在shift(-1)前一行代码之后添加.fillna(df['Start'])以在一行中完成,它可以工作(这里是要解释的(

最后,您可以删除使用以下命令创建的列:

df = df.drop('Field_group',1)

最新更新