Panda percentuale del totale con groupby


148

Questo è ovviamente semplice, ma come newbe insensibile mi sto bloccando.

Ho un file CSV che contiene 3 colonne, lo stato, l'ID ufficio e le vendite per quell'ufficio.

Voglio calcolare la percentuale di vendite per ufficio in un dato stato (il totale di tutte le percentuali in ogni stato è del 100%).

df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
                   'office_id': range(1, 7) * 2,
                   'sales': [np.random.randint(100000, 999999)
                             for _ in range(12)]})

df.groupby(['state', 'office_id']).agg({'sales': 'sum'})

Questo ritorna:

                  sales
state office_id        
AZ    2          839507
      4          373917
      6          347225
CA    1          798585
      3          890850
      5          454423
CO    1          819975
      3          202969
      5          614011
WA    2          163942
      4          369858
      6          959285

Non riesco a capire come "raggiungere" il statelivello del groupbytotale salesper il totale stateper calcolare la frazione.


3
df['sales'] / df.groupby('state')['sales'].transform('sum')sembra essere la risposta più chiara.
Paul Rougieux,

Risposte:


207

La risposta di Paul H è giusto che si dovrà fare un secondo groupbyoggetto, ma è possibile calcolare la percentuale in modo più semplice - basta groupbyl' state_officee dividere il salescolonna la somma. Copia dell'inizio della risposta di Paul H:

# From Paul H
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
                   'office_id': list(range(1, 7)) * 2,
                   'sales': [np.random.randint(100000, 999999)
                             for _ in range(12)]})
state_office = df.groupby(['state', 'office_id']).agg({'sales': 'sum'})
# Change: groupby state_office and divide by sum
state_pcts = state_office.groupby(level=0).apply(lambda x:
                                                 100 * x / float(x.sum()))

Ritorna:

                     sales
state office_id           
AZ    2          16.981365
      4          19.250033
      6          63.768601
CA    1          19.331879
      3          33.858747
      5          46.809373
CO    1          36.851857
      3          19.874290
      5          43.273852
WA    2          34.707233
      4          35.511259
      6          29.781508

1
Cosa sta succedendo qui? A quanto ho capito, xè una tabella di qualche tipo, quindi 100 * xnon ha senso in modo intuitivo (specialmente quando alcune celle contengono stringhe come AZ, ...).
dhardy,

5
@dhardy state_officeè una serie con un indice multiplo, quindi è solo una colonna i cui valori sono tutti numerici. Dopo aver eseguito il groupby, ognuno xè un sottoinsieme di quella colonna. Ha senso?
exp1orer

2
Potrebbe, ma non ha funzionato per me. I panda in Python 3 funzionano in modo leggermente diverso?
dhardy,

1
Cosa level=0significa?
van_d39

3
@Veenit significa che stai raggruppando per il primo livello dell'indice, piuttosto che per una delle colonne.
exp1orer

54

È necessario creare un secondo oggetto groupby che raggruppa in base agli stati, quindi utilizzare il divmetodo:

import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
               'office_id': list(range(1, 7)) * 2,
               'sales': [np.random.randint(100000, 999999) for _ in range(12)]})

state_office = df.groupby(['state', 'office_id']).agg({'sales': 'sum'})
state = df.groupby(['state']).agg({'sales': 'sum'})
state_office.div(state, level='state') * 100


                     sales
state office_id           
AZ    2          16.981365
      4          19.250033
      6          63.768601
CA    1          19.331879
      3          33.858747
      5          46.809373
CO    1          36.851857
      3          19.874290
      5          43.273852
WA    2          34.707233
      4          35.511259
      6          29.781508

il level='state'kwarg in divdice ai panda di trasmettere / unire la base dei frame di dati sui valori nel statelivello dell'indice.


4
Questo metodo funziona se hai 3 indici? Prima ho fatto un groupby su 3 colonne. Poi ho fatto un secondo groupby su solo 2 e ho calcolato la somma. Quindi provo a usare divma con level=["index1", "index2"]ma mi dice che Join on level between two MultiIndex objects is ambiguous.
Ger,

@Ger Funziona, ma non c'è modo che io possa capire cosa stai facendo di sbagliato da quella descrizione. Cerca un po 'di più sul sito. Se non trovi nulla, crea una nuova domanda con un esempio riproducibile che dimostri il problema. stackoverflow.com/questions/20109391/…
Paul H

34

Per concisione userei SeriesGroupBy:

In [11]: c = df.groupby(['state', 'office_id'])['sales'].sum().rename("count")

In [12]: c
Out[12]:
state  office_id
AZ     2            925105
       4            592852
       6            362198
CA     1            819164
       3            743055
       5            292885
CO     1            525994
       3            338378
       5            490335
WA     2            623380
       4            441560
       6            451428
Name: count, dtype: int64

In [13]: c / c.groupby(level=0).sum()
Out[13]:
state  office_id
AZ     2            0.492037
       4            0.315321
       6            0.192643
CA     1            0.441573
       3            0.400546
       5            0.157881
CO     1            0.388271
       3            0.249779
       5            0.361949
WA     2            0.411101
       4            0.291196
       6            0.297703
Name: count, dtype: float64

Per più gruppi devi usare transform (usando Radical's df ):

In [21]: c =  df.groupby(["Group 1","Group 2","Final Group"])["Numbers I want as percents"].sum().rename("count")

In [22]: c / c.groupby(level=[0, 1]).transform("sum")
Out[22]:
Group 1  Group 2  Final Group
AAHQ     BOSC     OWON           0.331006
                  TLAM           0.668994
         MQVF     BWSI           0.288961
                  FXZM           0.711039
         ODWV     NFCH           0.262395
...
Name: count, dtype: float64

Questo sembra essere leggermente più performante rispetto alle altre risposte (solo meno del doppio della velocità della risposta di Radical, per me ~ 0,08 secondi).


5
Questo è super veloce. Lo consiglierei come l'approccio panda preferito. Sfrutta davvero la vettorializzazione e l'indicizzazione dei panda di Numpy.
Charles

Questo ha funzionato bene anche per me, dato che sto lavorando con più gruppi. Grazie.
irene,

27

Penso che questo abbia bisogno di analisi comparativa. Utilizzando il DataFrame originale di OP,

df = pd.DataFrame({
    'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
    'office_id': range(1, 7) * 2,
    'sales': [np.random.randint(100000, 999999) for _ in range(12)]
})

1 ° Andy Hayden

Come commentato sulla sua risposta, Andy sfrutta appieno la vettorializzazione e l'indicizzazione dei panda.

c = df.groupby(['state', 'office_id'])['sales'].sum().rename("count")
c / c.groupby(level=0).sum()

3,42 ms ± 16,7 µs per loop
(media ± deviazione standard di 7 cicli, 100 loop ciascuno)


2 ° Paolo H

state_office = df.groupby(['state', 'office_id']).agg({'sales': 'sum'})
state = df.groupby(['state']).agg({'sales': 'sum'})
state_office.div(state, level='state') * 100

4.66 ms ± 24.4 µs per loop
(media ± deviazione standard di 7 cicli, 100 loop ciascuno)


3 ° exp1orer

Questa è la risposta più lenta in quanto viene calcolata x.sum()per ciascuna xnel livello 0.

Per me, questa è ancora una risposta utile, sebbene non nella sua forma attuale. Per un rapido EDA su insiemi di dati più piccoli, applyconsente di utilizzare il concatenamento dei metodi per scrivere questo in un'unica riga. Pertanto eliminiamo la necessità di decidere il nome di una variabile, che in realtà è molto computazionalmente costosa per la tua risorsa più preziosa (il tuo cervello !!).

Ecco la modifica,

(
    df.groupby(['state', 'office_id'])
    .agg({'sales': 'sum'})
    .groupby(level=0)
    .apply(lambda x: 100 * x / float(x.sum()))
)

10,6 ms ± 81,5 µs per loop
(media ± deviazione standard di 7 cicli, 100 loop ciascuno)


Quindi nessuno si preoccuperà di 6ms su un piccolo set di dati. Tuttavia, si tratta di una velocità 3 volte maggiore e, su un set di dati più ampio con gruppi di cardinalità elevati, questo farà una differenza enorme.

Aggiungendo al codice sopra, creiamo un DataFrame con forma (12.000.000, 3) con 14412 categorie di stato e 600 office_ids,

import string

import numpy as np
import pandas as pd
np.random.seed(0)

groups = [
    ''.join(i) for i in zip(
    np.random.choice(np.array([i for i in string.ascii_lowercase]), 30000),
    np.random.choice(np.array([i for i in string.ascii_lowercase]), 30000),
    np.random.choice(np.array([i for i in string.ascii_lowercase]), 30000),
                       )
]

df = pd.DataFrame({'state': groups * 400,
               'office_id': list(range(1, 601)) * 20000,
               'sales': [np.random.randint(100000, 999999)
                         for _ in range(12)] * 1000000
})

Usando Andy,

2 s ± 10,4 ms per ciclo
(media ± deviazione standard di 7 cicli, 1 ciclo ciascuno)

ed exp1orer

19 s ± 77,1 ms per ciclo
(media ± deviazione standard di 7 cicli, 1 ciclo ciascuno)

Quindi ora vediamo x10 accelerare su grandi set di dati di cardinalità.


Assicurati di UV queste tre risposte se UV questo !!


17

(Questa soluzione è ispirata a questo articolo https://pbpython.com/pandas_transform.html )

Trovo che la seguente soluzione sia la più semplice (e probabilmente la più veloce) usando transformation:

Trasformazione: sebbene l'aggregazione debba restituire una versione ridotta dei dati, la trasformazione può restituire una versione trasformata dei dati completi da ricombinare. Per tale trasformazione, l'output ha la stessa forma dell'input.

Quindi transformation, usando , la soluzione è 1-liner:

df['%'] = 100 * df['sales'] / df.groupby('state')['sales'].transform('sum')

E se stampi:

print(df.sort_values(['state', 'office_id']).reset_index(drop=True))

   state  office_id   sales          %
0     AZ          2  195197   9.844309
1     AZ          4  877890  44.274352
2     AZ          6  909754  45.881339
3     CA          1  614752  50.415708
4     CA          3  395340  32.421767
5     CA          5  209274  17.162525
6     CO          1  549430  42.659629
7     CO          3  457514  35.522956
8     CO          5  280995  21.817415
9     WA          2  828238  35.696929
10    WA          4  719366  31.004563
11    WA          6  772590  33.298509

3
@Cancer Questa è la mia risposta preferita poiché mantiene il df come df (senza convertirlo in serie) e aggiunge semplicemente una colonna%. Grazie
T.Fung

La variazione di questa risposta ha funzionato molto bene con metransform('max')
Sheldore,

11

So che questa è una vecchia domanda, ma la risposta di exp1orer è molto lenta per i set di dati con un numero elevato di gruppi univoci (probabilmente a causa della lambda). Ho costruito la loro risposta per trasformarla in un calcolo di array, quindi ora è super veloce! Di seguito è riportato il codice di esempio:

Crea il frame di dati di test con 50.000 gruppi univoci

import random
import string
import pandas as pd
import numpy as np
np.random.seed(0)

# This is the total number of groups to be created
NumberOfGroups = 50000

# Create a lot of groups (random strings of 4 letters)
Group1     = [''.join(random.choice(string.ascii_uppercase) for _ in range(4)) for x in range(NumberOfGroups/10)]*10
Group2     = [''.join(random.choice(string.ascii_uppercase) for _ in range(4)) for x in range(NumberOfGroups/2)]*2
FinalGroup = [''.join(random.choice(string.ascii_uppercase) for _ in range(4)) for x in range(NumberOfGroups)]

# Make the numbers
NumbersForPercents = [np.random.randint(100, 999) for _ in range(NumberOfGroups)]

# Make the dataframe
df = pd.DataFrame({'Group 1': Group1,
                   'Group 2': Group2,
                   'Final Group': FinalGroup,
                   'Numbers I want as percents': NumbersForPercents})

Quando raggruppato sembra:

                             Numbers I want as percents
Group 1 Group 2 Final Group                            
AAAH    AQYR    RMCH                                847
                XDCL                                182
        DQGO    ALVF                                132
                AVPH                                894
        OVGH    NVOO                                650
                VKQP                                857
        VNLY    HYFW                                884
                MOYH                                469
        XOOC    GIDS                                168
                HTOY                                544
AACE    HNXU    RAXK                                243
                YZNK                                750
        NOYI    NYGC                                399
                ZYCI                                614
        QKGK    CRLF                                520
                UXNA                                970
        TXAR    MLNB                                356
                NMFJ                                904
        VQYG    NPON                                504
                QPKQ                                948
...
[50000 rows x 1 columns]

Metodo di matrice per trovare la percentuale:

# Initial grouping (basically a sorted version of df)
PreGroupby_df = df.groupby(["Group 1","Group 2","Final Group"]).agg({'Numbers I want as percents': 'sum'}).reset_index()
# Get the sum of values for the "final group", append "_Sum" to it's column name, and change it into a dataframe (.reset_index)
SumGroup_df = df.groupby(["Group 1","Group 2"]).agg({'Numbers I want as percents': 'sum'}).add_suffix('_Sum').reset_index()
# Merge the two dataframes
Percents_df = pd.merge(PreGroupby_df, SumGroup_df)
# Divide the two columns
Percents_df["Percent of Final Group"] = Percents_df["Numbers I want as percents"] / Percents_df["Numbers I want as percents_Sum"] * 100
# Drop the extra _Sum column
Percents_df.drop(["Numbers I want as percents_Sum"], inplace=True, axis=1)

Questo metodo richiede circa 0,15 secondi

Metodo di risposta superiore (utilizzando la funzione lambda):

state_office = df.groupby(['Group 1','Group 2','Final Group']).agg({'Numbers I want as percents': 'sum'})
state_pcts = state_office.groupby(level=['Group 1','Group 2']).apply(lambda x: 100 * x / float(x.sum()))

Questo metodo richiede circa ~ 21 secondi per produrre lo stesso risultato.

Il risultato:

      Group 1 Group 2 Final Group  Numbers I want as percents  Percent of Final Group
0        AAAH    AQYR        RMCH                         847               82.312925
1        AAAH    AQYR        XDCL                         182               17.687075
2        AAAH    DQGO        ALVF                         132               12.865497
3        AAAH    DQGO        AVPH                         894               87.134503
4        AAAH    OVGH        NVOO                         650               43.132050
5        AAAH    OVGH        VKQP                         857               56.867950
6        AAAH    VNLY        HYFW                         884               65.336290
7        AAAH    VNLY        MOYH                         469               34.663710
8        AAAH    XOOC        GIDS                         168               23.595506
9        AAAH    XOOC        HTOY                         544               76.404494

9

Mi rendo conto che ci sono già buone risposte qui.

Vorrei tuttavia contribuire con il mio, poiché sento una domanda elementare e semplice come questa, dovrebbe esserci una breve soluzione comprensibile a colpo d'occhio.

Dovrebbe anche funzionare in modo da poter aggiungere le percentuali come nuova colonna, lasciando intatto il resto del frame di dati. Ultimo ma non meno importante, dovrebbe generalizzare in modo ovvio il caso in cui esiste più di un livello di raggruppamento (ad esempio, stato e paese anziché solo stato).

Il frammento seguente soddisfa questi criteri:

df['sales_ratio'] = df.groupby(['state'])['sales'].transform(lambda x: x/x.sum())

Nota che se stai ancora usando Python 2, dovrai sostituire la x nel denominatore del termine lambda con float (x).


Questa è la migliore risposta IMO. L'unica cosa da aggiungere sarebbe quella * 100di renderlo una percentuale.
Bouncner

1
@Bouncner: Sì, a rigore si dovrebbe moltiplicare per 100 per ottenere una percentuale o rinominare la nuova variabile da "sales_percentage" a "sales_ratio". Personalmente preferisco quest'ultima e ho modificato la risposta di conseguenza. Grazie per averlo menzionato!
MightyCurious

2
Questo non funziona se hai più livelli.
Irene,

@irene: buon punto, grazie! Probabilmente in quel caso df.reset_index (). Groupby (['state']) ['sales']. Transform (lambda x: x / x.sum ()) funzionerebbe. O sto trascurando qualcosa?
MightyCurious

1
Questa risposta è fantastica Non comporta la creazione di un groupbyoggetto temporaneo , è super conciso e legge logicamente da sinistra a destra.
C. Braun,

7

Il modo più elegante per trovare le percentuali tra colonne o indici è utilizzare pd.crosstab.

Dati di esempio

df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
               'office_id': list(range(1, 7)) * 2,
               'sales': [np.random.randint(100000, 999999) for _ in range(12)]})

Il frame di dati di output è così

print(df)

        state   office_id   sales
    0   CA  1   764505
    1   WA  2   313980
    2   CO  3   558645
    3   AZ  4   883433
    4   CA  5   301244
    5   WA  6   752009
    6   CO  1   457208
    7   AZ  2   259657
    8   CA  3   584471
    9   WA  4   122358
    10  CO  5   721845
    11  AZ  6   136928

Basta specificare l'indice, le colonne e i valori da aggregare. La parola chiave normalize calcolerà% su indice o colonne in base al contesto.

result = pd.crosstab(index=df['state'], 
                     columns=df['office_id'], 
                     values=df['sales'], 
                     aggfunc='sum', 
                     normalize='index').applymap('{:.2f}%'.format)




print(result)
office_id   1   2   3   4   5   6
state                       
AZ  0.00%   0.20%   0.00%   0.69%   0.00%   0.11%
CA  0.46%   0.00%   0.35%   0.00%   0.18%   0.00%
CO  0.26%   0.00%   0.32%   0.00%   0.42%   0.00%
WA  0.00%   0.26%   0.00%   0.10%   0.00%   0.63%

3

Puoi sumtutto DataFramee dividere per il statetotale:

# Copying setup from Paul H answer
import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
               'office_id': list(range(1, 7)) * 2,
               'sales': [np.random.randint(100000, 999999) for _ in range(12)]})
# Add a column with the sales divided by state total sales.
df['sales_ratio'] = (df / df.groupby(['state']).transform(sum))['sales']

df

ritorna

    office_id   sales state  sales_ratio
0           1  405711    CA     0.193319
1           2  535829    WA     0.347072
2           3  217952    CO     0.198743
3           4  252315    AZ     0.192500
4           5  982371    CA     0.468094
5           6  459783    WA     0.297815
6           1  404137    CO     0.368519
7           2  222579    AZ     0.169814
8           3  710581    CA     0.338587
9           4  548242    WA     0.355113
10          5  474564    CO     0.432739
11          6  835831    AZ     0.637686

Tuttavia, questo funziona solo perché tutte le colonne diverse da quelle statenumeriche consentono la somma dell'intero DataFrame. Ad esempio, se office_idinvece è un carattere, viene visualizzato un errore:

df.office_id = df.office_id.astype(str)
df['sales_ratio'] = (df / df.groupby(['state']).transform(sum))['sales']

TypeError: tipi di operando non supportati per /: 'str' e 'str'


Ho modificato per notare che questo funziona solo quando tutte le colonne tranne la groupbycolonna sono numeriche. Ma per il resto è abbastanza elegante. C'è un modo per farlo funzionare con altre strcolonne?
Max Ghenis,


2

Penso che questo farebbe il trucco in 1 riga:

df.groupby(['state', 'office_id']).sum().transform(lambda x: x/np.sum(x)*100)

Credo che siano necessarie tutte le colonne del set di dati. in questo caso, ce n'è solo uno. Se ne hai diversi e vuoi eseguire questa operazione su una sola, specificala solo dopo l'espressione groupby: df.groupby (['state', 'office_id']) [[YOUR COLUMN NAME HERE]]. Ecc se vuoi per mantenere intatte le altre colonne, basta riassegnare le colonne specifiche
louisD

@louisD: Mi piace molto il tuo approccio nel cercare di farla breve. Sfortunatamente, quando provo a riassegnare la colonna come suggerito, ottengo due errori: "ValueError: mancata corrispondenza del tipo di buffer, previsto" oggetto Python "ma ottenuto" long long "", e inoltre (durante la gestione della prima eccezione): " TypeError: indice incompatibile della colonna inserita con indice frame "Il codice che ho usato era il seguente: df ['percent'] = df.groupby (['state', 'office_id']). Sum (). Transform (lambda x: x / np.sum (x) * 100) Pertanto, posterò una risposta separata per risolvere questo problema.
MightyCurious,

1

Il modo semplice che ho usato è una fusione dopo i 2 groupby e poi la divisione semplice.

import numpy as np
import pandas as pd
np.random.seed(0)
df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
               'office_id': list(range(1, 7)) * 2,
               'sales': [np.random.randint(100000, 999999) for _ in range(12)]})

state_office = df.groupby(['state', 'office_id'])['sales'].sum().reset_index()
state = df.groupby(['state'])['sales'].sum().reset_index()
state_office = state_office.merge(state, left_on='state', right_on ='state', how = 'left')
state_office['sales_ratio'] = 100*(state_office['sales_x']/state_office['sales_y'])

   state  office_id  sales_x  sales_y  sales_ratio
0     AZ          2   222579  1310725    16.981365
1     AZ          4   252315  1310725    19.250033
2     AZ          6   835831  1310725    63.768601
3     CA          1   405711  2098663    19.331879
4     CA          3   710581  2098663    33.858747
5     CA          5   982371  2098663    46.809373
6     CO          1   404137  1096653    36.851857
7     CO          3   217952  1096653    19.874290
8     CO          5   474564  1096653    43.273852
9     WA          2   535829  1543854    34.707233
10    WA          4   548242  1543854    35.511259
11    WA          6   459783  1543854    29.781508

1
df = pd.DataFrame({'state': ['CA', 'WA', 'CO', 'AZ'] * 3,
               'office_id': list(range(1, 7)) * 2,
               'sales': [np.random.randint(100000, 999999)
                         for _ in range(12)]})

grouped = df.groupby(['state', 'office_id'])
100*grouped.sum()/df[["state","sales"]].groupby('state').sum()

Ritorna:

sales
state   office_id   
AZ  2   54.587910
    4   33.009225
    6   12.402865
CA  1   32.046582
    3   44.937684
    5   23.015735
CO  1   21.099989
    3   31.848658
    5   47.051353
WA  2   43.882790
    4   10.265275
    6   45.851935

0

Come qualcuno che sta anche imparando i panda, ho trovato le altre risposte un po 'implicite mentre i panda nascondono la maggior parte del lavoro dietro le quinte. Vale a dire come funziona l'operazione abbinando automaticamente i nomi di colonne e indici. Questo codice dovrebbe essere equivalente a una versione passo passo della risposta accettata da @ exp1orer

Con il df, lo chiamerò con l'alias state_office_sales:

                  sales
state office_id        
AZ    2          839507
      4          373917
      6          347225
CA    1          798585
      3          890850
      5          454423
CO    1          819975
      3          202969
      5          614011
WA    2          163942
      4          369858
      6          959285

state_total_salesè state_office_salesraggruppato per somme totali in index level 0(all'estrema sinistra).

In:   state_total_sales = df.groupby(level=0).sum()
      state_total_sales

Out: 
       sales
state   
AZ     2448009
CA     2832270
CO     1495486
WA     595859

Poiché i due frame di dati condividono un nome indice e un panda nome colonna troveranno le posizioni appropriate attraverso indici condivisi come:

In:   state_office_sales / state_total_sales

Out:  

                   sales
state   office_id   
AZ      2          0.448640
        4          0.125865
        6          0.425496
CA      1          0.288022
        3          0.322169
        5          0.389809
CO      1          0.206684
        3          0.357891
        5          0.435425
WA      2          0.321689
        4          0.346325
        6          0.331986

Per illustrare questo ancora meglio, ecco un totale parziale con un XXche non ha equivalenti. I panda corrisponderanno alla posizione in base all'indice e ai nomi delle colonne, dove non vi sono panda sovrapposti lo ignoreranno:

In:   partial_total = pd.DataFrame(
                      data   =  {'sales' : [2448009, 595859, 99999]},
                      index  =             ['AZ',    'WA',   'XX' ]
                      )
      partial_total.index.name = 'state'


Out:  
         sales
state
AZ       2448009
WA       595859
XX       99999
In:   state_office_sales / partial_total

Out: 
                   sales
state   office_id   
AZ      2          0.448640
        4          0.125865
        6          0.425496
CA      1          NaN
        3          NaN
        5          NaN
CO      1          NaN
        3          NaN
        5          NaN
WA      2          0.321689
        4          0.346325
        6          0.331986

Ciò diventa molto chiaro quando non ci sono indici o colonne condivisi. Qui missing_index_totalsè uguale a state_total_salestranne che non ha un nome-indice.

In:   missing_index_totals = state_total_sales.rename_axis("")
      missing_index_totals

Out:  
       sales
AZ     2448009
CA     2832270
CO     1495486
WA     595859
In:   state_office_sales / missing_index_totals 

Out:  ValueError: cannot join with no overlapping index names

-1

Soluzione a una riga:

df.join(
    df.groupby('state').agg(state_total=('sales', 'sum')),
    on='state'
).eval('sales / state_total')

Ciò restituisce una serie di rapporti per ufficio - può essere utilizzato da solo o assegnato al Dataframe originale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.