Как да разделим няколко колони въз основа на три условия

Това е моят набор от данни, където имам различни държави, различни модели за различните държави, години и цена и обем.

  data_dic = {
    "Country" : [1,1,1,1,2,2,2,2],
    "Model" : ["A","B","B","A","A","B","B","A"],
    "Year": [2005,2005,2020,2020,2005,2005,2020,2020],
    "Price" : [100,172,852,953,350,452,658,896],
    "Volume" : [4,8,9,10,12,6,8,9]
}

    Country Model   Year    Price   Volume
0   1   A   2005    100 4
4   2   A   2005    350 12
3   1   A   2020    953 10
7   2   A   2020    896 9
1   1   B   2005    172 8
5   2   B   2005    452 6
2   1   B   2020    852 9
6   2   B   2020    658 8

Бих искал да получа следното, където 1) колона Division_Price е разделението на цената за държава 1 от модел A между 2005 г. и 2020 г. и 2) колона Division_Volume е разделението на обема за държава 1 от модел A между 2005 г. и 2005 г. 2020 г.

data_dic2 = {
    "Country" : [1,1,1,1,2,2,2,2],
    "Model" : ["A","B","B","A","A","B","B","A"],
    "Year": [2005,2005,2020,2020,2005,2005,2020,2020],
    "Price" : [100,172,852,953,350,452,658,896],
    "Volume" : [4,8,9,10,12,6,8,9],
    "Division_Price": [0.953,4.95,4.95,0.953,2.56,1.45,1.45,2.56],
    "Division_Volume": [2.5,1.125,1.125,2.5,1,1.33,1.33,1],
}
print(data_dic2)



Country Model   Year    Price   Volume  Division_Price  Division_Volume
0   1   A   2005    100 4   0.953   2.500
4   2   A   2005    350 12  2.560   1.000
3   1   A   2020    953 10  0.953   2.500
7   2   A   2020    896 9   2.560   1.000
1   1   B   2005    172 8   4.950   1.125
5   2   B   2005    452 6   1.450   1.330
2   1   B   2020    852 9   4.950   1.125
6   2   B   2020    658 8   1.450   1.330

Целият ми набор от данни има до 50 държави и имам до 10 модела с години, вариращи от 1990 до 2030 г. Все още не съм сигурен как да отчета множеството условия на три колони, така че да мога да разделя автоматично колоната Цена и Обем въз основа на три условия (т.е. държава, година и модели)?

Благодаря !


person XYZ_2635    schedule 23.02.2021    source източник
comment
Вместо 0.953 няма ли да е 9.530?   -  person Cyttorak    schedule 25.02.2021


Отговори (1)


Можете да опитате следното, като използвате df.pivot, df.stack() и df.merge:

>>> df2 = ( df.pivot(['Year'], columns=['Model', 'Country'], values=['Price', 'Volume'])
              .diff().bfill(downcast='infer').abs().stack().stack()
              .sort_index(level=-1).add_prefix('Difference_')
          )
>>> df2
                    Difference_Price  Difference_Volume
Year Country Model                                     
2005 1       A                   853                  6
     2       A                   546                  3
2020 1       A                   853                  6
     2       A                   546                  3
2005 1       B                   680                  1
     2       B                   206                  2
2020 1       B                   680                  1
     2       B                   206                  2

>>> df.merge(df2, on=['Country', 'Model', 'Year'], how='right')

   Country Model  Year  Price  Volume  Difference_Price  Difference_Volume
0        1     A  2005    100       4               853                  6
1        2     A  2005    350      12               546                  3
2        1     A  2020    953      10               853                  6
3        2     A  2020    896       9               546                  3
4        1     B  2005    172       8               680                  1
5        2     B  2005    452       6               206                  2
6        1     B  2020    852       9               680                  1
7        2     B  2020    658       8               206                  2

РЕДАКТИРАНЕ:

За новата ви рамка с данни мисля, че 0.953 ще бъде 9.530, ако е така, можете да използвате pct_change и да добавите 1:

>>> df2 = ( df.pivot(['Year'], columns=['Model', 'Country'], values=['Price', 'Volume'])
              .pct_change(1).add(1).bfill(downcast='infer').abs().stack().stack()
              .sort_index(level=-1).add_prefix('Division_').round(3)
          )
>>> df2
                      Division_Price    Division_Volume
Year Country Model                                     
2005 1       A                 9.530              2.500
     2       A                 2.560              0.750
2020 1       A                 9.530              2.500
     2       A                 2.560              0.750
2005 1       B                 4.953              1.125
     2       B                 1.456              1.333
2020 1       B                 4.953              1.125
     2       B                 1.456              1.333

>>> df.merge(df2, on=['Country', 'Model', 'Year'], how='right')
 
   Country Model  Year  Price  Volume    Division_Price    Division_Volume
0        1     A  2005    100       4             9.530              2.500
1        2     A  2005    350      12             2.560              0.750
2        1     A  2020    953      10             9.530              2.500
3        2     A  2020    896       9             2.560              0.750
4        1     B  2005    172       8             4.953              1.125
5        2     B  2005    452       6             1.456              1.333
6        1     B  2020    852       9             4.953              1.125
7        2     B  2020    658       8             1.456              1.333
person Cyttorak    schedule 23.02.2021
comment
Здравей Саяндип! Това е идеалното, което исках! Ако исках да имам в новите колони разделението (т.е. 10/4 за държава A и модел 1 за цена и 853/853 за обем) вместо разликата в колоната цена и обем, трябваше ли просто да променя diff() към div()? - person XYZ_2635; 25.02.2021
comment
853/853 за обем или 100/953? - person Cyttorak; 25.02.2021
comment
@XYZ_2635 Би било най-добре, ако добавите отделен въпрос или поне редактирате желания резултат в текущия въпрос. - person Cyttorak; 25.02.2021
comment
Здравей Саяндип! Току-що редактирах въпроса :) Би било 10/4 за цена за държава A на модел 1! Актуализирах рамката с данни на публикацията, за да е по-ясна! - person XYZ_2635; 25.02.2021