2016-12-01 1 views
1

У меня есть Pandasdataframe запрос из базы данных, содержащей три столбца. Дата начала, дата окончания и лицо. Данные могут не иметь большого смысла, но это просто упрощенный пример.Скрытый диапазон дат для массива Numpy в составе Groupby в Pandas

startdate  enddate person 
0 2016-01-01 2016-01-02  A 
1 2016-01-03 2016-01-03  A 
2 2016-01-01 2016-01-01  B 
3 2016-01-02 2016-01-02  B 

За указанный диапазон дат, я хотел бы знать, какие дни покрыты записи в моем dataframe для каждого человека. Я думал, что создать numpyarray с длиной, равной количеству дней в диапазоне. Если этот конкретный день выпадает в диапазоне, значение этого индекса в массиве устанавливается равным 1, в противном случае 0. Затем я сглаживаю функцию groupby и lambda.

Итак, учитывая выше dataframe и диапазон дат 2016-01-01 до 2016-01-03, конечный результат будет:

 date_binary 
person    
A  [1, 1, 1] 
B  [1, 1, 0] 

Я был в состоянии выработать некоторые код (groupby часть), но я не уверен, как перейти от диапазона дат к массиву. Итак, в приведенном ниже примере я просто жестко закодировал преобразованный фрейм данных. Полагаю, я мог бы задать более простой вопрос, связанный с этой проблемой, но я знаю, что с Pandas часто бывает очень компактный способ делать что-то, поэтому я отправляю даже рабочую часть.

import pandas as pd 
from datetime import datetime 
import numpy as np 
# initial dataset 
df = pd.DataFrame(data=[['2016-01-01', '2016-01-02', 'A'], 
         ['2016-01-03', '2016-01-03', 'A'], 
         ['2016-01-01', '2016-01-01', 'B'], 
         ['2016-01-02', '2016-01-02', 'B']], 
        columns=['startdate', 'enddate', 'person']) 

# convert columns to dates 
df['startdate']= pd.to_datetime(df['startdate'], format='%Y-%m-%d') 
df['enddate']= pd.to_datetime(df['enddate'], format='%Y-%m-%d') 

# define period for which the matrix should be created 
start_date = datetime(month=01, day=1, year=2016) 
end_date = datetime(month=1, day=10, year=2016) 


###################### 
# Unsure how to do this 
##################### 

# what the dataframe should look like 
df = pd.DataFrame(data=[[[1, 1, 0], 'A'], 
         [[0, 0, 1], 'A'], 
         [[1, 0, 0], 'B'], 
         [[0, 1, 0], 'B']], 
        columns=['date_binary', 'person']) 

# flatten by person 
df = df.groupby('person').aggregate(lambda x: tuple(x)) 

# take the max value 
df.date_binary = df.date_binary.apply(lambda x: np.array([max(i) for i in zip(*x)])) 

print df 

ответ

1

Я думаю, что вы можете apply пользовательской функции с reindex по вашим date_range которые возвращают new_index и indexer. Последнее необходимо заменить в indexer значений -1 к 0 и других ценностей в 1 по numpy.where:

# define period for which the matrix should be created 
start_date = datetime(month=1, day=1, year=2016) 
end_date = datetime(month=1, day=3, year=2016) 

dr = pd.date_range(start_date, end_date) 

def f(x): 
    arr = pd.date_range(x.startdate, x.enddate).reindex(dr)[1] 
    return pd.Series([np.where(arr == -1, 0, 1)]) 

df['date_binary'] = df.apply(f, axis=1) 
df = df[['date_binary', 'person']] 
print (df) 
    date_binary person 
0 [1, 1, 0]  A 
1 [0, 0, 1]  A 
2 [1, 0, 0]  B 
3 [0, 1, 0]  B 
+0

спасибо это хорошее решение. Можете ли вы объяснить, что делает 'np.where (arr == -1, 0, 1)'? – user2242044

+0

numpy где is simple, если условие True, то 0 else 1. И здесь indexer возвращает '-1', если значение отсутствует - вам нужно' 0', а для других значений нужно '1' – jezrael

+0

, когда я печатаю' arr' первую строку массив равен '[0 1 -1]'. Поскольку это соответствует '['2016-01-01', '2016-01-02', 'A']', не должно быть '[1, 1, -1]', поскольку у нас есть два совпадения, тогда день за пределами диапазона? Может быть, я не понимаю, что делает этот код. – user2242044

Смежные вопросы