У меня есть фрейм данных с 1000 строк и 1000 столбцов. Я пытаюсь создать массив numpy из этого фрейма данных, используя цикл for, я использую цикл for для случайного выбора 5 столбцов за цикл. Мне нужно добавить или объединить каждый массив (1000 строк и 5 столбцов), который я генерирую за цикл. Однако видно, что невозможно создать массив numpy без указания сначала размеров.
Я пробовал следующий код:
import numpy as np
import pandas as pd
df = pd.DataFrame(np.random.choice([0.0, 0.05], size=(1000,1000)))
l = np.array([])
for i in range(0,100):
rand_cols = np.random.permutation(df.columns)[0:5]
df2 = df[rand_cols].copy()
l = np.append(l, df2, axis=0)
Однако я получаю следующую ошибку:
ValueError: all the input arrays must have same number of
dimensions
Этот код резюмирует то, что я делаю, однако, согласно этому примеру, результат, который мне нужен, — это массив из 1000 строк и 500 столбцов, который создается путем конкатенации каждого из массивов, которые я генерирую с каждым циклом for.
IIUC
l=[]
for i in range(0,100):
rand_cols = np.random.permutation(df.columns)[0:5]
df2 = df[rand_cols].copy()
l.append(df2.values)
a=np.concatenate(l,1)
a.shape
(1000, 500)
Добавление списка всегда лучше, чем np.append
. Это быстрее и проще в использовании.
Но давайте посмотрим на ваш код более подробно:
In [128]: df = pd.DataFrame(np.random.choice([0.0, 0.05], size=(1000,1000)))
In [129]: l = np.array([])
In [130]: rand_cols = np.random.permutation(df.columns)[0:5]
In [131]: rand_cols
Out[131]: array([190, 106, 618, 557, 514])
In [132]: df2 = df[rand_cols].copy()
In [133]: df2.shape
Out[133]: (1000, 5)
In [134]: l1 = np.append(l, df2, axis=0)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-134-64d82acc3963> in <module>
----> 1 l1 = np.append(l, df2, axis=0)
/usr/local/lib/python3.6/dist-packages/numpy/lib/function_base.py in append(arr, values, axis)
4692 values = ravel(values)
4693 axis = arr.ndim-1
-> 4694 return concatenate((arr, values), axis=axis)
4695
4696
ValueError: all the input arrays must have same number of dimensions
Поскольку вы указали ось, все, что делает np.append
, это:
np.concatenate([l, df2], axis=0)
l
это (0,) форма, df2
это (1000,5). 1д и 2д, отсюда и претензии к габаритам.
Начиная с 2d массива l
работает:
In [144]: l = np.zeros((0,5))
In [145]: np.concatenate([l, df2], axis=0).shape
Out[145]: (1000, 5)
In [146]: np.concatenate([df2, df2], axis=0).shape
Out[146]: (2000, 5)
Я думаю, что np.append
следует устареть. Мы видим слишком много ошибок SO. Как показывает ваш случай, сложно создать правильный исходный массив. np.array([])
работает только при построении массива 1d. Плюс повторные конкатенации медленные, каждый раз создавая совершенно новый массив.
Причина, по которой вы получаете эту ошибку, заключается в том, что вы пытаетесь добавить матрицу df2
формы (1000, 5) к матрице l
формы (0,) (только одно измерение). Проблема в том, что с numpy две объединенные матрицы должны совпадать по размерам, И все размеры, кроме того, к которому вы добавляете, должны быть выровнены, т. е. вы должны были инициализировать l
формой (0, 5).
Вот рабочая версия кода:
import numpy as np
import pandas as pd
df = pd.DataFrame(np.random.choice([0.0, 0.05], size=(1000,1000)))
l = np.empty(shape=(0, 5))
for _ in range(0,100):
rand_cols = np.random.permutation(df.columns)[0:5]
df2 = df[rand_cols]
l = np.append(l, df2, axis=0)
Теперь рекомендуется избегать добавления матриц внутри цикла, поскольку это неэффективно с точки зрения вычислений (на каждой итерации необходимо создавать новый массив numpy, что требует времени). Вам лучше добавить результат итерации цикла в стандартный список Python и дождаться окончания выполнения цикла, чтобы сложить все результаты вместе.
Вот код:
import numpy as np
import pandas as pd
df = pd.DataFrame(np.random.choice([0.0, 0.05], size=(1000,1000)))
df_list = []
for _ in range(0,100):
rand_cols = np.random.permutation(df.columns)[0:5]
df2 = df[rand_cols]
df_list += [df2]
l = np.vstack(df_list)
Здесь я использую numpy.vstack для конкатенации вдоль оси строки. Другие функции numpy с соответствующими параметрами дадут вам тот же результат. Обратите внимание, что нет необходимости преобразовывать кадры данных pandas в массивы numpy.
На моем компьютере это небольшое улучшение сократило время вычислений со 164 мс до 107 мс (значения взяты из быстрого выполнения каждой версии). Конечно, это не так важно здесь, но я думаю, что это полезно знать :)