считая строки, которые попадают в период с пандами - PullRequest
0 голосов
/ 12 мая 2018

У меня есть фрейм данных, который выглядит таккак это:

Period    Customers
2017-01   3
2017-02   5
2017-03   8
2017-04   9

Я написал цикл for для этого, но он ОЧЕНЬ неэффективен.Должен быть более быстрый способ, который использует функциональность панд, чтобы сделать это.Любая помощь с благодарностью!

Ответы [ 3 ]

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

Вы можете создать месячный период как to_period, в списках все периоды для каждого customer и последнего groupby с nunique :

df['Start_date'] = pd.to_datetime(df['Start_date']).dt.to_period('m')
df['End_date'] = pd.to_datetime(df['End_date']).dt.to_period('m')
#if want exclude last periods per rows subtract 1
#df['End_date'] = pd.to_datetime(df['End_date']).dt.to_period('m') - 1

L = [(a, d) for a,b,c in df.values for d in pd.period_range(b,c, freq='m')]

for all unique customers per period
df = pd.DataFrame(L, columns=['v','d']).groupby('d')['v'].nunique()
print (df.head(10))
d
2015-06    1
2015-07    1
2015-08    1
2015-09    1
2015-10    1
2015-11    1
2015-12    1
2016-01    1
2016-04    1
2016-05    1
Freq: M, dtype: int64

Образец с различными данными для тестового решения:

print (df)
   customer Start_date   End_date
0       100 2016-03-01 2016-06-01
1       100 2016-08-01 2016-10-01
2       102 2016-04-01 2017-01-01
3       103 2016-06-03 2016-01-01
4       103 2016-06-01 2016-05-01

df['Start_date'] = pd.to_datetime(df['Start_date']).dt.to_period('m')
df['End_date'] = pd.to_datetime(df['End_date']).dt.to_period('m')

L = [(a, d) for a,b,c in df.values for d in pd.period_range(b,c, freq='m')]

df = pd.DataFrame(L, columns=['v','d']) 
print (df)
      v       d
0   100 2016-03
1   100 2016-04
2   100 2016-05
3   100 2016-06
4   100 2016-08
5   100 2016-09
6   100 2016-10
7   102 2016-04
8   102 2016-05
9   102 2016-06
10  102 2016-07
11  102 2016-08
12  102 2016-09
13  102 2016-10
14  102 2016-11
15  102 2016-12
16  102 2017-01

df1 = df.groupby('d')['v'].nunique().reset_index()
print (df1)
         d  v
0  2016-03  1
1  2016-04  2
2  2016-05  2
3  2016-06  2
4  2016-07  1
5  2016-08  2
6  2016-09  2
7  2016-10  2
8  2016-11  1
9  2016-12  1
10 2017-01  1
0 голосов
/ 12 мая 2018
df.melt(id_vars='customer', \
        var_name='Period', \
        value_name='Date'). \
   groupby('customer'). \
   apply(lambda x: pd.Series(pd.date_range(x.Date.min(), \
                                           x.Date.max(), \
                                           freq='M'))). \
   reset_index(). \
   drop('level_1', axis=1). \
   set_index(0). \
   resample('M'). \
   nunique()

#             customer
# 0                   
# 2015-06-30         1
# 2015-07-31         1
# 2015-08-31         1
# 2015-09-30         1
# 2015-10-31         1
0 голосов
/ 12 мая 2018

Сначала убедитесь, что даты в порядке:

df.Start_date = pd.to_datetime(df.Start_date)
df.End_date = pd.to_datetime(df.End_date)

Создайте фиктивный столбец и используйте его для объединения во все периоды:

df['dummy'] = 1
merged = pd.merge(
    df,
    pd.DataFrame({'Period': pd.date_range(df.Start_date.min(), df.End_date.max(), freq='M'), 'dummy': 1}),
    how='outer')

Сохраните все строки, где находится периодпадает между начальной и конечной датами:

merged = merged[(merged.Start_date <= merged.Period) & (merged.End_date >= merged.Period)]

Теперь рассчитайте клиентов за период:

>>> merged.customer.groupby(merged.Period).nunique()
Period
2015-06-30    1
2015-07-31    1
2015-08-31    1
2015-09-30    1
2015-10-31    1
2015-11-30    1
2015-12-31    1
2016-04-30    1
2016-05-31    1
2016-06-30    3
2016-07-31    3
2016-08-31    3
2016-09-30    3
2016-10-31    3
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...