【问题标题】:Reduce dataframe using a running flag使用运行标志减少数据帧
【发布时间】:2020-07-10 04:01:30
【问题描述】:

我有一个带有xy 某些点坐标的数据框。每个点(坐标对)也都标有 True/False 标志:

xs = [1,3,7,5,4,6,2,8,9,0]
ys = [0,7,4,5,2,6,9,1,3,8]
flags = [True,False,False,False,True,True,False,True,True,True]
df = pd.DataFrame({'x':xs, 'y':ys,'flag':flags})


    x   y   flag
0   1   0   True
1   3   7   False
2   7   4   False
3   5   5   False
4   4   2   True
5   6   6   True
6   2   9   False
7   8   1   True
8   9   3   True
9   0   8   True

什么 reduce 函数可用于计算 2 个总距离:

1) 从 False 点之后的 True 点或第一个为 True 的点开始的路线的总距离,包括所有 True 点并以 False 点或所有点​​的结尾结束

2) 从真点之后的假点或第一个假点开始的路线的总距离,包括所有假点并以真点或所有点​​的结尾结束

在本例中,需要将以下部分相加得到总距离:

1) Route built from  True points:
(1,0) - (3,7)
---
(4,2) - (6,6)
(6,6) - (2,9)
---
(8,1) - (9,3)
(9,3) - (0,8)

2) Route built from False points:
(3,7) - (7,4)
(7,4) - (5,5)
(5,5) - (4,2)
---
(2,9) - (8,1)

因此,例如,以下几点:

points = [((1,0),(3,7)), ((4,2),(6,6)), ((6,6),(2,9)), 
           ((8,1),(9,3)), ((9,3),(0,8))]

# Compute distance between two points:
def distance(x1,y1,x2,y2):
    return math.sqrt((x2-x1)**2 + (y2-y1)**2)

总距离:

total_distance = 0
for t in points:
   total_distance += distance(t[0][0],t[0][1], t[1][0],t[1][1])  

print(total_distance)

29.283943962766887

如何使用reduce函数计算距离,而不是使用pandas.DataFrame.iterrows

【问题讨论】:

  • " 在 False 点之后以 True 点开始的路线或以 True 的第一个点开始,"

标签: python pandas reduce


【解决方案1】:

首先您可以使用shift 以矢量化方式计算距离:

df['dist'] = np.sqrt((df['x']-df['x'].shift(-1))**2 + (df['y']-df['y'].shift(-1))**2)

然后您可以在列标志上使用cumsumdiff 创建满足True 条件的掩码:

mask_true = df['flag'].cumsum().diff().fillna(df['flag']).gt(0)
# now use loc to select these rows and the dist column plus sum
print (df.loc[mask_true,'dist'].sum())
# 29.283943962766887

对于 False 条件,那么我猜它是互补的,所以你得到:

print (df.loc[~mask_true,'dist'].sum())
# 20.39834563766817

编辑:有时,最简单的解决方案不会首先出现,但实际上,mask_truedf['flag'],所以一旦你创建了列 dist,你可以直接做:

print (df.loc[df['flag'],'dist'].sum())
# 29.283943962766887
print (df.loc[~df['flag'],'dist'].sum())
# 20.39834563766817

【讨论】:

  • 这里的答案很好!
  • @ansev 谢谢,但它比这更简单;)
  • 您的答案的更简单版本有任何更新吗?谢谢!
  • @dokondr 所以cumsum 意味着每次你在列中有一个True,值就会增加1,所以首先True你得到1,然后第二个True你得到2,等等,如果你在Trues 之间有False,那么它们的值与前一行相同。通过执行diff,如果连续两行在该行中具有相同的值含义False,则它最终为0,而​​diff 给出值增加的值,即True 的含义。 fillna 是使用diff 填充丢失的第一行,最后gt(0) 将给出True 如果值>0 和False 否则。
  • @dokondr 所以你实际上会得到与df['flag'] 相同的列,如果你这样做(df['flag']==df['flag'].cumsum().diff().fillna(df['flag']).gt(0)).all() 你会得到Truemask_true 的创建是不必要的,因为它正是作为df['flag']
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-16
  • 2021-06-25
  • 1970-01-01
  • 2019-08-13
  • 1970-01-01
  • 1970-01-01
  • 2021-03-13
相关资源
最近更新 更多