DataFrame(Python)中的最后一个匹配值

时间:2018-05-16 20:34:56

标签: python pandas dataframe

我有一个非常大的df,我正在努力,但到目前为止我找到的唯一方法是使用for循环,这需要太长时间。我知道这是可能的,但只是不确定如何希望有人可以提供帮助。假设我有以下df:

Date       ID   Name Old_Value New_Value
2018-01-01 101  Bob  10.0      12.0
2018-01-01 102  Tim  9.0       14.0

..... 15 mil rows

我需要找到一种方法来获取Bob的New_Value并将其用作下一个Old_Value,因此df看起来如下:

Date       ID   Name Old_Value New_Value
2018-01-01 101  Bob  10.0      12.0
2018-01-01 102  Tim  9.0       14.0
2018-02-01 101  Bob  12.0      9.0
2018-02-14 101  Bob  9.0       7.0
2018-02-14 102  Tim  14.0      19.0
2018-02-21 101  Bob  7.00      6.0
2018-02-21 102  Tim  19.0      16.0
2018-02-23 102  Tim  16.0      14.0

问题是,在知道每个ID的Old_Value并且日期必须按整个df的升序排列之前,无法计算New_Value。因此,在第三行中返回9.0作为New_Value的计算取决于更新的Old_Value(第一行中New_Value为12.0)。

某些ID在df中比其他ID更频繁出现,并且在它们出现时没有设置序列。数据帧具有超过100,000个唯一ID,并且使用for循环不是一个可行的解决方案,因为运行时间在数千小时内。

*更新:到目前为止,感谢您的回答,我添加了一些信息,以使其更清晰一些。

2 个答案:

答案 0 :(得分:1)

我不确定我是否完全理解您的问题,但是这个应该对按时排序的数据帧起作用的解决方案可能有所帮助:

首先我模仿你的数据库(大部分时间都是这样):

import pandas as pd
import numpy as np
import time

df_len = 15*10**6
user_size = 100000

now = int(time.time())
df = pd.DataFrame(index = range(df_len))
df['time_delta'] = np.random.choice(60, df_len)
df['time_delta_sum'] = df.time_delta.cumsum()
df['time_sec']= now - df.time_delta_sum
df['user_id'] = np.random.choice(user_size, df_len)
df['New_Value'] = np.random.choice(80, df_len)
df.sort_values(['user_id', 'time_sec'], inplace = True)

df['Old_Value'] = None
df['Old_Value'].iloc[1:] = df.New_Value.iloc[:-1].values
df['Old_Value'].iloc[0] = np.random.choice(80)

df.sort_values(['time_sec'], inplace = True)

df['date_time'] = df['time_sec'].apply(time.ctime)
df = df[['date_time', 'user_id', 'Old_Value', 'New_Value']].reset_index(drop = True)

这个尾巴看起来像:

df.tail() =
                         date_time  user_id Old_Value  New_Value
14999995  Thu May 17 01:14:14 2018    33790        42         23
14999996  Thu May 17 01:14:36 2018    44252        58         75
14999997  Thu May 17 01:15:18 2018    86755         7         45
14999998  Thu May 17 01:15:44 2018    31874        24         72
14999999  Thu May 17 01:16:20 2018    94365        27         29

应该进行更新的功能

def Append_To_Df(user_id, new_value):
    global df
    old_value = df.loc[df.user_id == user_id, 'New_Value'].iloc[-1]
    df = df.append(pd.DataFrame([[time.ctime(),user_id,old_value,new_value]], columns = df.columns, index = [len(df)]))

然后使用此用户的用户ID和新值

调用此函数
user_id = 3357
new_value = 35

Append_To_Df(user_id, new_value)

数据帧的尾部看起来像:

df.tail() =
                         date_time  user_id Old_Value  New_Value
14999996  Thu May 17 01:14:36 2018    44252        58         75
14999997  Thu May 17 01:15:18 2018    86755         7         45
14999998  Thu May 17 01:15:44 2018    31874        24         72
14999999  Thu May 17 01:16:20 2018    94365        27         29
15000000  Thu May 17 01:18:34 2018     3357        37         35

请注意,这仅在用户已在数据库中时才有效。

答案 1 :(得分:1)

这个更符合您提供的示例:

首先创建数据框(将日期列作为索引):

import pandas as pd

column_names = ['Date', 'ID', 'Name', 'Old_Value', 'New_Value']
values = [['2018-01-01', '101', 'Bob', '10.0', '12.0'], ['2018-01-01', 102, 'Tim', 9.0, 14.0],['2018-02-01', 101, 'Bob', 12.0, 9.0], ['2018-02-14', 101, 'Bob', 9.0, 7.0], ['2018-02-14', 102, 'Tim', 14.0, 19.0], ['2018-02-21', 101, 'Bob', 7.00, 6.0], ['2018-02-21', 102, 'Tim', 19.0, 16.0], ['2018-02-23', 102, 'Tim', 16.0, 14.0]]

df = pd.DataFrame(values, columns = column_names).set_index('Date', drop = True)

然后定义要更新其值的用户ID:

# the user id of which you want to change the value, 101 of Bob in this case
user_id = 101

# get the last line of the user_id, and take its 'new' value as old value and the name
last_line = df.loc[df.ID == user_id, ['New_Value', 'Name']].iloc[-1]
name = last_line.Name
old_value = last_line.New_Value

# apply a function on the 'new' old value to calculate the 'new' new value
new_value = old_value - 4 #(or any other function)

# set the date for the new value
new_date = '2018-02-25'

#update the dataframe
df = df.append(pd.DataFrame([[user_id, name, old_value, new_value]], index = [new_date], columns = df.columns))
df.index.name = 'Date'

在这种情况下导致:

df = 
             ID Name Old_Value New_Value
Date                                    
2018-01-01  101  Bob      10.0      12.0
2018-01-01  102  Tim         9        14
2018-02-01  101  Bob        12         9
2018-02-14  101  Bob         9         7
2018-02-14  102  Tim        14        19
2018-02-21  101  Bob         7         6
2018-02-21  102  Tim        19        16
2018-02-23  102  Tim        16        14
2018-02-25  101  Bob         6         2