向量化 for 循环

Vectorizing for-loop

我有一个非常大的数据框(~10^8 行),我需要在其中更改一些值。我使用的算法很复杂,所以我试图将问题分解为下面的一个简单示例。我主要用 C++ 编程,所以我一直在思考 for 循环。我知道我应该矢量化,但我是 python 的新手,也是 pandas 的新手,无法提出更好的解决方案。欢迎任何提高性能的解决方案。

#!/usr/bin/python3


import numpy as np
import pandas as pd

data = {'eventID': [1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 6, 7, 8],
        'types':    [0, -1, -1, -1, 1, 0, 0, 0, -1, -1, -1, 1, -1, -1]
        }


mydf = pd.DataFrame(data, columns=['eventID', 'types'])
print(mydf)

MyIntegerCodes = np.array([0, 1])
eventIDs = np.unique(mydf.eventID.values)  # can be up to 10^8 values

for val in eventIDs:

    currentTypes = mydf[mydf.eventID == val].types.values

    if (0 in currentTypes) & ~(1 in currentTypes):
        mydf.loc[mydf.eventID == val, 'types'] = 0

    if ~(0 in currentTypes) & (1 in currentTypes):
        mydf.loc[mydf.eventID == val, 'types'] = 1


print(mydf)

有什么想法吗?

编辑:我被要求解释我用 for 循环做了什么。 对于每个 eventID,我想知道所有对应类型是否包含 1 或 0 或两者。如果它们包含 1,则所有等于 -1 的值都应更改为 1。如果值为 0,则所有等于 -1 的值都应更改为 0。我的问题是独立地为每个 eventID 有效地执行此操作。每个 eventID 可以有一个或多个条目。

示例输入:

    eventID  types
0         1      0
1         1     -1
2         1     -1
3         2     -1
4         2      1
5         3      0
6         4      0
7         5      0
8         6     -1
9         6     -1
10        6     -1
11        6      1
12        7     -1
13        8     -1

示例输出:

    eventID  types
0         1      0
1         1      0
2         1      0
3         2      1
4         2      1
5         3      0
6         4      0
7         5      0
8         6      1
9         6      1
10        6      1
11        6      1
12        7     -1
13        8     -1

首先我们使用 Series.eq then use DataFrame.groupby on this mask and transform using any, then using np.select 创建布尔掩码 m1m2 根据条件 m1 or m2:[=21= 从 1, 0 选择元素]

m1 = mydf['types'].eq(1).groupby(mydf['eventID']).transform('any')
m2 = mydf['types'].eq(0).groupby(mydf['eventID']).transform('any')
mydf['types'] = np.select([m1 , m2], [1, 0], mydf['types'])

结果:

# print(mydf)

    eventID  types
0         1      0
1         1      0
2         1      0
3         2      1
4         2      1
5         3      0
6         4      0
7         5      0
8         6      1
9         6      1
10        6      1
11        6      1
12        7     -1
13        8     -1