векторизация панд df по строке с несколькими условными выражениями - PullRequest
0 голосов
/ 06 июня 2019

Я стараюсь избегать циклов, применяющих функцию для каждой строки панды 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.

Любая помощь в указании меня в правильном направлении будет высоко ценится.

Спасибо.

UPDATE: Мне удалось немного увеличить скорость, заменив раздел df.iterrows на df.apply.

df['points'] = df.apply(lambda row: point_calc(row), axis=1)

UPDATE2: Я обновил функцию следующим образом и существенно уменьшил время выполнения с увеличением скорости в 10 раз по сравнению с использованием df.apply и начальной функции.

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 для самой функции, чтобы посмотреть, можно ли ее улучшить.

1 Ответ

1 голос
/ 06 июня 2019

Вы можете попробовать это следующим образом:

# 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

Решает ли это вашу проблему?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...