Добавить массив в цикл - PullRequest
1 голос
/ 07 апреля 2019

У меня есть фрейм данных с 1000 строк и 1000 столбцов. Я пытаюсь сгенерировать пустой массив из этого фрейма данных, используя цикл for, я использую цикл for для случайного выбора 5 столбцов за цикл. Мне нужно добавить или объединить каждый массив (1000 строк и 5 столбцов), которые я генерирую за цикл. Однако видно, что невозможно создать пустой массив без указания сначала размеров.

Я пробовал следующий код:

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. цикл.

Ответы [ 3 ]

4 голосов
/ 07 апреля 2019

Добавить в список всегда лучше, чем 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).1d и 2d, отсюда и жалоба на размеры.

Начиная с массива 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 массива.Плюс повторяющиеся объединения происходят медленно, каждый раз создавая совершенно новый массив.

1 голос
/ 07 апреля 2019

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)
0 голосов
/ 07 апреля 2019

Предлагаемое решение

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

На моем компьютере это небольшое улучшение уменьшило время вычислений с 164 мс до 107 мс (значения выбираются из быстрого исполнения каждой версии). Конечно, это не так важно, но я думаю, что это полезно знать:)

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