Mam zestaw danych zawierający imiona i nazwiska uczniów, datę transakcji i kwotę. Każdy student dokonał wielu transakcji.

Chcę obliczyć pozycję w bieżącym miesiącu i w poprzednim miesiącu na podstawie łącznej kwoty dla każdego ucznia.

Jestem w stanie utworzyć grupę według nazwiska ucznia, aby obliczyć całkowitą kwotę dla każdego ucznia przy użyciu:

transactions['Totals'] = transactions.groupby('Student Name')['Sale Amount'].transform('sum')

Jak to rozszerzyć, aby utworzyć dwie różne kolumny obliczające sumy z poprzedniego miesiąca i bieżącego miesiąca dla każdego ucznia, aby móc przypisać im rangi poprzedniego i bieżącego miesiąca?

Data ma następujący format:

    09/05/2015 04:18 PM
    07/15/2019 09:50 AM
    05/18/2018 02:34 PM
    08/11/2018 06:29 PM
    06/14/2018 07:42 AM

EDYCJA: Dodawanie ramki danych w celach informacyjnych:

Out[15]: 
      Date of Transaction       Student Name  Sale Amount
0     09/05/2015 04:18 PM          Dan Kelly         4333
1     07/15/2019 09:50 AM         Peter Dyer         8805
2     05/18/2018 02:34 PM  Natalie Robertson         5640
3     08/11/2018 06:29 PM        Sean Miller         6485
4     06/14/2018 07:42 AM     Thomas Forsyth         6815
                  ...                ...          ...
9977  03/15/2018 09:28 PM        Grace Vance         6379
9978  08/07/2019 11:14 PM  Alexandra Cameron         6688
9979  01/09/2015 10:53 AM  Sebastian Vaughan         2262
9980  05/19/2019 10:00 PM     Caroline Blake         6977
9981  01/11/2016 04:05 AM     Austin Edmunds         3205

[9982 rows x 3 columns]

EDIT : Dodanie przykładowego oczekiwanego wyniku:

enter image description here

1
Nick Adams 5 grudzień 2019, 15:04
Czy jesteś w stanie podać dokładniejszy zbiór danych? z twoimi oczekiwanymi wynikami?
 – 
Umar.H
5 grudzień 2019, 15:12
- Jedyne trzy kolumny to te, o których już wspomniałem. Imię i nazwisko ucznia, kwota sprzedaży i data transakcji. Dodałem DataFrame w celach informacyjnych. Oczekiwany wynik to dwie nowe kolumny: Ranking poprzedniego miesiąca i Ranking bieżącego miesiąca.
 – 
Nick Adams
6 grudzień 2019, 06:43
pd.crosstab( df["Student Name"], df["Date"].dt.strftime("%b"), df["Sale Amount"], aggfunc="sum").fillna(0).reset_index() to powinno działać.
 – 
Umar.H
6 grudzień 2019, 13:03
To dało mi tabelę krzyżową z dyskretnymi miesiącami. Myślę, że będę potrzebował ciągłych miesięcy, aby zebrać dane dla bieżącego i poprzedniego miesiąca w celu obliczenia rang.
 – 
Nick Adams
6 grudzień 2019, 14:02
Czy jesteś w stanie dostarczyć zamierzone wyniki? byłoby o wiele łatwiej znaleźć rozwiązanie, gdyby tak było.
 – 
Umar.H
6 grudzień 2019, 14:11

2 odpowiedzi

Spróbuj wykonać następujące czynności, nie mogłem przetestować kodu, ponieważ nie dostarczasz próbki zestawu danych. Zakładam, że Twoja początkowa ramka danych nazywa się df:

import datetime
import pandas as pd

# get 1st day of current and previous months
CURRENT_MONTH_START = datetime.datetime.now().date() - datetime.timedelta(days=datetime.datetime.now().day -1)
PREVIOUS_MONTH_START = (CURRENT_MONTH_START - pd.DateOffset(months=1)).date()

# get ranks of those months
this_months_rank_df = df[df['date'] >= CURRENT_MONTH_START].groupby('Student Name')['Sale Amount'].transform('sum')
prev_months_rank_df = df[(df['date'] >= PREVIOUS_MONTH_START) & (df['date'] < CURRENT_MONTH_START)].groupby('Student Name')['Sale Amount'].transform('sum')
0
Neofytos Boufidis 5 grudzień 2019, 15:39

Utworzyłem ramkę danych z minimalnymi danymi, które podałeś: „Imię ucznia”, „Kwota sprzedaży”, „Data”

Moja ramka danych:

          df = pd.DataFrame([['12/05/2019 04:18 PM','Marisa',500],
               ['11/29/2019 04:18 PM','Marisa',500],
               ['11/20/2019 04:18 PM','Marisa',800],
               ['12/04/2019 04:18 PM','Peter',300],
               ['11/30/2019 04:18 PM','Peter',300],
               ['12/05/2019 04:18 PM','Debra',400],
               ['11/28/2019 04:18 PM','Debra',200],
               ['11/15/2019 04:18 PM','Debra',600],
               ['10/23/2019 04:18 PM','Debra',200]],columns=['Date','Student Name','Sale Amount']
               )

Upewnij się, że data jest kolumną z datą i godziną.

df.Date = pd.to_datetime(df.Date)

To daje całkowitą miesięczną kwotę na jednego ucznia w oryginalnej ramce danych:

df['Total'] = df.groupby(['Student Name',pd.Grouper(key='Date', freq='1M')])['Sale Amount'].transform('sum')


    Date Student             Name       Sale Amount  Total
0 2019-12-05 16:18:00       Marisa          500      500
1 2019-11-29 16:18:00       Marisa          500     1300
2 2019-11-20 16:18:00       Marisa          800     1300
3 2019-12-04 16:18:00        Peter          300      300
4 2019-11-30 16:18:00        Peter          300      300
5 2019-12-05 16:18:00        Debra          400      400
6 2019-11-28 16:18:00        Debra          200      800
7 2019-11-15 16:18:00        Debra          600      800
8 2019-10-23 16:18:00        Debra          200      200

Jak wydrukować tylko wybrane wyniki?

Df jest teraz nowy:

dnew = df

Usuńmy datę i godzinę, aby zachować tylko miesiące:

#Strip date to month
dnew['Date'] = dnew['Date'].apply(lambda x:x.date().strftime('%m'))

Wpisy kwoty sprzedaży i grupowanie według nazwiska i daty ucznia (nowa ramka danych to „sprzedaż”):

#Drop Sale Amount 
sales = dnew.drop(['Sale Amount'], axis=1).groupby(['Student Name','Date'])['Total'].max()


print(sales)
Student Name  Date
Debra         10       200
              11       800
              12       400
Marisa        11      1300
              12       500
Peter         11       300
              12       300

Właściwie „sprzedaż” to pandas.core.series.Series i ważne jest, aby o tym wiedzieć

print(sales.index)
MultiIndex([( 'Debra', '10'),
        ( 'Debra', '11'),
        ( 'Debra', '12'),
        ('Marisa', '11'),
        ('Marisa', '12'),
        ( 'Peter', '11'),
        ( 'Peter', '12')],
       names=['Student Name', 'Date'])    

 from datetime import datetime      
 curMonth = int(datetime.today().strftime('%m')) #transform to integer to perform (curMonth-1)
 #12

 #months of interest
 moi = sales.iloc[(sales.index.get_level_values('Date') == str(curMonth-1)) | (sales.index.get_level_values('Date') == str(curMonth))]

 print(moi)

 Student Name  Date
 Debra         11       800
               12       400
 Marisa        11      1300
               12       500
 Peter         11       300
               12       300
2
powerPixie 7 grudzień 2019, 10:45
To ma sens. Ale jak mogę to rozszerzyć, aby utworzyć dwie nowe kolumny, Ranking poprzedniego miesiąca i Ranking bieżącego miesiąca?
 – 
Nick Adams
6 grudzień 2019, 06:54
@NickAdams, zmodyfikowałem moją odpowiedź, aby pokazać możliwe rozwiązanie Twojego nowego pytania. Zaczyna się od "Jak wydrukować tylko wybrane wyniki?"
 – 
powerPixie
6 grudzień 2019, 15:31
Działa to dobrze, ale trochę różni się od moich oczekiwanych wyników. Dwa punkty: 1) Czy to będzie nadal działać, jeśli moje dane zawierają transakcje z wielu poprzednich lat? Czy dostosuje się do ostatniego miesiąca obecnego w danych, czy też wykorzystuje datę systemową do obliczania bieżącego i poprzedniego miesiąca? 2) Muszę wizualizować te dane w Tableau i chciałbym zachować oryginalne wiersze. Czy można zamiast tego utworzyć dwie nowe kolumny, które będą przechowywać rankingi z bieżącego i poprzedniego miesiąca na podstawie sprzedaży w tych miesiącach? (Lub nawet kwoty sprzedaży, które obliczyłeś, jeśli nie rankingi)
 – 
Nick Adams
9 grudzień 2019, 11:08
1) Czy potrzebujesz poprzednich lat? Jeśli tego nie zrobisz, możesz wyczyścić lub dopasować dane. Powiedziałeś, że chcesz bieżący miesiąc i poprzedni miesiąc, jeśli zwrócisz uwagę na kod, którego użyłem datetime.today(). Oznacza datę i czas systemowy. 2) Jeśli chcesz dodać dwa nowe wiersze, to bardziej przypomina to pierwsze rozwiązanie, które ci podałem, ponieważ zawsze będziesz mieć kolumnę kwoty sprzedaży (Kwota sprzedaży).
 – 
powerPixie
10 grudzień 2019, 09:00
Potrzebuję oryginalnego zestawu danych z danymi historycznymi (z poprzednich lat), aby przeprowadzić analizy, takie jak trendy i sumy. System rankingowy to kolejna analiza, która będzie oparta wyłącznie na sprzedaży z poprzedniego miesiąca i bieżącego miesiąca. W idealnym przypadku nie chcę tworzyć dwóch różnych wersji tego samego zestawu danych dla tych dwóch analiz. Wiem, że można to zrobić w tym samym zbiorze danych, tylko nie wiem jak. Najlepsze, co przychodzi mi do głowy, to podejście polegające na dodaniu dwóch nowych kolumn z rankingami z poprzedniego i bieżącego miesiąca, które będą wyświetlane na wyższym poziomie szczegółowości. Dzięki temu będę mógł używać jednego zmodyfikowanego zestawu danych do obu analiz.
 – 
Nick Adams
10 grudzień 2019, 15:50