Как передать большое количество столбцов данных в numpy векторизация в качестве аргумента - PullRequest
0 голосов
/ 27 марта 2020

У меня есть кадр данных с ровно 31 столбцом и, например, 100 строками.

Мне нужно создать список из 100 словарей, значения которых обрабатываются из разных 31 столбцов.

В настоящее время я использую функцию apply() для этого:

my_df.apply(lambda row: _build_data(row, param1, param2, param3), axis=1)

Но теперь я хочу изучить возможности numpy vectorize(). Проблема в том, что из того, что я читаю, я должен передать каждый столбец в качестве отдельного аргумента:

np.vectorize(_build_data)(my_df[col1], my_df[col2], ..., my_df[col31], param1, param2, param3)

Это не выглядит как pythoni c, и при этом я не хочу определять функция с 34 аргументами.

Знаете ли вы, есть ли другой способ сделать это?

Большое спасибо за помощь!

Ответы [ 2 ]

0 голосов
/ 27 марта 2020

Я подозреваю, что вы пытались использовать np.vectorize, потому что вы прочитали, что numpy 'векторизация' - это способ ускорения pandas кода.

In [29]: df = pd.DataFrame(np.arange(12).reshape(4,3), columns=['A','B','C'])                  
In [30]: df                                                                                    
Out[30]: 
   A   B   C
0  0   1   2
1  3   4   5
2  6   7   8
3  9  10  11

Медленный построчно, Подход к получению строки означает:

In [31]: df.apply(lambda row: np.mean(row), axis=1)                                            
Out[31]: 
0     1.0
1     4.0
2     7.0
3    10.0
dtype: float64

Быстрый numpy метод:

In [32]: df.to_numpy()                                                                         
Out[32]: 
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])
In [33]: df.to_numpy().mean(axis=1)                                                            
Out[33]: array([ 1.,  4.,  7., 10.])

То есть мы получаем массив значений данных и используем метод быстрой компиляции рассчитать рядные средства.

Но чтобы сделать что-то похожее на словарь для каждой строки:

In [35]: df.apply(lambda row: {str(k):k for k in row}, axis=1)                                 
Out[35]: 
0        {'0': 0, '1': 1, '2': 2}
1        {'3': 3, '4': 4, '5': 5}
2        {'6': 6, '7': 7, '8': 8}
3    {'9': 9, '10': 10, '11': 11}
dtype: object

Мы должны выполнять итерации по строкам массива, как мы делаем с фреймом данных apply:

In [36]: [{str(k):k for k in row} for row in df.to_numpy()]                                    
Out[36]: 
[{'0': 0, '1': 1, '2': 2},
 {'3': 3, '4': 4, '5': 5},
 {'6': 6, '7': 7, '8': 8},
 {'9': 9, '10': 10, '11': 11}]

Подход к массиву быстрее:

In [37]: timeit df.apply(lambda row: {str(k):k for k in row}, axis=1)                          
1.13 ms ± 702 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [38]: timeit [{str(k):k for k in row} for row in df.to_numpy()]                             
40.8 µs ± 157 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Но метод apply возвращает кадр данных, а не список. Я подозреваю, что большая часть дополнительного времени находится на этом шаге.

np.vectorizenp.frompyfunc) также может использоваться для итерации массива, но по умолчанию используется итерация по элементам, а не по строкам или столбцам , Как правило, они медленнее, чем более явная итерация (как я делаю в [36]).

Неуклюжий способ создания кадра данных из списка:

In [53]: %%timeit 
    ...: df1 = pd.DataFrame(['one','two','three','four'],columns=['d'])   
    ...: df1['d'] =[{str(k):k for k in row} for row in df.to_numpy()]                                                                                       
572 µs ± 18.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
0 голосов
/ 27 марта 2020

Как вы можете прочитать из np.vectorize : , функция векторизации предоставляется в первую очередь для удобства, а не для производительности. Реализация по сути для l oop.

Поэтому, как уже сказал hpaulj, он не ускорит ваш код

Однако, если вы все равно захотите его использовать, Вам не нужно вводить все свои столбцы, просто используйте понимание списка:

np.vectorize(_build_data)([my_df[c] for c in list(my_df)], param1, param2, param3)
...