Python 数据帧的矢量化
假设以下简化框架: 我有一个由100行、4个类和每个实例的4个特征组成的参数的3D数据帧:Python 数据帧的矢量化,python,pandas,for-loop,vectorization,Python,Pandas,For Loop,Vectorization,假设以下简化框架: 我有一个由100行、4个类和每个实例的4个特征组成的参数的3D数据帧: 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.rando
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
我想创建第三个数据框(我们称之为new_df
),形状为(100,4),包含数据框参数中的参数,基于数据框df
上观察到的类
例如,在第一列(a)的df的第一行中,我观察到类2,因此我感兴趣的值是参数的第一个实例中的第二个类,即1127,它将填充新df的第一行和列。按照这种方法,列“b”的第一个观察值是0级,因此在第一行中,新_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维)使用stack
将两个数据帧重塑为长格式,然后使用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