#pandas #dataframe #numpy #series
Вопрос:
Я выполняю некоторые операции с фреймом данных Pandas. Для определенного столбца мне нужно преобразовать каждую ячейку в массив numpy, что не сложно. Конечная цель состоит в том, чтобы получить 2D-массив в результате всего столбца. Однако, когда я выполняю следующую операцию, я получаю массив 1D, а внутренние массивы не распознаются.
df = pd.DataFrame({'col': ['abc', 'def']})
mapping = {v: k for k, v in enumerate('abcdef')}
df['new'] = df['col'].apply(lambda x: list(x))
df['new'].apply(lambda x: np.array([mapping[i] for i in x])).values
Это дает:
array([array([0, 1, 2]), array([3, 4, 5])], dtype=object)
и форма (2,), что означает, что внутренние массивы не распознаются.
Если я это сделаю s.reshape(2,-1)
, то получу (2,1)
вместо (2,3)
этого форму.
Ценю любую помощь!
Осветление:
Вышесказанное-всего лишь игрушечный пример. То, что я делал, было предварительной обработкой для машинного обучения с использованием набора данных IMDB. Мне пришлось преобразовать каждое значение в столбце обзора в встраивание слов, которое представляет собой массив numpy. Теперь задача состоит в том, чтобы вывести все эти массивы в виде 2D-массива, чтобы я мог использовать их в своей модели машинного обучения.
Комментарии:
1.
np.array(df['new'].values.tolist())
илиnp.stack(df['new'])
2. @user3483203
tolist()
будет означать, что это больше не массив3. @роганджош не уверен, что ты имеешь в виду. Если вы опустите
tolist
это , вы получите массив объекта типа с формой(2,)
4. @user3483203 но все равно массив numpy, который вы можете попробовать (если в подходящем состоянии) преобразовать в тип.
tolist()
отбрасывает его в список python, который вы просто собираетесь преобразовать обратно в массив? Вы могли бы просто оставить его на.values
? Или я что-то упускаю5. @George вы ищете вложенный массив в ячейке панды?
Ответ №1:
Я думаю, что было бы лучше создать массив непосредственно из значений списка.
df
col new
0 abc [a, b, c]
1 def [d, e, f]
arr = np.array(df['new'].tolist())
arr
# array([['a', 'b', 'c'],
# ['d', 'e', 'f']], dtype='<U1')
arr.shape
# (2, 3)
Большой отказ от ответственности: Это будет работать только в том случае, если все подсписки содержат одинаковое количество элементов. Если нет, это будет означать, что они являются неровными массивами, и numpy не сможет использовать эффективный формат памяти для представления вашего массива (следовательно, dtype='object'
).
Комментарии:
1.
concatenate
(или одна из егоstack
дочерних структур) будет обрабатывать массив объектов 1d как список и попытается объединить подмассивы в один.2. @hpaulj Я предполагаю, что это будет намного медленнее, так
concatenate
как работает с массивом объектов, верно?3. Нам нужно сделать несколько таймингов 🙂
4. @hpaulj
np.stack(df[['new']].values, axis=1)
дает вам 2D массив формы (2,3)? Похоже, это не работает, для меня они остаются списками.5.
axis=0
это версия, которая воспроизводитсяnp.array
.
Ответ №2:
In [2]: import pandas as pd
In [3]: df = pd.DataFrame({'col': ['abc', 'def']})
...: mapping = {v: k for k, v in enumerate('abcdef')}
...: df['new'] = df['col'].apply(lambda x: list(x))
In [7]: df['new']
Out[7]:
0 [a, b, c]
1 [d, e, f]
Name: new, dtype: object
In [8]: df['new'].values
Out[8]: array([list(['a', 'b', 'c']), list(['d', 'e', 'f'])], dtype=object)
np.stack
ведет себя очень похоже np.array
на соединение элементов на новой начальной оси:
In [9]: np.stack(df['new'].values)
Out[9]:
array([['a', 'b', 'c'],
['d', 'e', 'f']], dtype='<U1')
или на другой оси вы выбираете:
In [10]: np.stack(df['new'].values, axis=1)
Out[10]:
array([['a', 'd'],
['b', 'e'],
['c', 'f']], dtype='<U1')
np.array
также работает, если массив объектов преобразован в список (как показывает @coldspeed):
In [11]: df['new'].values.tolist()
Out[11]: [['a', 'b', 'c'], ['d', 'e', 'f']]
In [12]: np.array(df['new'].values.tolist())
Out[12]:
array([['a', 'b', 'c'],
['d', 'e', 'f']], dtype='<U1')
Что касается скорости, давайте сделаем массив больше:
In [16]: arr = np.frompyfunc(lambda x: np.arange(1000),1,1)(np.arange(1000))
In [17]: arr.shape
Out[17]: (1000,)
In [18]: np.stack(arr).shape
Out[18]: (1000, 1000)
In [20]: np.array(arr.tolist()).shape
Out[20]: (1000, 1000)
In [21]: timeit np.stack(arr).shape
5.24 ms ± 190 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [22]: timeit np.array(arr.tolist()).shape
4.45 ms ± 138 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
В основном то же самое, с небольшим преимуществом в np.array
подходе.
stack
like vstack
расширяет размеры каждого элемента по мере необходимости. Пропустить это с concatenate
помощью a немного быстрее:
In [27]: timeit np.concatenate(arr).reshape(-1,1000).shape
4.04 ms ± 12.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Это arr
содержит массивы. Если бы вместо этого он содержал списки array(arr.tolist())
, подход работал бы лучше (относительно), поскольку у него есть только один список (списков) для преобразования в массив. stack
Подход должен сначала преобразовать каждый из подсписков в массивы.