将列中的行类别除以相同类别但日期不同的值

2024-09-26 22:54:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我的数据集有数百万行,大约400个类别。每个类别包含2019年、2020年和2021年的每周数据。我试图通过将列的周值除以2019年对应的周值来规范化列值。该列包含来自不同类别的数据

示例数据如下:

sample data/m25c4.png

我希望得到如下输出: sample output

我试着使用python来实现这一点,但运行起来需要几个小时。 我的代码是这样的

for category, weeks in category_weeks_dict.items():
    for week in weeks:
        y = df.query("category== @category and Year==2019 and week==@week['value'].values
        if not y: y=np.nan
        df.loc[(df['category']==category) & (df['week']==week), 'value'] = y

代码基本上会创建一个新列,并为每个类别和周指定2019值。这样我就可以将value列除以2019 value列。 因此,我创建了一个包含每个类别及其唯一周的dict{a:[1,2,3,4],B:[1,2,3,4]…}。然后得到y,这是每个类别和每周的2019值

有没有更好的方法可以让我用熊猫来做这件事。我真的很感谢你的帮助。谢谢


Tags: and数据sample代码indfforvalue
1条回答
网友
1楼 · 发布于 2024-09-26 22:54:38

如果所有年份的类别和周数相同

如果dataframe按照示例中的顺序进行排序,使得周数和类别的数量和顺序每年都完全重复,那么您可以对计算进行矢量化,这应该会快得多

使用^{}创建一个数组,该数组包含2019年的值,重复次数与年份相同(样本数据中为2次),因此该数组的长度与整个数据帧的长度相同。然后,您可以通过将values列除以该数组来计算规范化值,这将按元素进行

import numpy as np
import pandas as pd

df = pd.DataFrame({'category': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B',
                                'C', 'C', 'C', 'C', 'A', 'A', 'A', 'A', 
                                'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C'],
                   'year': [2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019,
                            2019, 2019, 2019, 2019, 2020, 2020, 2020, 2020,
                            2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020],
                   'val': [100, 200, 300, 400, 300, 200, 500, 700,
                           450, 550, 650, 200, 100, 100, 100, 100,
                           100, 100, 100, 100, 100, 100, 100, 100],
                   'week': [1, 2, 3, 4, 1, 2, 3, 4, 
                            1, 2, 3, 4, 1, 2, 3, 4, 
                            1, 2, 3, 4, 1, 2, 3, 4]})

val_2019 = np.tile(df.val[df.year == 2019], 2)
df['normalized'] = df.val / val_2019

df
    category  year  val     week  normalized
0   A         2019  100     1     1.000000
1   A         2019  200     2     1.000000
2   A         2019  300     3     1.000000
3   A         2019  400     4     1.000000
4   B         2019  300     1     1.000000
5   B         2019  200     2     1.000000
6   B         2019  500     3     1.000000
7   B         2019  700     4     1.000000
8   C         2019  450     1     1.000000
9   C         2019  550     2     1.000000
10  C         2019  650     3     1.000000
11  C         2019  200     4     1.000000
12  A         2020  100     1     1.000000
13  A         2020  100     2     0.500000
14  A         2020  100     3     0.333333
15  A         2020  100     4     0.250000
16  B         2020  100     1     0.333333
17  B         2020  100     2     0.500000
18  B         2020  100     3     0.200000
19  B         2020  100     4     0.142857
20  C         2020  100     1     0.222222
21  C         2020  100     2     0.181818
22  C         2020  100     3     0.153846
23  C         2020  100     4     0.500000

注意,为了避免错误,我重命名了values列,因为df.values是一个数据帧属性,包含所有列的值

如果年份可能有不同的类别和周

我已经更改了下面的示例数据来说明这个案例。 无论如何,要使矢量化方法起作用,您必须为每年调整相同的类别和周数。这可以通过将数据帧转换为宽格式来实现:

df = pd.DataFrame({'category': ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C', 
                                'A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C',
                                'A', 'A', 'B', 'B', 'C'],
                   'year': [2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019,
                            2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020,
                            2021, 2021, 2021, 2021, 2021],
                   'val': [100, 200, 300, 400, 300, 200, 500, 700, 350,
                           200, 400, 600, 200, 300, 100, 100, 700, 700,
                           100, 200, 200, 600, 350],
                   'week': [1, 2, 3, 1, 2, 3, 1, 2, 3, 
                            1, 2, 3, 1, 2, 3, 1, 2, 3, 
                            1, 2, 1, 2, 1]})

df_wide = df.pivot(index='year', columns=['category', 'week'], values='val')
df_wide
category A                      B                       C
week     1      2       3       1       2       3       1       2       3
year                                    
2019     100.0  200.0   300.0   400.0   300.0   200.0   500.0   700.0   350.0
2020     200.0  400.0   600.0   200.0   300.0   100.0   100.0   700.0   700.0
2021     100.0  200.0   NaN     200.0   600.0   NaN     350.0   NaN     NaN

现在,您可以使用NumPy的广播规则将每个值除以相应的2019值:

df_norm = df_wide / df_wide.loc[2019]
df_norm
category A                      B                       C
week     1      2       3       1       2       3       1       2       3
year                                    
2019     1.0    1.0     1.0     1.0     1.0     1.0     1.0     1.0     1.0
2020     2.0    2.0     2.0     0.5     1.0     0.5     0.2     1.0     2.0
2021     1.0    1.0     NaN     0.5     2.0     NaN     0.7     NaN     NaN

相关问题 更多 >

    热门问题