我有两个具有两种不同形状的数据框:
df_rts_1 #Shape: (38658637, 7)
df_crsh_rts #Shape: (9456, 6)
我正在尝试使用
np.where
根据特定条件将列值 (df_rts_1['crash'])
更新为等于 1
,如下所示:
df_rts_1['tmc_code']= df_crsh_rts['tmc']
df_rts_1['measurement_tstamp'] is between df_crsh_rts['Start_time'] and df_crsh_rts['Closed_time']
我的代码:
df_rts_1['crash'] = np.where((df_rts_1['tmc_code'].values == df_crsh_rts['tmc'].values) & ((df_rts_1['measurement_tstamp'].values > df_crsh_rts['Start_time'].values) & (df_rts_1['measurement_tstamp'].values > df_crsh_rts['Closed_time'].values)), 1, df_rts_1['crash'])
我收到标题中的错误。我对 Python/数据科学非常陌生。
假设您的两个 DataFrame 包含:
df_rts_1:
tmc_code measurement_tstamp crash
0 1 2020-01-03 10:05:00 0
1 1 2020-01-03 11:00:00 0
2 1 2020-01-03 12:10:00 0
3 2 2020-01-03 10:10:00 0
4 3 2020-01-03 10:05:00 0
df_crsh_rts:
tmc Start_time Closed_time
0 1 2020-01-03 10:00:00 2020-01-03 11:00:00
1 2 2020-01-03 14:00:00 2020-01-03 15:00:00
2 4 2020-01-03 16:00:00 2020-01-03 18:00:00
为了方便评估“之间”条件,让我们创建以下内容 间隔索引:
interv = pd.IntervalIndex.from_arrays(df_crsh_rts.Start_time,
df_crsh_rts.Closed_time, closed='both')
现在,假设我们有来自 df_rts_1 的当前 row,让我们构造 您的情况:
interv.contains(row.measurement_tstamp)
,df_crsh_rts.tmc.eq(row.tmc_code)
。
df_rts_1 中的第一行保存为 row 变量:
row = df_rts_1.iloc[0]
并执行这两个条件。第一个条件生成一个
bool 类型的 Numpy 数组:
array([ True, False, False])
第二个 - Series(也是 bool 类型):
0 True
1 False
2 False
Name: tmc, dtype: bool
因此要构造最终(单个)bool值 - 是否是这一行 应该更新它的crash栏,条件是:
(interv.contains(row.measurement_tstamp) & df_crsh_rts.tmc.eq(row.tmc_code)).any()
即上述两个条件的逻辑 AND 和 any() - 是否 any 这个合取的元素是True。
与您的代码相比,最后的更改是:
df_rts_1.loc[[ (interv.contains(row.measurement_tstamp) &
df_crsh_rts.tmc.eq(row.tmc_code)).any()
for row in df_rts_1.itertuples()], 'crash'] = 1
对于我的样本数据,结果是:
tmc_code measurement_tstamp crash
0 1 2020-01-03 10:05:00 1
1 1 2020-01-03 11:00:00 1
2 1 2020-01-03 12:10:00 0
3 2 2020-01-03 10:10:00 0
4 3 2020-01-03 10:05:00 0
编辑评论中的以下问题问题1。我们是否使用这两个条件的索引来访问和更新 df_rts_1 数据框?
实际上不是。请注意:
[ (interv.contains(row.measurement_tstamp) &
df_crsh_rts.tmc.eq(row.tmc_code)).any() for row in df_rts_1.itertuples() ]
产生 bool 的 list,其中甚至不包含原始索引。 然后在 .loc[...] 中使用,所以这是 boolean 的情况 索引。此列表中连续的 True / False 元素涉及 来自 df_rts_1 的连续行并说明特定行是否是 待选。
Q2和Q3。 any()在这里做什么? any() 对我们有什么帮助 实现。
查看第一行的示例:
同一行必须满足两个这些条件 来自 df_crsh_rts,因此 & 加入它们。
但请注意:
condition_1 & condition_2 产生 bool 类型的 Series - 是否 连续行满足两个部分条件:
0 True
1 False
2 False
Name: tmc, dtype: bool
Series 的 bool。我们需要一个 single bool, 说明上述结果是否至少包含一个True值。
bool Series 到 single bool) 由 any() 执行。
编辑2
def newCrash(grp):
# Intervals for the current tmc_code
wrk = intrv[intrv.index == grp.iloc[0,0]]
if wrk.empty:
return grp.crash # Nothing found - no change
wrkInd = pd.IntervalIndex(wrk)
return grp.crash.mask([ wrkInd.contains(ts).any()
for ts in grp.measurement_tstamp ], 1)
然后创建辅助系列:
intrv = pd.Series(pd.IntervalIndex.from_arrays(df_crsh_rts.Start_time,
df_crsh_rts.Closed_time, closed='both'), index=df_crsh_rts.tmc)
最后运行crash列的更新:
df_rts_1.crash = df_rts_1.groupby('tmc_code', sort=False).\
apply(newCrash).reset_index(level=0, drop=True)
对于您的(非常小的)样本数据,此解决方案运行速度较慢。但是当我将
df_rts_1 的大小增加到 40 行后,这个解决方案 工作速度更快一点。
如果进一步增大df_rts_1的大小,速度上的差异 应该更大(有利于第二种解决方案)。
在样本上检查两种解决方案(原始解决方案和此解决方案)。 100,000 行 来自df_rts_1 并写出这两个解决方案的执行时间。