【问题标题】:Vectorization Pandas DataFrame矢量化 Pandas DataFrame
【发布时间】:2023-03-20 12:05:01
【问题描述】:

假设以下简化框架:

我有一个由 100 行、4 个类和每个实例的 4 个特征组成的参数的 3D Pandas 数据框:

iterables = [list(range(100)), [0,1,2,3]]
index = pd.MultiIndex.from_product(iterables, names=['instances', 'classes'])
columns = ['a', 'b', 'c', 'd']
np.random.seed(42)
parameters = pd.DataFrame(np.random.randint(1, 2000, size=(len(index), len(columns))), index=index, columns=columns)

parameters

instances classes   a     b     c     d                     
0         0        1127  1460   861  1295
          1        1131  1096  1725  1045
          2        1639   122   467  1239
          3         331  1483    88  1397
1         0        1124   872  1688   131
...                 ...   ...   ...   ...
98        3        1321  1750   779  1431
99        0        1793   814  1637  1429
          1        1370  1646   420  1206
          2         983   825  1025  1855
          3        1974   567   371   936

df 成为一个数据框,为每个实例和每个特征(列)报告观察到的类。

np.random.seed(42)
df = pd.DataFrame(np.random.randint(0, 3, size=(100, len(columns))), index=list(range(100)), 
                  columns=columns)
    a  b  c  d
0   2  0  2  2
1   0  0  2  1
2   2  2  2  2
3   0  2  1  0
4   1  1  1  1
.. .. .. .. ..
95  1  2  0  1
96  2  1  2  1
97  0  0  1  2
98  0  0  0  1
99  1  2  2  2

我想根据数据框 df 上观察到的类创建第三个形状为 (100, 4) 的数据框(我们称之为 new_df),其中包含数据框 parameters 中的参数。

例如,在df的第一行第一列(a)我观察到类2,所以我感兴趣的值是parameters数据框的第一个实例中的第二个类,即1127 将填充new df 的第一行和第一列。按照这种方法,“b”列的第一个观察是0类,所以在第一行,new_df的b列我想观察1460等等。

使用 for 循环我可以获得想要的结果:

new_df = pd.DataFrame(0, index=list(range(100)), columns=columns) # initialize the df
for i in range(len(df)):
    for c in df.columns:
        new_df.iloc[i][c] = parameters.loc[i][c][df.iloc[i][c]]

new_df

    a     b      c    d
0   1639  1460   467  1239
1   1124   872   806   344
2   1083   511  1706  1500
3    958  1155  1268   563
4     14   242   777  1370
..   ...   ...   ...   ...
95  1435  1316  1709   755
96   346   712   363   815
97  1234   985   683  1348
98   127  1130  1009  1014
99  1370   825  1025  1855

但是,原始数据集包含数百万行和数百列,继续进行 for 循环是不可行的。

有没有办法对这样的问题进行矢量化以避免 for 循环? (至少超过 1 个维度)

【问题讨论】:

    标签: python pandas for-loop vectorization


    【解决方案1】:

    使用stack 将两个DataFrame 重新整形为长格式,然后使用unstack 执行合并和整形,恢复为宽格式。有一堆重命名,以便我们可以引用和对齐合并中的列。

    (df.rename_axis(index='instances', columns='cols').stack().to_frame('classes')
       .merge(parameters.rename_axis(columns='cols').stack().rename('vals'),
              on=['instances', 'classes', 'cols'])
       .unstack(-1)['vals']
       .rename_axis(index=None, columns=None)
    )
    

           a     b     c     d
    0   1639  1460   467  1239
    1   1124   872   806   344
    2   1083   511  1706  1500
    3    958  1155  1268   563
    4     14   242   777  1370
    ..   ...   ...   ...   ...
    95  1435  1316  1709   755
    96   346   712   363   815
    97  1234   985   683  1348
    98   127  1130  1009  1014
    99  1370   825  1025  1855
    

    【讨论】:

    • 非常感谢您详尽的回答!
    猜你喜欢
    • 1970-01-01
    • 2015-01-02
    • 2021-01-18
    • 2017-09-26
    • 2021-02-07
    • 2021-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多