我有一个非常大的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循环不是一个可行的解决方案,因为运行时间在数千小时内。
*更新:到目前为止,感谢您的回答,我添加了一些信息,以使其更清晰一些。
答案 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