R développez.grille en fonction de() en Python

Existe-t-il une fonction Python similaire à l'expansion.grille() dans R ? Merci à l'avance.

(EDIT) Voici la description de cette fonction R et un exemple.

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) voici un exemple avec le paquet rpy. Je voudrais obtenir le même objet de sortie mais sans utiliser 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: je suis vraiment perdu avec Python. Le code de Lev Levitsky donné dans sa réponse ne fonctionne pas pour moi:

>>> 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

Cependant le module itertools semble être installé (taper from itertools import * ne renvoie aucun message d'erreur)

25
demandé sur Stéphane Laurent 2012-08-26 18:24:14

7 réponses

Voici un exemple qui donne une sortie similaire à ce dont vous avez besoin:

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]}

La différence est liée au fait que dans itertools.product l'élément le plus à droite avance à chaque itération . Vous pouvez modifier la fonction en triant intelligemment la liste product si c'est important.

12
répondu Lev Levitsky 2012-09-02 08:29:37

Utilisez simplement les compréhensions de liste:

>>> [(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)]

Convertir en tableau numpy si désiré:

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

J'ai testé jusqu'à 10000 x 10000 et les performances de python sont comparables à celles de expand.grille en R. L'utilisation d'un tuple (x, y) est environ 40% plus rapide que l'utilisation d'une liste [x, y] dans la compréhension.

OU...

Environ 3 fois plus rapide avec np.meshgrid et beaucoup moins de mémoire intensive.

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

Dans R:

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

Gardez à l'esprit que R a des tableaux basés sur 1 alors que Python est basé sur 0.

18
répondu Thomas Browne 2015-09-11 08:43:06

product à partir de itertools est la clé de votre solution. Il produit un produit cartésien des entrées.

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
14
répondu Alexander 2015-09-13 12:55:47

Je me suis demandé cela pendant un moment et je n'ai pas été satisfait des solutions proposées jusqu'à présent, alors j'ai trouvé la mienne, ce qui est beaucoup plus simple (mais probablement plus lent). La fonction utilise numpy.meshgrid pour faire la grille, puis aplatit les grilles en tableaux 1d et les met ensemble:

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

Par exemple:

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)

Je sais que c'est un vieux post, mais je pensais partager ma version simple!

10
répondu Nate 2014-01-16 05:44:02

La documentation pandas définit une fonction 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())

Pour que ce code fonctionne, vous aurez besoin des deux importations suivantes:

import itertools
import pandas as pd

La sortie est un pandas.DataFrame qui est l'objet le plus comparable en Python à un R data.frame.

5
répondu Daniel Himmelstein 2016-09-17 20:43:53

Voici une autre version qui renvoie un 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])
3
répondu snth 2013-02-14 12:28:34

Avez-vous essayé product de itertools? Un peu plus simple à utiliser que certaines de ces méthodes, à mon avis (à l'exception de pandas et meshgrid). Gardez à l'esprit que cette configuration tire réellement tous les éléments de l'itérateur dans une liste, puis la convertit en ndarray alors soyez prudent avec des dimensions plus élevées ou supprimez np.asarray(list(combs)) pour les grilles de dimensions plus élevées sauf si vous voulez manquer de mémoire, vous pouvez alors vous référer à l'itérateur pour des combinaisons spécifiques. Je recommande fortement meshgrid pour cela bien que:

#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

Et j'obtiens la sortie suivante de ceci:

array([[1, 1],
   [1, 2],
   [1, 3],
   [2, 1],
   [2, 2],
   [2, 3],
   [3, 1],
   [3, 2],
   [3, 3]])
0
répondu ThisGuyCantEven 2017-06-07 02:13:27