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)
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.
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.
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
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!
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
.
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])
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]])