Groupby ile toplam panda yüzdesi


148

Bu açıkça basit, ama numpy bir yenidoğan olarak sıkışıp kalıyorum.

3 sütun, devlet, Office kimliği ve o ofis için Satış içeren bir CSV dosyası var.

Belirli bir eyalette ofis başına satış yüzdesini hesaplamak istiyorum (her eyaletteki tüm yüzdelerin toplamı% 100'dür).

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'})

Bu döndürür:

                  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

Ben kesir hesaplamak için tüm için toplam stateseviyesine kadar "ulaşmak" anlayamıyorum.groupbysalesstate


3
df['sales'] / df.groupby('state')['sales'].transform('sum')en açık cevap gibi görünüyor.
Paul Rougieux

Yanıtlar:


207

Paul H cevabı İkinci yapmak zorunda olacağı doğru groupbynesneyi, ancak daha basit bir şekilde yüzdesini hesaplayabilirsiniz - sadece ve bölmek onun toplamına sütunu. Paul H'nin cevabının başlangıcını kopyalamak:groupbystate_officesales

# 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()))

İadeler:

                     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
Burada neler oluyor? Anladığım kadarıyla x, bir tür tablo, bu yüzden 100 * xsezgisel olarak mantıklı değil (özellikle bazı hücreler gibi dizeler içeriyorsa AZ, ...).
dhardy

5
@dhardy state_office, Çoklu Dizine sahip bir Seridir - bu nedenle değerlerinin tamamı sayısal olan yalnızca bir sütundur. Groupby yaptıktan sonra, her xbiri bu sütunun bir alt kümesidir. bu mantıklı mı?
exp1orer

2
Olabilir, ama benim için işe yaramadı. Python 3'teki pandalar biraz farklı çalışıyor mu?
dhardy

1
Ne anlama level=0geliyor?
van_d39

3
@Veenit, sütunlardan biri yerine dizinin ilk düzeyine göre gruplandırdığınız anlamına gelir.
exp1orer

54

Durumlara göre gruplanan ikinci bir groupby nesnesi oluşturmanız ve sonra divyöntemi kullanmanız gerekir :

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

level='state'içinde kwarg divyayına pandalar söyler / değerlere dataframes tabanını katılmak stateindeksi düzeyinde.


4
3 dizininiz varsa bu yöntem işe yarar mı? Önce 3 sütun üzerinde bir groupby yaptım. Sonra sadece 2 ikinci bir groupby yaptım ve toplamı hesaplamak. Sonra kullanmaya çalışıyorum divama birlikte level=["index1", "index2"]söyler Join on level between two MultiIndex objects is ambiguous.
Ger

@Ger İşe yarıyor, ama yanlış yaptığınızı o açıklamadan ayırt edebilmem mümkün değil. Sitede biraz daha arama yapın. Hiçbir şey bulamazsanız, sorunu gösteren tekrarlanabilir bir örnekle yeni bir soru oluşturun. stackoverflow.com/questions/20109391/…
Paul H

34

Kısacası SeriesGroupBy'yi kullanırdım:

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

Birden fazla grup için dönüşümü kullanmanız gerekir ( Radical'in df'sini kullanarak ):

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

Bu, diğer cevaplardan biraz daha performanslı görünüyor (Radical'in cevabının iki katından daha az, benim için ~ 0.08s).


5
Bu süper hızlı. Bunu tercih edilen pandalar yaklaşımı olarak tavsiye ederim. Gerçekten numpy'nin vektörleştirme ve panda indekslemesinden yararlanır.
Charles

Birden fazla grupla çalıştığım için bu benim için de işe yaradı. Teşekkürler.
irene

27

Bunun kıyaslamaya ihtiyacı olduğunu düşünüyorum. OP'nin orijinal DataFrame'ini kullanarak,

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

Cevabına yorum yaptığı gibi, Andy vektörleşme ve panda indekslemesinden tam olarak yararlanıyor.

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

Çevrim başına 3,42 ms ± 16,7 µs
(ortalama 7 çalışma, ortalama 100 döngü, ortalama 100 döngü)


2. Paul 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 döngü başına ± 24.4 µs
(ortalama 7 adım, ortalama 100 döngü, her biri 100 döngü)


3. expororer

Bu seviye 0'daki x.sum()her biri için hesapladığı için en yavaş cevaptır x.

Benim için bu, mevcut haliyle olmasa da, hala yararlı bir cevaptır. Daha küçük veri kümelerinde hızlı EDA için, applybunu tek bir satıra yazmak için yöntem zinciri kullanmanıza izin verir . Bu nedenle , en değerli kaynağınız (beyniniz !!) için aslında çok hesaplamalı olarak pahalı olan bir değişkenin adına karar verme ihtiyacını ortadan kaldırıyoruz .

İşte değişiklik,

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

Loop başına 10.6 ms ± 81.5 µs
(ortalama 7 std. Ortalama, her biri 100 ilmek)


Yani hiç kimse küçük bir veri kümesinde 6 ms umurumda değil. Bununla birlikte, bu 3 kat hızlanır ve yüksek kardinalite gruplarına sahip daha büyük bir veri kümesinde bu büyük bir fark yaratacaktır.

Yukarıdaki koda ek olarak, 14412 devlet kategorisi ve 600 office_id ile şekilli (12.000.000, 3) bir DataFrame,

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
})

Andy's kullanarak,

Devre başına 2 s ± 10,4 ms
(7 çalışmanın ortalama ± standart sapması, her biri 1 döngü)

ve exp1orer

Çevrim başına 19 s ± 77,1 ms
(7 çalışmanın ortalama ± standart sapması, her biri 1 döngü)

Şimdi büyük, yüksek kardinalite veri kümelerinde x10'un hızlandığını görüyoruz.


Eğer bu UV cevap bu üç cevap UV emin olun !!


17

(Bu çözüm, bu makaleden esinlenmiştir https://pbpython.com/pandas_transform.html )

Aşağıdaki çözümü kullanarak en basit (ve muhtemelen en hızlı) bulmak transformation:

Dönüşüm: Toplama, verilerin indirgenmiş bir sürümünü döndürmek zorunda olsa da, dönüşüm, yeniden birleştirmek için tüm verilerin dönüştürülmüş bir sürümünü döndürebilir. Böyle bir dönüşüm için çıktı, girdi ile aynı şekildedir.

Kullanarak Yani transformation, çözüm 1-liner geçerli:

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

Yazdırırsanız:

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 (benim diziye dönüştürmeden) df'yi bir df olarak tuttuğu ve sadece bir% sütunu eklediği için bu benim favori cevabım. Teşekkür ederim
T.Fung

Bu cevabın varyasyonu benim için çok iyi çalıştıtransform('max')
Sheldore

11

Bunun eski bir soru olduğunu biliyorum, ancak exp1orer'in cevabı çok sayıda benzersiz gruba sahip veri kümeleri için çok yavaştır (muhtemelen lambda nedeniyle). Ben bir dizi hesaplama dönüştürmek için onların cevap inşa böylece şimdi süper hızlı! Örnek kod aşağıdadır:

50.000 benzersiz grupla test veri çerçevesi oluşturun

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})

Gruplandırıldığında şöyle görünür:

                             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]

Yüzde bulma dizisi yöntemi:

# 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)

Bu yöntem yaklaşık ~ 0.15 saniye sürer

Üst yanıt yöntemi (lambda işlevini kullanarak):

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()))

Bu yöntemin aynı sonucu üretmesi yaklaşık ~ 21 saniye sürer.

Sonuç:

      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

Burada zaten iyi cevaplar olduğunun farkındayım.

Yine de kendime katkıda bulunmak istiyorum, çünkü bunun gibi temel ve basit bir soru hissediyorum, bir bakışta anlaşılabilir kısa bir çözüm olmalı.

Ayrıca, yüzdeleri yeni bir sütun olarak ekleyebileceğim şekilde çalışmalı ve veri çerçevesinin geri kalanına dokunulmaz. Son fakat aynı derecede önemli olarak, birden fazla gruplama seviyesinin olduğu duruma (örneğin, sadece devlet yerine devlet ve ülke) açık bir şekilde genelleme yapılmalıdır.

Aşağıdaki snippet bu kriterleri yerine getirir:

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

Hala Python 2 kullanıyorsanız, lambda teriminin paydasındaki x'i kayan nokta (x) ile değiştirmeniz gerektiğini unutmayın.


Bu en iyi cevap IMO. Eklenecek tek şey * 100bir yüzde yapmak olacaktır.
Bouncner

1
@Bouncner: Evet, kesinlikle bir yüzde almak için 100 ile çarpmanız veya yeni değişkeni "satış_dönemi" den "satış_ratipi" olarak yeniden adlandırmanız gerekir. Şahsen, ikincisini tercih ediyorum ve cevabı buna göre düzenledim. Bahsettiğiniz için teşekkürler!
MightyCurious

2
Birden fazla seviyeniz varsa bu işe yaramaz.
irene

@irene: Güzel nokta, teşekkürler! Muhtemelen bu durumda df.reset_index (). Groupby (['state']) ['sales']. Dönüşümü (lambda x: x / x.sum ()) işe yarar. Yoksa bir şey mi görüyorum?
MightyCurious

1
Bu cevap harika. Geçici bir groupbynesne yaratmayı içermez , süper özlüdür ve çok mantıksal olarak soldan sağa okur.
C. Braun

7

Sütun veya dizin içindeki yüzdeleri bulmanın en zarif yolu kullanmaktır pd.crosstab.

Örnek veri

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)]})

Çıktı veri çerçevesi şöyle

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

Toplanacak dizini, sütunları ve değerleri belirtmeniz yeterlidir. Normalize anahtar kelimesi, bağlama bağlı olarak dizin veya sütunlardaki% değerini hesaplar.

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

Şunları yapabilirsiniz sumbütün DataFrametarafından ve bölme statetoplam:

# 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

İadeler

    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

Ancak bunun yalnızca stateDataFrame öğesinin toplanmasını sağlayan sayısaldan farklı olduğu için çalıştığını unutmayın . Örneğin, office_idbunun yerine karakter ise , bir hata mesajı alırsınız:

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

TypeError: /: 'str' ve 'str' için desteklenmeyen işlenen türleri


Bunun yalnızca sütun dışındaki tüm sütunlar groupbysayısal olduğunda işe yarayacak şekilde düzenlendi . Ancak aksi halde oldukça zariftir. Diğer strsütunlarla çalışmasını sağlamanın bir yolu var mı ?
Max Ghenis

Bildiğim kadarıyla değil: stackoverflow.com/questions/34099684/…
iggy

2

Bu 1 satırda hile yapacağını düşünüyorum:

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

Veri kümesinin tüm sütunlarını aldığını düşünüyorum. bu durumda, sadece bir tane var. Birkaç işleminiz varsa ve bu işlemi tek bir işlemde gerçekleştirmek istiyorsanız, bunu groupby ifadesinden sonra belirtin: df.groupby (['state', 'office_id']) [[KOLON ADINIZ BURADA]]. diğer sütunlara
dokunmamak

@louisD: Kısa tutmaya çalışmanızı çok seviyorum. Ne yazık ki, sütunu önerdiğiniz gibi yeniden atamaya çalıştığımda, iki hata alıyorum: "ValueError: Buffer dtype uyumsuzluğu, beklenen 'Python nesnesi' ama 'uzun uzun' var" ve ayrıca (ilk istisna işlenirken): " TypeError: "Kullandığım kod şöyledir:" Kullandığım kod şuydu: df ['yüzde'] = df.groupby (['durum', 'office_id']). Sum (). Transform (lambda x: x / np.sum (x) * 100) Bu nedenle, bunu düzeltmek için ayrı bir cevap göndereceğim.
MightyCurious

1

Ben kullandım basit yolu sonra 2 groupby's sonra basit bölümü yapıyor bir birleştirme olduğunu.

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()

İadeler:

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

Pandaları da öğrenen biri olarak, pandaların perde arkasındaki çalışmaların çoğunu gizlediği için diğer cevapları biraz örtülü buldum. Diğer bir deyişle, sütun ve dizin adlarını otomatik olarak eşleştirerek işlemin nasıl çalıştığı. Bu kod, @ exp1orer'in kabul edilen yanıtının adım adım sürümüne eşdeğer olmalıdır

İle, dftakma ad ile arayacağım 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_salesstate_office_salestoplamı index level 0(en solda) olarak gruplandırılır .

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

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

İki veri çerçevesi bir dizin adı paylaştığından ve bir sütun adı pandaları aşağıdaki gibi paylaşılan dizinler aracılığıyla uygun konumları bulur:

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

Bunu daha da iyi göstermek için, XXeşdeğeri olmayan bir kısmi toplam var. Pandalar, örtüşme olmayan pandaların yok sayacağı dizin ve sütun adlarına göre konumla eşleşir:

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

Paylaşılan dizin veya sütun olmadığında bu çok netleşir. Burada missing_index_totals, state_total_salesbir dizin adı olmaması dışında eşittir .

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

Tek hat çözümü:

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

Bu, bir dizi ofis başına oran döndürür - kendi başına kullanılabilir veya orijinal Veri Çerçevesine atanabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.