Панды, как посчитать количество записей по идентификатору в выбранном диапазоне дат - PullRequest
0 голосов
/ 26 июня 2018

У меня относительно большой фрейм данных (~ 10 млн строк). Он имеет id и DateTimeIndex. Я должен посчитать количество записей с определенным id для каждой строки за период времени (последняя неделя \ месяц \ год). Я создал свою собственную функцию, используя relativedelta и сохраняя даты в отдельном словаре {id: [dates]}, но она работает очень медленно. Как мне сделать это быстро и правильно?

П.С .: Я слышал о pandas.rolling(), но не могу понять, как правильно его использовать.

P.P.S .: моя функция:

def isinrange(date, listdate, delta):
    date,listdate = datetime.datetime.strptime(date,format),datetime.datetime.strptime(listdate,format)
    return date-delta<=listdate

основной код, содержит множество ненужных операций:

dictionary = dict() #structure {id: [dates]}
for row in df.itertuples():#filling a dictionary
    if row.id in dictionary:
        dictionary[row.id].append(row.DateTimeIndex)
    else:
        dictionary[row.id] = [row.DateTimeIndex,]

week,month,year = relativedelta(days =7),relativedelta(months = 1),relativedelta(years = 1)#relative delta init

for row, i in zip(df.itertuples(),range(df.shape[0])):#iterating over dataframe
    cnt1=cnt2=cnt3=0 #weekly,monthly, yearly - for each row
    for date in dictionary[row.id]:#for each date with an id from row
        index_date=row.DateTimeIndex 
        if date<=index_date: #if date from dictionary is lesser than from a row 
            if isinrange(index_date,date,year):
                cnt1+=1
            if isinrange(index_date,date,month):
                cnt2+=1
            if isinrange(index_date,date,week):
                cnt3+=1
    df.loc[[i,36],'Weekly'] = cnt1 #add values to a data frame
    df.loc[[i,37],'Monthly'] = cnt2
    df.loc[[i,38],'Yearly']=cnt3

Пример:

id  date
1   2015-05-19
1   2015-05-22
2   2018-02-21
2   2018-02-23
2   2018-02-27

Ожидаемый результат:

id  date    last_week
1   2015-05-19  0
1   2015-05-22  1
2   2018-02-21  0
2   2018-02-23  1
2   2018-02-27  2

Ответы [ 2 ]

0 голосов
/ 26 июня 2018
import pandas as pd                                                                               
src = "path/data.csv"                                                        
df = pd.read_csv(src, sep=",")                                                                    
print df                                                                                          
#    id        date                                                                               
# 0   1  2015-05-19                                                                               
# 1   1  2015-05-22                                                                               
# 2   2  2018-02-21                                                                               
# 3   2  2018-02-23                                                                               
# 4   2  2018-02-27                                                                               

# Convert date column to a datetime                                                               
df['date'] = pd.to_datetime(df['date'])                                                           

# Retrieve rows in the date range                                                                 

date_ini = '2015-05-18'                                                                           
date_end = '2016-05-18'                                                                           

filtered_rows = df.loc[(df['date'] > date_ini) & (df['date'] <= date_end)]                        
print filtered_rows                                                                               
#    id       date                                                                                
# 0   1 2015-05-19                                                                                
# 1   1 2015-05-22                                                                                

# Group rows by id                                                                                
grouped_by_id = filtered_rows.groupby(['id']).agg(['count'])                                      
print  grouped_by_id                                                                              
#    count                                                                                        
# id                                                                                              
# 1      2                                                                                        
0 голосов
/ 26 июня 2018
year_range = ["2018"]
month_range = ["06"]
day_range = [str(x) for x in range(18, 25)]
date_range = [year_range, month_range, day_range]

# df = your dataframe
your_result = df[df.date.apply(lambda x: sum([x.split("-")[i] in date_range[i] for i in range(3)]) == 3)].groupby("id").size().reset_index(name="counts")
print(your_result[:5])

Я не уверен, что правильно понял, но это то, что вы ищете?
Взял ~ 15с с 10 миллионами строк "тестового" кадра данных

   id  counts
0   0  454063
1   1  454956
2   2  454746
3   3  455317
4   4  454312
Wall time: 14.5 s

Фрейм данных "test":

   id        date
0   4  2018-06-06
1   2  2018-06-18
2   4  2018-06-06
3   3  2018-06-18
4   5  2018-06-06
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...