Hypothesis strategy to generate multiple kwargs - python-hypothesis

It is natural to write my test in terms of 3 separate numpy arrays, but the first dimension of each numpy array must be of equal length. As a hack, I can simply ask for a larger numpy array
#given(
arrays=arrays(
dtype=float,
shape=tuples(
integers(3, 3),
array_shapes(max_dims=1).map(lambda t: t[0]),
array_shapes(max_dims=1).map(lambda t: t[0]),
),
elements=floats(width=16, allow_nan=False, allow_infinity=False),
),
)
def test(arrays: np.ndarray):
a, b, c = arrays[0], arrays[1], arrays[2]
...
but this obscures what I'm really trying to generate, and makes it impossible to have separate strategies the elements of each of the arrays. Is there any way to generate these arrays while maintaining the constraint on the size of the first dimension? I imagine I would want something like
#given(
(a, b, c) = batched_arrays(
n_arrays=3,
shared_sizes=array_sizes(max_dims=1),
unshared_sizes=arrays_sizes(),
dtypes=[float, int, float],
elements=[floats(), integers(0), floats(0, 1)])
)
def test(a: np.ndarray, b:np.ndarray, c:np.ndarray):
assert a.shape[0] == b.shape[0] and a.shape[0] == c.shape[0]
...

Sorry to answer my own question. It turns out you can get this with shared
#given(
a=arrays(float, shared(array_shapes(max_dims=1), key="dim1")),
b=arrays(float, shared(array_shapes(max_dims=1), key="dim1")),
)
def test_shared(a, b):
assert a.shape[0] == b.shape[0]

Related

How we will convert nested if - else code into list comprehension in python

I have tried and google the solution for below mentioned code but unfortunately I didn't get anything regarding this.
Don't change the logic pleaseConvert it into list comprehension. I Have tried list comprehension. I'm bit far from getting output.But due to syntactical error, I'm getting failure. Thanks in advance.
data = "abc##123"
t=tuple(data)
flag=0
print(t)
alpha=[]
digit=[]
spl_chr=[]
for i in t:
if i.isnumeric():
i=int(i)
if type(i)==type(flag):
digit.append(i)
elif type(i)==type(data) and i.isalpha():
alpha.append(i)
else:
spl_chr.append(i)
dic={}
dic["alphabets"]=alpha
dic["digits"]=digit
dic["symbols"]=spl_chr
print(dic)
My take:
import re
import itertools
def char_class(c):
if re.match(r'[a-z]', c, re.IGNORECASE):
return c, 'alphabets'
elif re.match(r'[0-9]', c):
return c, 'digits'
else:
return c, 'symbols'
data = "abc##123"
dic = {
k: list(e[0] for e in v) for k, v in itertools.groupby((char_class(c) for c in data), key=lambda e: e[1])
}
print(dic)
Of course, if your assignment prevents you from using SPL modules, you can always use language built-ins only:
dic = {
'alphabets': list(
set(c for c in data if c.isalpha())
),
'digits': list(
set(c for c in data if c.isnumeric())
),
'symbols': list(
set(c for c in data if not (c.isalpha() or c.isnumeric()))
),
}

Pythonic way to handle arguments with values in Union

In the code below, print_pos accepts one argument which can be of
three different types.
from typing import List, Tuple, Union
pos_t = Tuple[int, int]
anchor_t = Tuple[str, str]
anchor_pos_t = Tuple[anchor_t, pos_t]
def print_pos(
pos: Union[
pos_t,
anchor_pos_t,
List[Union[pos_t, anchor_pos_t]]
]
) -> None:
if isinstance(pos, tuple) and isinstance(pos[0], int):
print('xy =', pos)
elif isinstance(pos, tuple) and isinstance(pos[0], tuple):
print('anchor =', pos[0])
print('xy =', pos[1])
elif isinstance(pos, list):
print('[')
for p in pos:
print_pos(p)
print(']')
else:
raise ValueError('invalid pos')
print_pos((0, 100))
print_pos((('right', 'bottom'), (0, 100)))
print_pos([
(0, 100),
(('right', 'bottom'), (0, 100))
])
Right now, I use isinstance to check for the different possibilities
for the type of pos but I find the code rather clumsy. Is there a
more convenient/elegant way to do that? In particular is there a mean
to reuse types I defined (pos_t, anchor_t, anchor_pos_t) in my type check?
You can use the typeguard library to check variable types at runtime.
This library is mainly for runtime type validation, rather than conditional type checking, so an extra is_type function needs to be defined to fit your needs.
Extra type casts are also unfortunately necessary to prevent type checker errors.
from typing import Any, List, Tuple, Union, cast
from typeguard import check_type
pos_t = Tuple[int, int]
anchor_t = Tuple[str, str]
anchor_pos_t = Tuple[anchor_t, pos_t]
def is_type(value: Any, expected_type: Any) -> bool:
"""
Return whether the given value is of the expected type or not.
"""
try:
check_type('<blank>', value, expected_type)
return True
except TypeError:
return False
def print_pos(
pos: Union[pos_t, anchor_pos_t, List[Union[pos_t, anchor_pos_t]]]
) -> None:
if is_type(pos, pos_t):
pos = cast(pos_t, pos)
print('xy =', pos)
elif is_type(pos, anchor_pos_t):
pos = cast(anchor_pos_t, pos)
print('anchor =', pos[0])
print('xy =', pos[1])
elif is_type(pos, List[Union[pos_t, anchor_pos_t]]):
pos = cast(List[Union[pos_t, anchor_pos_t]], pos)
print('[')
for p in pos:
print_pos(p)
print(']')
else:
raise ValueError('invalid pos')
print_pos((0, 100))
print_pos((('right', 'bottom'), (0, 100)))
print_pos([(0, 100), (('right', 'bottom'), (0, 100))])
This isn't the cleanest solution, but it works.
I would recommend using a more object-oriented approach with classes if possible, to eliminate the need for union types.
This does not yet work with any current python version, but python 3.10 (planned to be released October 2021) will have structural pattern matching.
This allows something like this, which might be slightly more readable:
from typing import List, Tuple, Union
pos_t = Tuple[int, int]
anchor_t = Tuple[str, str]
anchor_pos_t = Tuple[anchor_t, pos_t]
def print_pos(
pos: Union[
pos_t,
anchor_pos_t,
List[Union[pos_t, anchor_pos_t]]
]
) -> None:
match pos:
# need to match this more specific case first, as tuple((x, y)) matches this as well
case tuple(((a, b), (x, y))):
print('anchor =', (a, b))
print('xy =', (x, y))
case tuple((x, y)):
print('xy =', (x, y))
case list(_):
print('[')
for p in pos:
print_pos(p)
print(']')
case _:
raise ValueError('invalid pos')
print_pos((0, 100))
print_pos((('right', 'bottom'), (0, 100)))
print_pos([
(0, 100),
(('right', 'bottom'), (0, 100))
])
This already works with the 3.10.0a7 pre-release, although the mypy support is not there yet.
Structural pattern matching is in a sense similar to sequence unpacking like
(a, b), (x, y) = pos
but more powerful.
The three PEPs describing structural pattern matching:
PEP 634 -- Structural Pattern Matching: Specification
PEP 635 -- Structural Pattern Matching: Motivation and Rationale
PEP 636 -- Structural Pattern Matching: Tutorial

To generate all possible combinations of items in a list and STORE them in different lists, and to access them later. I have stated an example below

# To generate possible combinations
from itertools import combinations
main_list=('a1','a2','a3','a4')
abc=combinations(main_list,3)
for i in list(abc):
print(i)
# Creating number of empty lists
n=6
obj={}
for i in range(n):
obj['set'+str(i)]=()
# I want to combine these, take list1 generated by combinations and store them down in set1.
/* To generate all possible combinations of items in a list and STORE them in different lists. Eg: main_list=('a1','a2','a3'), now i want to combination lists like set1=('a1'), set2=('a2'), set3=('a3'), set4=('a1','a2'), set5=('a1','a3'), set6=('a2','a3'), set7=('a1','a2','a3'). How to access lists set1, set2,... */
If I understand correctly, you want to generate the power set - the set of all subsets of the list. Python's itertools package provides a nice example function to generate this:
from itertools import chain, combinations
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
While Nathan answers helps with first part of the question, my code will help you making a dictionary, so you can access the sets like sets['set1'] as asked.
from itertools import chain, combinations
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
def make_dict(comb):
sets = {}
for i, set in enumerate(comb):
sets['set'+str(i)] = set
return sets
if __name__ == '__main__':
sets = make_dict(powerset(['a1','a2','a3','a4']))
print(sets['set1'])
Output
('a1',)

Python, scipy - How to fit a curve using a piecewise function with a conditional parameter that also needs to be calculated?

As the title suggests, I'm trying to fit a piecewise equation to a large data set. The equations I would like to fit to my data are as follows:
y(x) = b, when x < c
else:
y(x) = b + exp(a(x-c)) - 1, when x >= c
There are multiple answers to how such an issue can be addressed, but as a Python beginner I can't figure out how to apply them to my problem:
Curve fit with a piecewise function?
Conditional curve fit with scipy?
The problem is that all variables (a,b and c) have to be calculated by the fitting algorithm.
Thank you for your help!
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# Reduced Dataset
y = np.array([23.032, 21.765, 20.525, 21.856, 21.592, 20.754, 20.345, 20.534,
23.502, 21.725, 20.126, 21.381, 20.217, 21.553, 21.176, 20.976,
20.723, 20.401, 22.898, 22.02 , 21.09 , 22.543, 22.584, 22.799,
20.623, 20.529, 20.921, 22.505, 22.793, 20.845, 20.584, 22.026,
20.621, 23.316, 22.748, 20.253, 21.218, 23.422, 23.79 , 21.371,
24.318, 22.484, 24.775, 23.773, 25.623, 23.204, 25.729, 26.861,
27.268, 27.436, 29.471, 31.836, 34.034, 34.057, 35.674, 41.512,
48.249])
x = np.array([3756., 3759., 3762., 3765., 3768., 3771., 3774., 3777., 3780.,
3783., 3786., 3789., 3792., 3795., 3798., 3801., 3804., 3807.,
3810., 3813., 3816., 3819., 3822., 3825., 3828., 3831., 3834.,
3837., 3840., 3843., 3846., 3849., 3852., 3855., 3858., 3861.,
3864., 3867., 3870., 3873., 3876., 3879., 3882., 3885., 3888.,
3891., 3894., 3897., 3900., 3903., 3906., 3909., 3912., 3915.,
3918., 3921., 3924.])
# Simple exponential function without conditions (works so far)
def exponential_fit(x,a,b,c):
return b + np.exp(a*(x-c))
popt, pcov = curve_fit(exponential_fit, x, y, p0 = [0.1, 20,3800])
plt.plot(x, y, 'bo')
plt.plot(x, exponential_fit(x, *popt), 'r-')
plt.show()
You should change your function to something like
def exponential_fit(x, a, b, c):
if x >= c:
return b + np.exp(a*(x-c))-1
else:
return b
Edit: As chaosink pointed out in the comments, this approach no longer works as the the above function assumes that x is a scalar. However, curve_fit evaluates the function for array-like x. Consequently, one should use vectorised operations instead, see here for more details. To do so, one can either use
def exponential_fit(x, a, b, c):
return np.where(x >= c, b + np.exp(a*(x-c))-1, b)
or chaosink's suggestion in the comments:
def exponential_fit(x, a, b, c):
mask = (x >= c)
return mask * (b + np.exp(a*(x-c)) - 1) + ~mask * b
Both give:

Python/Pandas element wise union of 2 Series containing sets in each element

I have 2 pandas data Series that I know are the same length. Each Series contains sets() in each element. I want to figure out a computationally efficient way to get the element wise union of these two Series' sets. I've created a simplified version of the code with fake and short Series to play with below. This implementation is a VERY inefficient way of doing this. There has GOT to be a faster way to do this. My real Series are much longer and I have to do this operation hundreds of thousands of times.
import pandas as pd
set_series_1 = pd.Series([{1,2,3}, {'a','b'}, {2.3, 5.4}])
set_series_2 = pd.Series([{2,4,7}, {'a','f','g'}, {0.0, 15.6}])
n = set_series_1.shape[0]
for i in range(0,n):
set_series_1[i] = set_series_1[i].union(set_series_2[i])
print set_series_1
>>> set_series_1
0 set([1, 2, 3, 4, 7])
1 set([a, b, g, f])
2 set([0.0, 2.3, 15.6, 5.4])
dtype: object
I've tried combining the Series into a data frame and using the apply function, but I get an error saying that sets are not supported as dataframe elements.
pir4
After testing several options, I finally came up with a good one... pir4 below.
Testing
def jed1(s1, s2):
s = s1.copy()
n = s1.shape[0]
for i in range(n):
s[i] = s2[i].union(s1[i])
return s
def pir1(s1, s2):
return pd.Series([item.union(s2[i]) for i, item in enumerate(s1.values)], s1.index)
def pir2(s1, s2):
return pd.Series([item.union(s2[i]) for i, item in s1.iteritems()], s1.index)
def pir3(s1, s2):
return s1.apply(list).add(s2.apply(list)).apply(set)
def pir4(s1, s2):
return pd.Series([set.union(*z) for z in zip(s1, s2)])

Resources