【问题标题】:Pandas - Compute a value for each row, using information from previous rows?Pandas - 使用前几行的信息计算每一行的值?
【发布时间】:2021-08-18 21:07:36
【问题描述】:

所以我有一个 Pandas 数据框 df,它看起来像这样(带有其他列):

timestamp player event location_x location_y location_z dist
2021-07-14 22:54:28.001000 Bob 'PlayerMoveEvent' 10 10 10 ?
2021-07-14 22:54:28.001600 Alice 'PlayerJoinEvent' NaN NaN NaN ?
2021-07-14 22:54:28.001600 Alice 'PlayerMoveEvent' 20 20 20 ?
2021-07-14 22:54:28.001670 Bob 'PlayerMoveEvent' 11 10 10 ?
2021-07-14 22:54:28.001740 Eve 'PlayerMoveEvent' 5 15 9 ?
2021-07-14 22:54:28.001670 Eve 'PlayerQuitEvent' NaN NaN NaN ?
2021-07-14 22:54:28.001820 Alice 'PlayerMoveEvent' 18 20 19 ?

每次玩家移动时,都会触发一个事件并记录他们的位置。

现在我想计算两个给定玩家之间的距离 √((x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2),在本例中为 Alice 和 Bob,以及将其作为新列添加到数据框的末尾。

对于另一个玩家的行或非“PlayerMoveEvent”,它只会重复上一行的相同值,因为它将使用较旧的位置(我尝试通过将位置存储为单独的列表,如下所示)。

def player_distance(df, player_0, player_1):
    player_0_location = [None, None, None]
    player_1_location = [None, None, None]

我已经尝试了很多东西(在我使用 .apply 和 lambda 函数“dist”之前),但现在我试图在一个函数中完成所有这些。我知道 iterrows() 没有做我认为它在下面做的事情,因为下面没有一个作为 IF 语句起作用,即使它们在函数之外手动测试时起作用:

if((df.loc[i]['player'][0]) == player_0) & (df.loc[i]['event'][0]) == 'PlayerMoveEvent')):

if((df.loc[i]['player'].item()) == player_0) & (df.loc[i]['event'].item()) == 'PlayerMoveEvent')):

当类型转换为字符串时,这两个都不起作用

if((df.loc[i]['player'].item() == player_0) & (df.loc[i]['event'].item() == 'PlayerMoveEvent')):

if((j['player'] == player_0) and (j['event'] == 'PlayerMoveEvent')):

if((j['player'].eq(player_0)) & (j['event'].eq('PlayerMoveEvent'))):

def player_distance(df, player_0, player_1):
    player_0_location = [None, None, None]
    player_1_location = [None, None, None]
    for i, j in df.iterrows():
        # PROBLEM LINE
        if((df.loc[i]['player'][0]) == player_0) & (df.loc[i]['event'][0]) == 'PlayerMoveEvent')):
        # this line always gives a "ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all()." error
            player_0_location[0] = df.loc[i, 'location_x'].values[0]
            player_0_location[1] = df.loc[i, 'location_y'].values[0]
            player_0_location[2] = df.loc[i, 'location_z'].values[0]
        # PROBLEM LINE
        if((df.loc[i]['player'][0]) == player_1) & (df.loc[i]['event'][0]) == 'PlayerMoveEvent')):
            player_1_location[0] = df.loc[i, 'location_x'].values[0]
            player_1_location[1] = df.loc[i, 'location_y'].values[0]
            player_1_location[2] = df.loc[i, 'location_z'].values[0]
        if ((None not in player_0_location) and (None not in player_1_location)):
            df.loc[i]['dist'] = (((player_0_location[0] - player_1_location[0]) ** 2) + ((player_0_location[1] - player_1_location[1]) ** 2) + ((player_0_location[2] - player_1_location[2]) ** 2)) ** 0.5

【问题讨论】:

    标签: python python-3.x pandas dataframe


    【解决方案1】:

    您当前的尝试感觉非常 imperative,但我发现将 Pandas 更像是一种 declarative 语言通常会有所帮助。

    以下是我处理问题陈述的方式(但请注意,我尚未测试此代码):

    # filter down to move events for just these two players
    df_important_events = df.loc[(df['player'].isin([player_0, player_1])) & (df['event'] == 'PlayerMoveEvent')]
    
    # make sure events are timestamp-ordered for the next step
    df_important_events = df_important_events.sort_values(['timestamp'])
    
    # filter down to the latest move event per player
    df_latest_move_events = df_important_events.groupby('player').last().reset_index(drop=True)
    
    if len(df_latest_move_events) != 2:
        # handle the case where the user passed in an invalid player, or one of the players has not moved yet
    
    # filter down to just location columns
    df_locations = df_latest_move_events[['location_x', 'location_y', 'location_z']]
    
    # convert to numpy array of (x, y, z) tuples
    locations_array = df_locations.to_records()
    
    # return euclidean distance between the two locations
    return numpy.linalg.norm(locations_array[1] - locations_array[0])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-26
      • 2020-10-30
      • 2020-01-03
      • 2019-10-18
      • 2014-01-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多