使用多个条件语句逐行向量化 pandas df

vectoring pandas df by row with multiple conditional statements

我试图避免循环在 pandas df 的每行基础上应用一个函数。我看过很多矢量化示例,但还没有遇到任何可以完全工作的东西。最终,我试图添加一个额外的 df 列,其中包含成功条件的总和,每个条件按行指定一个值。

我看过 np.apply_along_axis 但这只是一个隐藏循环,np.where 但我看不到它在我正在检查的 25 个条件下有效

              A         B         C  ...         R         S         T
0  0.279610  0.307119  0.553411  ...  0.897890  0.757151  0.735718
1  0.718537  0.974766  0.040607  ...  0.470836  0.103732  0.322093
2  0.222187  0.130348  0.894208  ...  0.480049  0.348090  0.844101
3  0.834743  0.473529  0.031600  ...  0.049258  0.594022  0.562006
4  0.087919  0.044066  0.936441  ...  0.259909  0.979909  0.403292

[5 rows x 20 columns]

def point_calc(row):
    points = 0
    if row[2] >= row[13]:
        points += 1
    if row[2] < 0:
        points -= 3
    if row[4] >= row[8]:
        points += 2
    if row[4] < row[12]:
        points += 1
    if row[16] == row[18]:
        points += 4
    return points

points_list = []
for indx, row in df.iterrows():
    value = point_calc(row)
    points_list.append(value)

df['points'] = points_list

这显然效率不高,但我不确定如何向量化我的代码,因为它需要 df 中每一列的每行值来获得条件的自定义总和。

如能为我指明正确的方向,我们将不胜感激。

谢谢。

更新: 我可以用 df.apply.

替换 df.iterrows 部分来获得更快的速度
df['points'] = df.apply(lambda row: point_calc(row), axis=1)

更新 2: 我按如下方式更新了函数,并大大减少了 运行 时间,使用 df.apply 和初始函数的速度提高了 10 倍。

def point_calc(row):
    a1 = np.where(row[:,2]) >= row[:,13], 1,0)
    a2 = np.where(row[:,2] < 0, -3, 0) 
    a3 = np.where(row[:,4] >= row[:,8])
    etc.
    all_points = a1 + a2 + a3 + etc.
    return all_points

df['points'] = point_calc(df.to_numpy())

我仍在努力的是在函数本身上使用 np.vectorize 以查看是否也可以对其进行改进。

您可以通过以下方式尝试:

# this is a small version of your dataframe
df = pd.DataFrame(np.random.random((10,4)), columns=list('ABCD'))

看起来是这样的:

    A           B           C           D
0   0.724198    0.444924    0.554168    0.368286
1   0.512431    0.633557    0.571369    0.812635
2   0.680520    0.666035    0.946170    0.652588
3   0.467660    0.277428    0.964336    0.751566
4   0.762783    0.685524    0.294148    0.515455
5   0.588832    0.276401    0.336392    0.997571
6   0.652105    0.072181    0.426501    0.755760
7   0.238815    0.620558    0.309208    0.427332
8   0.740555    0.566231    0.114300    0.353880
9   0.664978    0.711948    0.929396    0.014719

您可以创建一个系列来计算您的分数并用零初始化:

points = pd.Series(0, index=df.index)

看起来是这样的:

0    0
1    0
2    0
3    0
4    0
5    0
6    0
7    0
8    0
9    0
dtype: int64

之后您可以根据需要逐行添加和减去值: 括号内的条件选择条件为真的行。 因此 -=+= 仅应用于那些行。

points.loc[df.A < df.C] += 1
points.loc[df.B <    0] -= 3

最后,如果需要,您可以将系列的值提取为 numpy 数组(可选):

point_list = points.values

这是否解决了您的问题?