Последнее соответствующее значение в DataFrame (Python) - PullRequest
0 голосов
/ 16 мая 2018

У меня есть очень большой df, над которым я пытаюсь работать, но единственный метод, который я нашел до сих пор, - это использование для циклов, которое занимает слишком много времени. Я знаю, что это возможно, но просто не знаю, как так надеяться, что кто-то может помочь. Допустим, у меня есть следующий 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

Мне нужно найти способ взять Боба 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

Проблема в том, что New_Value не может быть рассчитано до тех пор, пока не будет известно Old_Value для каждого идентификатора, а дата должна быть в порядке возрастания в течение всего df. Таким образом, вычисления, которые возвращают 9.0 как New_Value в третьей строке, зависят от обновленного Old_Value (которое равно 12.0 от New_Value в первой строке).

Некоторые идентификаторы появляются в df чаще, чем другие, и последовательности их появления не задано. Фрейм данных имеет более 100 000 уникальных идентификаторов, и использование циклов for не является жизнеспособным решением, поскольку время выполнения составляет тысячи часов.

* ОБНОВЛЕНИЕ: Спасибо за ваши ответы, я добавил еще немного информации, чтобы сделать ее немного понятнее.

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

Это больше похоже на приведенный вами пример:

сначала создайте фрейм данных (со столбцом даты в качестве индекса):

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)

Затем определите идентификатор пользователя, для которого вы хотите обновить значение:

# 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
0 голосов
/ 17 мая 2018

Я не уверен, полностью ли я понимаю вашу проблему, но, может быть, это решение, которое должно работать на фрейме данных, отсортированном по времени, может помочь:

сначала я имитировал вашу базу данных (которая займет большую частьвремя):

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)]))

Затем вызвать эту функцию с идентификатором пользователяи новое значение для этого пользователя

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

Обратите внимание, что это будет работать, только если пользователь уже находится в базе данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...