Mam zbiór danych z 3 kolumnami. ID klienta, numer zamówienia i czas. W tym zestawie danych widać, że niektórzy klienci złożyli więcej niż jedno zamówienie w różnym czasie. Na przykład klient o ID4 złożył zamówienie 4 o 14:14, a następnie 5 o 18:17. To, co muszę zrobić, to określić czas między pierwszym a ostatnim zamówieniem.

    CustomerID  Order#  Time
0   1   1   2021-06-16 19:11:21
1   2   2   2021-06-17 19:24:19
2   3   3   2021-06-16 19:22:42
3   4   4   2021-06-14 14:16:50
4   4   5   2021-06-14 18:17:48
5   5   6   2021-06-16 21:11:06
6   6   7   2021-06-15 17:02:19
7   7   8   2021-06-13 21:01:36
8   8   9   2021-06-16 18:40:14
9   8   10  2021-06-14 14:46:59
10  8   11  2021-06-14 14:46:59
11  9   12  2021-06-17 09:10:15
12  10  13  2021-06-15 02:49:5

W excelu posortowałbym identyfikator klienta od najniższego do najwyższego, a następnie utworzył kolumnę z uruchomioną listą wystąpień identyfikatora, a następnie obliczyłbym różnicę w czasie pierwszego i ostatniego wystąpienia tego samego identyfikatora.

W Pythonie próbowałem tego:

import pandas as pd
orders = pd.read_csv("data/Orders.csv")
occur = orders.groupby(['CustomerID']).size()

Ale problem polega na tym, że grupuje identyfikator klienta i stracę wymiar czasowy. Docelowo muszę utworzyć dodatkową kolumnę, w której obliczę czas między pierwszym a ostatnim wystąpieniem dla tego samego CustomerID.

Wynik będzie wyglądał tak: tu wpisz opis obrazu

Czy jest jakiś sposób, aby zrobić to w Pythonie?

3
Slavisha84 20 czerwiec 2021, 04:48

4 odpowiedzi

Najlepsza odpowiedź

Wypróbuj z np.ptp

df['new'] = df.groupby('CustomerID')['Time'].transform(np.ptp).\
                mask(lambda x : x.eq('00:00:00') | x.duplicated(),'')
df
    CustomerID  Order#                Time              new
0            1       1 2021-06-16 19:11:21                 
1            2       2 2021-06-17 19:24:19                 
2            3       3 2021-06-16 19:22:42                 
3            4       4 2021-06-14 14:16:50  0 days 04:00:58
4            4       5 2021-06-14 18:17:48                 
5            5       6 2021-06-16 21:11:06                 
6            6       7 2021-06-15 17:02:19                 
7            7       8 2021-06-13 21:01:36                 
8            8       9 2021-06-16 18:40:14  2 days 03:53:15
9            8      10 2021-06-14 14:46:59                 
10           8      11 2021-06-14 14:46:59                 
11           9      12 2021-06-17 09:10:15                 
12          10      13 2021-06-15 02:49:05 
1
BENY 20 czerwiec 2021, 02:36

Możesz użyć groupby w kolumnie CustomerID, jak próbowałeś, a następnie obliczyć różnicę między minimalną i maksymalną wartością kolumny Time dla każdego unikatowego CustomerID i scalić ją z oryginalną ramką DataFrame.

## read in the data
df = pd.read_clipboard()
df.reset_index(inplace=True)
df['CustomerID'] = df['level_1']
df = df.drop(columns=['level_0','level_1'])
df['Time'] = pd.to_datetime(df['Order#'] + ' ' + df['Time'])
df['Order#'] = df.index.values + 1

time_diffs = df.groupby('CustomerID').apply(lambda x: x.Time.max() - x.Time.min()).reset_index().rename(columns={0:'time_diffs'})

df = df.merge(time_diffs, on='CustomerID')

Wynik df:

    CustomerID  Order#                Time      time_diffs
0            1       1 2021-06-16 19:11:21 0 days 00:00:00
1            2       2 2021-06-17 19:24:19 0 days 00:00:00
2            3       3 2021-06-16 19:22:42 0 days 00:00:00
3            4       4 2021-06-14 14:16:50 0 days 04:00:58
4            4       5 2021-06-14 18:17:48 0 days 04:00:58
5            5       6 2021-06-16 21:11:06 0 days 00:00:00
6            6       7 2021-06-15 17:02:19 0 days 00:00:00
7            7       8 2021-06-13 21:01:36 0 days 00:00:00
8            8       9 2021-06-16 18:40:14 2 days 03:53:15
9            8      10 2021-06-14 14:46:59 2 days 03:53:15
10           8      11 2021-06-14 14:46:59 2 days 03:53:15
11           9      12 2021-06-17 09:10:15 0 days 00:00:00
12          10      13 2021-06-15 02:49:05 0 days 00:00:00
1
Derek O 20 czerwiec 2021, 02:24

Groupby CustomerID następnie oblicz aggregation dla wartości minimalnych i maksymalnych kolumny Time, a następnie po prostu weź różnicę i na koniec połącz z powrotem do oryginalnej ramki danych.

df['Time'] = pd.to_datetime(df['Time'])
minMax = df.groupby('CustomerID').agg(minTime=('Time', 'min'), maxTime=('Time', 'max'))
minMax['Diff'] = minMax['maxTime'] - minMax['minTime']
df = df.merge(minMax[['Diff']], on='CustomerID')

WYJŚCIE:

    CustomerID  Order#                Time            Diff
0            1       1 2021-06-16 19:11:21 0 days 00:00:00
1            2       2 2021-06-17 19:24:19 0 days 00:00:00
2            3       3 2021-06-16 19:22:42 0 days 00:00:00
3            4       4 2021-06-14 14:16:50 0 days 04:00:58
4            4       5 2021-06-14 18:17:48 0 days 04:00:58
5            5       6 2021-06-16 21:11:06 0 days 00:00:00
6            6       7 2021-06-15 17:02:19 0 days 00:00:00
7            7       8 2021-06-13 21:01:36 0 days 00:00:00
8            8       9 2021-06-16 18:40:14 2 days 03:53:15
9            8      10 2021-06-14 14:46:59 2 days 03:53:15
10           8      11 2021-06-14 14:46:59 2 days 03:53:15
11           9      12 2021-06-17 09:10:15 0 days 00:00:00
12          10      13 2021-06-15 02:49:05 0 days 00:00:00
2
Don'tAccept 20 czerwiec 2021, 02:19

Inna opcja z groupby max - groupby min:

df['Time'] = pd.to_datetime(df['Time'])

g = df.groupby('CustomerID')['Time']
df['duration'] = g.max() - g.min()

Następnie za pomocą Series.where< /a> aby wyczyścić wartości

df['duration'] = df['duration'].where(
    df['duration'] > pd.Timedelta(seconds=0),
    pd.NaT
)
    CustomerID  Order#                Time        duration
0            1       1 2021-06-16 19:11:21             NaT
1            2       2 2021-06-17 19:24:19             NaT
2            3       3 2021-06-16 19:22:42             NaT
3            4       4 2021-06-14 14:16:50             NaT
4            4       5 2021-06-14 18:17:48 0 days 04:00:58
5            5       6 2021-06-16 21:11:06             NaT
6            6       7 2021-06-15 17:02:19             NaT
7            7       8 2021-06-13 21:01:36             NaT
8            8       9 2021-06-16 18:40:14 2 days 03:53:15
9            8      10 2021-06-14 14:46:59             NaT
10           8      11 2021-06-14 14:46:59             NaT
11           9      12 2021-06-17 09:10:15             NaT
12          10      13 2021-06-15 02:49:05             NaT

Lub z pustym miejscem:

df['duration'] = df['duration'].where(
    df['duration'] > pd.Timedelta(seconds=0),
    ''
)
    CustomerID  Order#                Time         duration
0            1       1 2021-06-16 19:11:21                 
1            2       2 2021-06-17 19:24:19                 
2            3       3 2021-06-16 19:22:42                 
3            4       4 2021-06-14 14:16:50                 
4            4       5 2021-06-14 18:17:48  0 days 04:00:58
5            5       6 2021-06-16 21:11:06                 
6            6       7 2021-06-15 17:02:19                 
7            7       8 2021-06-13 21:01:36                 
8            8       9 2021-06-16 18:40:14  2 days 03:53:15
9            8      10 2021-06-14 14:46:59                 
10           8      11 2021-06-14 14:46:59                 
11           9      12 2021-06-17 09:10:15                 
12          10      13 2021-06-15 02:49:05                 

DataFrame i importy:

import pandas as pd

df = pd.DataFrame({
    'CustomerID': [1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 8, 9, 10],
    'Order#': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
    'Time': ['2021-06-16 19:11:21', '2021-06-17 19:24:19',
             '2021-06-16 19:22:42', '2021-06-14 14:16:50',
             '2021-06-14 18:17:48', '2021-06-16 21:11:06',
             '2021-06-15 17:02:19', '2021-06-13 21:01:36',
             '2021-06-16 18:40:14', '2021-06-14 14:46:59',
             '2021-06-14 14:46:59', '2021-06-17 09:10:15', 
             '2021-06-15 02:49:5']
})
2
Henry Ecker 20 czerwiec 2021, 02:25