Функция R expand.grid() в Python

Есть ли функция Python, аналогичная функции expand.grid() в R? Спасибо заранее.

(EDIT) Ниже приведено описание этой функции R и примера.

Create a Data Frame from All Combinations of Factors

Description:

     Create a data frame from all combinations of the supplied vectors
     or factors.  

> x <- 1:3
> y <- 1:3
> expand.grid(x,y)
  Var1 Var2
1    1    1
2    2    1
3    3    1
4    1    2
5    2    2
6    3    2
7    1    3
8    2    3
9    3    3

(EDIT2) Ниже приведен пример с пакетом rpy. Я хотел бы получить один и тот же выходной объект, но без использования R:

>>> from rpy import *
>>> a = [1,2,3]
>>> b = [5,7,9]
>>> r.assign("a",a)
[1, 2, 3]
>>> r.assign("b",b)
[5, 7, 9]
>>> r("expand.grid(a,b)")
{'Var1': [1, 2, 3, 1, 2, 3, 1, 2, 3], 'Var2': [5, 5, 5, 7, 7, 7, 9, 9, 9]}

EDIT 02/09/2012: Я действительно потерялся с Python. Лев Левицкий, приведенный в его ответе, не работает для меня:

>>> a = [1,2,3]
>>> b = [5,7,9]
>>> expandgrid(a, b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in expandgrid
NameError: global name 'itertools' is not defined

Однако модуль itertools, кажется, установлен (ввод from itertools import * не возвращает сообщение об ошибке)

Ответы

Ответ 1

Вот пример, который дает результат, похожий на то, что вам нужно:

import itertools
def expandgrid(*itrs):
   product = list(itertools.product(*itrs))
   return {'Var{}'.format(i+1):[x[i] for x in product] for i in range(len(itrs))}

>>> a = [1,2,3]
>>> b = [5,7,9]
>>> expandgrid(a, b)
{'Var1': [1, 1, 1, 2, 2, 2, 3, 3, 3], 'Var2': [5, 7, 9, 5, 7, 9, 5, 7, 9]}

Разница связана с тем, что в itertools.product самый правый элемент продвигается на каждой итерации. Вы можете настроить функцию, отсортировав список product, если это важно.

Ответ 2

Просто используйте списки:

>>> [(x, y) for x in range(5) for y in range(5)]

[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)]

конвертировать в массив numpy при желании:

>>> import numpy as np
>>> x = np.array([(x, y) for x in range(5) for y in range(5)])
>>> x.shape
(25, 2)

Я тестировал до 10000 x 10000, а производительность python сравнима с производительностью expand.grid в R. Использование кортежа (x, y) примерно на 40% быстрее, чем использование списка [x, y] в понимание.

ИЛИ...

Примерно в 3 раза быстрее, чем np.meshgrid, и значительно меньше памяти.

%timeit np.array(np.meshgrid(range(10000), range(10000))).reshape(2, 100000000).T
1 loops, best of 3: 736 ms per loop

в R:

> system.time(expand.grid(1:10000, 1:10000))
   user  system elapsed 
  1.991   0.416   2.424 

Имейте в виду, что R имеет 1 базируемый массив, тогда как Python основан на 0.

Ответ 3

product от itertools является ключом к вашему решению. Он производит декартовую продукцию входов.

from itertools import product

def expand_grid(dictionary):
   return pd.DataFrame([row for row in product(*dictionary.values())], 
                       columns=dictionary.keys())

dictionary = {'color': ['red', 'green', 'blue'], 
              'vehicle': ['car', 'van', 'truck'], 
              'cylinders': [6, 8]}

>>> expand_grid(dictionary)
    color  cylinders vehicle
0     red          6     car
1     red          6     van
2     red          6   truck
3     red          8     car
4     red          8     van
5     red          8   truck
6   green          6     car
7   green          6     van
8   green          6   truck
9   green          8     car
10  green          8     van
11  green          8   truck
12   blue          6     car
13   blue          6     van
14   blue          6   truck
15   blue          8     car
16   blue          8     van
17   blue          8   truck

Ответ 4

Я задавался этим вопросом некоторое время, и я до сих пор не удовлетворен решениями, поэтому я придумал свой собственный, который значительно проще (но, вероятно, медленнее). Функция использует numpy.meshgrid для создания сетки, затем выравнивает сетки в 1d массивы и складывает их:

def expand_grid(x, y):
    xG, yG = np.meshgrid(x, y) # create the actual grid
    xG = xG.flatten() # make the grid 1d
    yG = yG.flatten() # same
    return pd.DataFrame({'x':xG, 'y':yG}) # return a dataframe

Например:

import numpy as np
import pandas as pd

p, q = np.linspace(1, 10, 10), np.linspace(1, 10, 10)

def expand_grid(x, y):
    xG, yG = np.meshgrid(x, y) # create the actual grid
    xG = xG.flatten() # make the grid 1d
    yG = yG.flatten() # same
    return pd.DataFrame({'x':xG, 'y':yG})

print expand_grid(p, q).head(n = 20)

Я знаю, что это старый пост, но я решил поделиться своей простой версией!

Ответ 5

pandas документация определяет функцию expand_grid:

def expand_grid(data_dict):
    """Create a dataframe from every combination of given values."""
    rows = itertools.product(*data_dict.values())
    return pd.DataFrame.from_records(rows, columns=data_dict.keys())

Для этого кода вам понадобятся следующие два импорта:

import itertools
import pandas as pd

Вывод представляет собой pandas.DataFrame, который является наиболее сопоставимым объектом в Python для R data.frame.

Ответ 6

Здесь другая версия, которая возвращает pandas.DataFrame:

import itertools as it
import pandas as pd

def expand_grid(*args, **kwargs):
    columns = []
    lst = []
    if args:
        columns += xrange(len(args))
        lst += args
    if kwargs:
        columns += kwargs.iterkeys()
        lst += kwargs.itervalues()
    return pd.DataFrame(list(it.product(*lst)), columns=columns)

print expand_grid([0,1], [1,2,3])
print expand_grid(a=[0,1], b=[1,2,3])
print expand_grid([0,1], b=[1,2,3])

Ответ 7

Вы пробовали product от itertools? На мой взгляд, это немного проще, чем некоторые из этих методов (за исключением pandas и meshgrid). Имейте в виду, что эта настройка фактически вытаскивает все элементы из итератора в список и затем преобразует его в ndarray, поэтому будьте осторожны с более высокими размерами или удалите np.asarray(list(combs)) для больших размерных сеток, если вы не хотите исчерпать память, вы можете обратиться к итератору за конкретными комбинациями. Я настоятельно рекомендую meshgrid для этого:

#Generate square grid from axis
from itertools import product
import numpy as np
a=np.array(list(range(3)))+1 # axis with offset for 0 base index to 1
points=product(a,repeat=2) #only allow repeats for (i,j), (j,i) pairs with i!=j
np.asarray(list(points))   #convert to ndarray

И я получаю следующий вывод из этого:

array([[1, 1],
   [1, 2],
   [1, 3],
   [2, 1],
   [2, 2],
   [2, 3],
   [3, 1],
   [3, 2],
   [3, 3]])