Оптимизация данной операции, есть ли лучший способ?

#python #pandas #numpy #optimization #vectorization

#python #панды #numpy #оптимизация #векторизация

Вопрос:

Я новичок, и мне нужно некоторое понимание. Допустим, у меня есть фрейм данных pandas следующим образом:

 temp = pd.DataFrame()
temp['A'] = np.random.rand(100)
temp['B'] = np.random.rand(100)
temp['C'] = np.random.rand(100)
  

Мне нужно написать функцию, в которой я заменяю каждое значение в столбце «C» на 0, если значение «A» больше 0,5 в соответствующей строке. В противном случае мне нужно умножить A и B в одной строке по элементам и записать результат в соответствующей строке столбца «C».

То, что я сделал до сих пор, это:

 A=temp.loc[temp['A']<0.5, 'A'].values
B=temp.loc[temp['A']<0.5, 'B'].values
temp['C'] = 0
temp.loc[temp['A']<0.5,'C']=A*B
  

Это работает так, как я хочу, чтобы это работало, ОДНАКО я не уверен, есть ли более быстрый способ реализовать это. Я очень скептически настроен, особенно в разрезах, которые, как мне кажется, в изобилии используют эти многочисленные фрагменты. Тем не менее, я не смог найти никаких других решений, поскольку мне нужно писать 0 для строк C, где A больше 0,5.

Или, есть ли способ нарезать только ту часть, которая необходима, выполнить вычисления, а затем каким-то образом запомнить индексы, чтобы вы могли вернуть требуемые значения в исходный фрейм данных в соответствующих строках?

Ответ №1:

Один из способов использования numpy.where :

 temp["C"] = np.where(temp["A"]<0.5, temp["A"] * temp["B"], 0)
  

Бенчмарк (примерно в 4 раза быстрее в выборке и продолжает увеличиваться):

 # With given sample of 100 rows

%%timeit
A=temp.loc[temp['A']<0.5, 'A'].values
B=temp.loc[temp['A']<0.5, 'B'].values
temp['C'] = 0
temp.loc[temp['A']<0.5,'C']=A*B

# 819 µs ± 2.77 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit np.where(temp["A"]<0.5, temp["A"] * temp["B"], 0)

# 174 µs ± 455 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
  

Тест на больших данных (примерно в 7 раз быстрее)

 temp = pd.DataFrame()
temp['A'] = np.random.rand(1000000)
temp['B'] = np.random.rand(1000000)
temp['C'] = np.random.rand(1000000)

%%timeit
A=temp.loc[temp['A']<0.5, 'A'].values
B=temp.loc[temp['A']<0.5, 'B'].values
temp['C'] = 0
temp.loc[temp['A']<0.5,'C']=A*B

# 35.2 ms ± 345 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit np.where(temp["A"]<0.5, temp["A"] * temp["B"], 0)

# 5.16 ms ± 188 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
  

Проверка

 A=temp.loc[temp['A']<0.5, 'A'].values
B=temp.loc[temp['A']<0.5, 'B'].values
temp['C'] = 0
temp.loc[temp['A']<0.5,'C']=A*B
np.array_equal(temp["C"], np.where(temp["A"]<0.5, temp["A"] * temp["B"], 0))
# True
  

Комментарии:

1. Чрезвычайно полезно! Однако один крошечный вопрос: относится ли np.where к категории «векторизованных» операций?

2. @rocketsfallonrocketfalls Да, это так 😉