Expert Analysis: Wuppertal vs Fortuna Dusseldorf II
The upcoming match between Wuppertal and Fortuna Dusseldorf II is set to be an exciting encounter with numerous betting opportunities. With a high average total goals of 4.71, this game promises plenty of action and potential for multiple scoring events. Both teams have shown tendencies to score, with Wuppertal averaging 1.38 goals per game and conceding 2.62, indicating a dynamic offensive and defensive play style.
Wuppertal
Fortuna Dusseldorf II
Predictions:
| Market | Prediction | Odd | Result |
|---|---|---|---|
| Over 1.5 Goals | 96.00% | 1.15 Make Bet | |
| Home Team Not To Score In 1st Half | 87.80% | Make Bet | |
| Last Goal 73+ Minutes | 86.80% | Make Bet | |
| Over 0.5 Goals HT | 79.80% | Make Bet | |
| Goal In Last 15 Minutes | 80.30% | Make Bet | |
| Both Teams To Score | 69.40% | 1.50 Make Bet | |
| Over 2.5 Goals | 71.50% | 1.55 Make Bet | |
| Goal In Last 10 Minutes | 68.30% | Make Bet | |
| Away Team To Score In 1st Half | 71.40% | Make Bet | |
| Over 3.5 Goals | 65.90% | 2.40 Make Bet | |
| Both Teams Not To Score In 1st Half | 64.60% | Make Bet | |
| Both Teams Not To Score In 2nd Half | 64.10% | Make Bet | |
| Over 2.5 BTTS | 59.00% | Make Bet | |
| Home Team To Score In 2nd Half | 59.90% | Make Bet | |
| First Goal Between Minute 0-29 | 56.00% | Make Bet | |
| Away Team Not To Score In 2nd Half | 56.10% | Make Bet | |
| Avg. Total Goals | 4.71% | Make Bet | |
| Avg. Conceded Goals | 2.62% | Make Bet | |
| Avg. Goals Scored | 1.38% | Make Bet | |
| Red Cards | 1.34% | Make Bet |
Betting Predictions
Goal Oriented Bets
- Over 1.5 Goals: 96.00 – Given the high average total goals, betting on more than 1.5 goals seems highly favorable.
- Over 0.5 Goals HT: 79.80 – The likelihood of at least one goal in the first half is strong.
- Both Teams To Score: 69.40 – Both teams have demonstrated their ability to find the back of the net, making this a compelling bet.
- Over 2.5 Goals: 71.50 – With an average of nearly five goals per match, over 2.5 goals is a plausible outcome.
- Goal In Last 15 Minutes: 80.30 – Late goals are common in this matchup, suggesting a good chance for a final-minute strike.
- Last Goal After 73 Minutes: 86.80 – The trend indicates that late goals are likely, making this bet attractive.
- Away Team To Score In 1st Half: 71.40 – Fortuna Dusseldorf II has the potential to score early in the game.
- Away Team Not To Score In 2nd Half: 56.10**
- Home Team To Score In 2nd Half: 59.90**
Timing Bets
- First Goal Between Minute 0-29: 56.00**
- Goal In Last 10 Minutes: 68.30**
No Goals Bets (Halves)
- Home Team Not To Score In First Half: 87.80**
- Away Team Not To Score In First Half: **71.40** (Complementary Bet)
- Both Teams Not To Score In First Half: **64.60** (Complementary Bet)
- Away Team Not To Score In Second Half: **56.10** (Complementary Bet)</luser
I’m having trouble using `np.linalg.eigvals` with complex-valued matrices that have very small imaginary parts compared to their real parts:
a = np.array([[0., .00001], [100., .00001]]) b = np.array([[0., .000001], [100., .000001]]) c = np.array([[0., .000001j], [100., .000001j]]) eig_a = np.linalg.eigvals(a) eig_b = np.linalg.eigvals(b) eig_c = np.linalg.eigvals(c) print(eig_a) print(eig_b) print(eig_c) print(np.allclose(eig_a, eig_b)) print(np.allclose(eig_a, eig_c)) print(np.allclose(eig_b, eig_c)) print(np.iscomplexobj(eig_a)) print(np.iscomplexobj(eig_b)) print(np.iscomplexobj(eig_c)) # Output: # [100.+0.j -0.-0.j] # [100.+0.j -0.-0.j] # [100.+9.e-07j -9.e-07j] # True # False # False # False # False # TrueThe issue here is that `np.linalg.eigvals` returns complex values even when they should be real-valued; I'm not sure why it's doing this or how to get it to return real values when they're appropriate (i.e., when the imaginary part is very small).
I've tried using `np.real_if_close`, but it doesn't seem to work for eigenvalues:
eigenvalues_real_if_close = np.real_if_close(eig_a)
eigenvalues_real_if_close_complex = np.real_if_close(eig_c)print(type(eigenvalues_real_if_close[0]))
print(type(eigenvalues_real_if_close_complex[0]))
# Output:
# <class 'numpy.complexfloating'>
# <class 'numpy.complexfloating'>
print(np.allclose(a,eigenvalues_real_if_close_complex))
# Output:
# Falsefor i in range(len(a)):
for j in range(len(a)):
if abs((a[i,j]-c[i,j])/a[i,j]) >= tolerance:
return False
return Truedef close_matrices(m,n,tolerance):
return close_matrices(a,c,.00001)close_matrices(a,c,.00001) # This returns True as expected.
close_matrices(b,c,.00001) # This returns False as expected.
close_matrices(a,b,.00001) # This returns True as expected.
close_matrices(b,a,.00001) # This returns True as expected.
close_matrices(c,a,.00001) # This returns False as expected.
close_matrices(c,b,.00001) # This returns False as expected.I would expect `np.real_if_close` to return real-valued arrays when appropriate because I'm only interested in the real part of these eigenvalues for my application.
I also tried using `np.isreal` on each element in `eigenvalues_real_if_close`, but this still resulted in a complex array:
eigenvalues_real_check = []for i in range(len(a)):
for j in range(len(a)):
if np.isreal(eigenvalues_real_if_close[i]):
eigenvalues_real_check.append(np.real(eigenvalues_real_if_close[i]))
else:
eigenvalues_real_check.append(eigenvalues_real_if_close[i])print(type(eigenvalues_real_check[0]))
#print([type(x) for x in eigenvalues_real_check])
#print([x.imag for x in eigenvalues_real_check])
#print([x.real for x in eigenvalues_real_check])
Output:This is also surprising because `np.real` works fine on its own if you just want to extract the real part:
eigenvalue_1_realsplit = []
eigenvalue_2_realsplit = []for i,j in zip(*np.split(np.real(eigs),2)):
eigenvalue_1_realsplit.append(i)
eigenvalue_2_realsplit.append(j)print(type(eigenvalue_1_realsplit[0]))
#print([type(x) for x in eigenvalue_1_realsplit])
#print([x.imag for x in eigenvalue_1_realsplit])
#print([x.real for x in eigenvalue_1_realsplit])Output:
I think I'm missing something about how numpy treats complex numbers and floating-point precision here... Any suggestions?
Edit:
- If I use `np.round()` instead of `np.real()` on my original output from `np.linalg.eighvals`, then I get what I want:
eigs_rounded_split = []
for i,j in zip(*np.split(np.round(10000*eigs)/10000,2)):
eigs_rounded_split.append(i)
eigs_rounded_split.append(j)round_eigs_split_are_the_same_as_origs_split =
all(
[
round_eigs_split_are_the_same_as_origs_split,
all(abs(orig-eval)<=tolerance*abs(orig) for orig,eval
in zip(origs_split,eigs_rounded_split)),
]
)round_eigs_split_are_the_same_as_origs_split == True
origs_rounded_split_are_the_same_as_round_eigs_split =
all(
[
origs_rounded_split_are_the_same_as_round_eigs_split,
all(abs(orig-eval)<=tolerance*abs(orig)
for orig,eval
in zip(origs_rounded_split,eigs_rounded_split)),
]
)origs_rounded_split_are_the_same_as_round_eigs_split == True
origs_rounded_and_origs_are_the_same =
all(
[
origs_rounded_and_origs_are_the_same,
all(abs(orig-eval)<=tolerance*abs(eval)
for orig,eval
in zip(origs_rounded,eorigs)),
]
)origs_rounded_and_origs_are_the_same == True
origs_all_about_equal =
all([
round_eigs_splits_are_the_same_as_orig_splits,
origs_rondeds_splits_are_the_same_as_rondsplits,
origroundedandorignarethesame,
])origes_all_about_equal == True
This seems like kind of a hacky way of getting what I want though...
Edit #2:
- I don't know why my original code didn't work:
eisrealchecksplit =
[
type(x)==float if eisrealchecksplit else type(x)==complex
for x
in eisrealchecksplit]The above gives me all floats like I wanted.
I was hoping there was some better way though...
- If I use `np.round()` instead of `np.real()` on my original output from `np.linalg.eighvals`, then I get what I want: