Permutations with a sum constraint
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
I have made the following function that gives the combinations permuted of n elements with a constrain/rule. This consist on creating a dataframe with all combination of numbers from 0 to n that sums n.
Function
import pandas as pd
import itertools
import numpy as np
def combinations_permuted(n_elm):
items = list(range(0,n_elm+1,1))
combinations = pd.DataFrame(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.combinations_with_replacement(items, n_elm)))))
comb_permuted = pd.DataFrame()
for index, combination in combinations.iterrows():
comb_permuted=comb_permuted.append(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.permutations(combination.tolist(), n_elm)))))
return(comb_permuted.drop_duplicates().as_matrix())
Example
array([[0, 0, 3],
[0, 3, 0],
[3, 0, 0],
[0, 1, 2],
[0, 2, 1],
[1, 0, 2],
[1, 2, 0],
[2, 0, 1],
[2, 1, 0],
[1, 1, 1]], dtype=int64)
The problem is that is taking a long time when n_elm
is "big" for example 9. I think this code can be improving in terms of time performance.
Maybe by replacing the for
loop with a map
function.
Any help to get it?
python performance numpy combinatorics pandas
add a comment |Â
up vote
3
down vote
favorite
I have made the following function that gives the combinations permuted of n elements with a constrain/rule. This consist on creating a dataframe with all combination of numbers from 0 to n that sums n.
Function
import pandas as pd
import itertools
import numpy as np
def combinations_permuted(n_elm):
items = list(range(0,n_elm+1,1))
combinations = pd.DataFrame(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.combinations_with_replacement(items, n_elm)))))
comb_permuted = pd.DataFrame()
for index, combination in combinations.iterrows():
comb_permuted=comb_permuted.append(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.permutations(combination.tolist(), n_elm)))))
return(comb_permuted.drop_duplicates().as_matrix())
Example
array([[0, 0, 3],
[0, 3, 0],
[3, 0, 0],
[0, 1, 2],
[0, 2, 1],
[1, 0, 2],
[1, 2, 0],
[2, 0, 1],
[2, 1, 0],
[1, 1, 1]], dtype=int64)
The problem is that is taking a long time when n_elm
is "big" for example 9. I think this code can be improving in terms of time performance.
Maybe by replacing the for
loop with a map
function.
Any help to get it?
python performance numpy combinatorics pandas
What Python version are you targeting?
â Mast
Mar 21 at 13:41
try with stackoverflow.com/a/28969798/3308055
â juvian
Mar 21 at 14:32
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I have made the following function that gives the combinations permuted of n elements with a constrain/rule. This consist on creating a dataframe with all combination of numbers from 0 to n that sums n.
Function
import pandas as pd
import itertools
import numpy as np
def combinations_permuted(n_elm):
items = list(range(0,n_elm+1,1))
combinations = pd.DataFrame(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.combinations_with_replacement(items, n_elm)))))
comb_permuted = pd.DataFrame()
for index, combination in combinations.iterrows():
comb_permuted=comb_permuted.append(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.permutations(combination.tolist(), n_elm)))))
return(comb_permuted.drop_duplicates().as_matrix())
Example
array([[0, 0, 3],
[0, 3, 0],
[3, 0, 0],
[0, 1, 2],
[0, 2, 1],
[1, 0, 2],
[1, 2, 0],
[2, 0, 1],
[2, 1, 0],
[1, 1, 1]], dtype=int64)
The problem is that is taking a long time when n_elm
is "big" for example 9. I think this code can be improving in terms of time performance.
Maybe by replacing the for
loop with a map
function.
Any help to get it?
python performance numpy combinatorics pandas
I have made the following function that gives the combinations permuted of n elements with a constrain/rule. This consist on creating a dataframe with all combination of numbers from 0 to n that sums n.
Function
import pandas as pd
import itertools
import numpy as np
def combinations_permuted(n_elm):
items = list(range(0,n_elm+1,1))
combinations = pd.DataFrame(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.combinations_with_replacement(items, n_elm)))))
comb_permuted = pd.DataFrame()
for index, combination in combinations.iterrows():
comb_permuted=comb_permuted.append(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.permutations(combination.tolist(), n_elm)))))
return(comb_permuted.drop_duplicates().as_matrix())
Example
array([[0, 0, 3],
[0, 3, 0],
[3, 0, 0],
[0, 1, 2],
[0, 2, 1],
[1, 0, 2],
[1, 2, 0],
[2, 0, 1],
[2, 1, 0],
[1, 1, 1]], dtype=int64)
The problem is that is taking a long time when n_elm
is "big" for example 9. I think this code can be improving in terms of time performance.
Maybe by replacing the for
loop with a map
function.
Any help to get it?
python performance numpy combinatorics pandas
edited Mar 21 at 16:10
200_success
123k14142399
123k14142399
asked Mar 21 at 13:31
PeCaDe
1184
1184
What Python version are you targeting?
â Mast
Mar 21 at 13:41
try with stackoverflow.com/a/28969798/3308055
â juvian
Mar 21 at 14:32
add a comment |Â
What Python version are you targeting?
â Mast
Mar 21 at 13:41
try with stackoverflow.com/a/28969798/3308055
â juvian
Mar 21 at 14:32
What Python version are you targeting?
â Mast
Mar 21 at 13:41
What Python version are you targeting?
â Mast
Mar 21 at 13:41
try with stackoverflow.com/a/28969798/3308055
â juvian
Mar 21 at 14:32
try with stackoverflow.com/a/28969798/3308055
â juvian
Mar 21 at 14:32
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
def combinations_permuted(n_elm):
IMO n
(as used in the description of the code in the question) is more readable than n_elm
.
items = list(range(0,n_elm+1,1))
1
is the default step, and range
isn't so obscure a function that the maintenance programmer would wonder what range(0, n+1)
does.
combinations = pd.DataFrame(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.combinations_with_replacement(items, n_elm)))))
comb_permuted = pd.DataFrame()
for index, combination in combinations.iterrows():
comb_permuted=comb_permuted.append(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.permutations(combination.tolist(), n_elm)))))
return(comb_permuted.drop_duplicates().as_matrix())
There are two things here which sound warning bells:
comb_permuted=comb_permuted.append
. The documentation for DataFrame.append says
Iteratively appending rows to a DataFrame can be more computationally intensive than a single concatenate. A better solution is to append those rows to a list and then concatenate the list with the original DataFrame all at once.
drop_duplicates()
. That says that the generation process is doing more work that it needs to.
A KISS approach would be to replace the combinations_with_replacement
, permutations
, drop_duplicates
chain with itertools.product
. This is much faster at n = 3
, but already slower at n = 5
(because it's still doing more work that it needs to, and filtering).
The efficient approach is to do only the work that's necessary. A quick and dirty implementation (i.e. please tidy it up before using) calculates for n = 6
in less time than it takes the original code to calculate n = 3
:
def combinations_recursive_inner(n, buf, gaps, sum, accum):
if gaps == 0:
accum.append(list(buf))
else:
for x in range(0, n+1):
if sum + x + (gaps - 1) * n < n: continue
if sum + x > n: break
combinations_recursive_inner(n, buf + [x], gaps - 1, sum + x, accum)
def combinations_recursive(n):
accum =
combinations_recursive_inner(n, , n, 0, accum)
return pd.DataFrame(accum).as_matrix()
Online test and benchmark
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
def combinations_permuted(n_elm):
IMO n
(as used in the description of the code in the question) is more readable than n_elm
.
items = list(range(0,n_elm+1,1))
1
is the default step, and range
isn't so obscure a function that the maintenance programmer would wonder what range(0, n+1)
does.
combinations = pd.DataFrame(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.combinations_with_replacement(items, n_elm)))))
comb_permuted = pd.DataFrame()
for index, combination in combinations.iterrows():
comb_permuted=comb_permuted.append(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.permutations(combination.tolist(), n_elm)))))
return(comb_permuted.drop_duplicates().as_matrix())
There are two things here which sound warning bells:
comb_permuted=comb_permuted.append
. The documentation for DataFrame.append says
Iteratively appending rows to a DataFrame can be more computationally intensive than a single concatenate. A better solution is to append those rows to a list and then concatenate the list with the original DataFrame all at once.
drop_duplicates()
. That says that the generation process is doing more work that it needs to.
A KISS approach would be to replace the combinations_with_replacement
, permutations
, drop_duplicates
chain with itertools.product
. This is much faster at n = 3
, but already slower at n = 5
(because it's still doing more work that it needs to, and filtering).
The efficient approach is to do only the work that's necessary. A quick and dirty implementation (i.e. please tidy it up before using) calculates for n = 6
in less time than it takes the original code to calculate n = 3
:
def combinations_recursive_inner(n, buf, gaps, sum, accum):
if gaps == 0:
accum.append(list(buf))
else:
for x in range(0, n+1):
if sum + x + (gaps - 1) * n < n: continue
if sum + x > n: break
combinations_recursive_inner(n, buf + [x], gaps - 1, sum + x, accum)
def combinations_recursive(n):
accum =
combinations_recursive_inner(n, , n, 0, accum)
return pd.DataFrame(accum).as_matrix()
Online test and benchmark
add a comment |Â
up vote
1
down vote
accepted
def combinations_permuted(n_elm):
IMO n
(as used in the description of the code in the question) is more readable than n_elm
.
items = list(range(0,n_elm+1,1))
1
is the default step, and range
isn't so obscure a function that the maintenance programmer would wonder what range(0, n+1)
does.
combinations = pd.DataFrame(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.combinations_with_replacement(items, n_elm)))))
comb_permuted = pd.DataFrame()
for index, combination in combinations.iterrows():
comb_permuted=comb_permuted.append(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.permutations(combination.tolist(), n_elm)))))
return(comb_permuted.drop_duplicates().as_matrix())
There are two things here which sound warning bells:
comb_permuted=comb_permuted.append
. The documentation for DataFrame.append says
Iteratively appending rows to a DataFrame can be more computationally intensive than a single concatenate. A better solution is to append those rows to a list and then concatenate the list with the original DataFrame all at once.
drop_duplicates()
. That says that the generation process is doing more work that it needs to.
A KISS approach would be to replace the combinations_with_replacement
, permutations
, drop_duplicates
chain with itertools.product
. This is much faster at n = 3
, but already slower at n = 5
(because it's still doing more work that it needs to, and filtering).
The efficient approach is to do only the work that's necessary. A quick and dirty implementation (i.e. please tidy it up before using) calculates for n = 6
in less time than it takes the original code to calculate n = 3
:
def combinations_recursive_inner(n, buf, gaps, sum, accum):
if gaps == 0:
accum.append(list(buf))
else:
for x in range(0, n+1):
if sum + x + (gaps - 1) * n < n: continue
if sum + x > n: break
combinations_recursive_inner(n, buf + [x], gaps - 1, sum + x, accum)
def combinations_recursive(n):
accum =
combinations_recursive_inner(n, , n, 0, accum)
return pd.DataFrame(accum).as_matrix()
Online test and benchmark
add a comment |Â
up vote
1
down vote
accepted
up vote
1
down vote
accepted
def combinations_permuted(n_elm):
IMO n
(as used in the description of the code in the question) is more readable than n_elm
.
items = list(range(0,n_elm+1,1))
1
is the default step, and range
isn't so obscure a function that the maintenance programmer would wonder what range(0, n+1)
does.
combinations = pd.DataFrame(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.combinations_with_replacement(items, n_elm)))))
comb_permuted = pd.DataFrame()
for index, combination in combinations.iterrows():
comb_permuted=comb_permuted.append(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.permutations(combination.tolist(), n_elm)))))
return(comb_permuted.drop_duplicates().as_matrix())
There are two things here which sound warning bells:
comb_permuted=comb_permuted.append
. The documentation for DataFrame.append says
Iteratively appending rows to a DataFrame can be more computationally intensive than a single concatenate. A better solution is to append those rows to a list and then concatenate the list with the original DataFrame all at once.
drop_duplicates()
. That says that the generation process is doing more work that it needs to.
A KISS approach would be to replace the combinations_with_replacement
, permutations
, drop_duplicates
chain with itertools.product
. This is much faster at n = 3
, but already slower at n = 5
(because it's still doing more work that it needs to, and filtering).
The efficient approach is to do only the work that's necessary. A quick and dirty implementation (i.e. please tidy it up before using) calculates for n = 6
in less time than it takes the original code to calculate n = 3
:
def combinations_recursive_inner(n, buf, gaps, sum, accum):
if gaps == 0:
accum.append(list(buf))
else:
for x in range(0, n+1):
if sum + x + (gaps - 1) * n < n: continue
if sum + x > n: break
combinations_recursive_inner(n, buf + [x], gaps - 1, sum + x, accum)
def combinations_recursive(n):
accum =
combinations_recursive_inner(n, , n, 0, accum)
return pd.DataFrame(accum).as_matrix()
Online test and benchmark
def combinations_permuted(n_elm):
IMO n
(as used in the description of the code in the question) is more readable than n_elm
.
items = list(range(0,n_elm+1,1))
1
is the default step, and range
isn't so obscure a function that the maintenance programmer would wonder what range(0, n+1)
does.
combinations = pd.DataFrame(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.combinations_with_replacement(items, n_elm)))))
comb_permuted = pd.DataFrame()
for index, combination in combinations.iterrows():
comb_permuted=comb_permuted.append(list(filter(lambda x: np.sum(x)==n_elm,list(itertools.permutations(combination.tolist(), n_elm)))))
return(comb_permuted.drop_duplicates().as_matrix())
There are two things here which sound warning bells:
comb_permuted=comb_permuted.append
. The documentation for DataFrame.append says
Iteratively appending rows to a DataFrame can be more computationally intensive than a single concatenate. A better solution is to append those rows to a list and then concatenate the list with the original DataFrame all at once.
drop_duplicates()
. That says that the generation process is doing more work that it needs to.
A KISS approach would be to replace the combinations_with_replacement
, permutations
, drop_duplicates
chain with itertools.product
. This is much faster at n = 3
, but already slower at n = 5
(because it's still doing more work that it needs to, and filtering).
The efficient approach is to do only the work that's necessary. A quick and dirty implementation (i.e. please tidy it up before using) calculates for n = 6
in less time than it takes the original code to calculate n = 3
:
def combinations_recursive_inner(n, buf, gaps, sum, accum):
if gaps == 0:
accum.append(list(buf))
else:
for x in range(0, n+1):
if sum + x + (gaps - 1) * n < n: continue
if sum + x > n: break
combinations_recursive_inner(n, buf + [x], gaps - 1, sum + x, accum)
def combinations_recursive(n):
accum =
combinations_recursive_inner(n, , n, 0, accum)
return pd.DataFrame(accum).as_matrix()
Online test and benchmark
answered Mar 21 at 16:04
Peter Taylor
14k2454
14k2454
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f190122%2fpermutations-with-a-sum-constraint%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
What Python version are you targeting?
â Mast
Mar 21 at 13:41
try with stackoverflow.com/a/28969798/3308055
â juvian
Mar 21 at 14:32