text:
# how to improve efficiency when I want to classify a list according to certain laws

I have a function that generates lists:

f[n_] := Join @@ Permutations /@ PadLeft@IntegerPartitions[n];

For example

f[3]

{{0, 0, 3}, {0, 3, 0}, {3, 0, 0}, {0, 2, 1}, {0, 1, 2},
{2, 0, 1}, {2, 1, 0}, {1, 0, 2}, {1, 2, 0}, {1, 1, 1}}

f[3] returns 10 lists of three elements, which I want to classify this according to certain laws;

{0, 0, 3}, {0, 3, 0} and {3, 0, 0} belong one class with 3 members because RotateLeft can transform any one of these into any of the others.

Similarly, {0,1,2}, {1,2,0} and {2,0,1} belong one class with 3 members.

{0, 2, 1}, {2, 1, 0} and {1, 0, 2} belong one class with 3 members.

{1, 1, 1} belongs to a class of which it is the only member.

So the result I want is

I have code that will generate the desired result

m = AbsoluteTime[];
f[n_Integer] := Join @@ Permutations /@ PadLeft@IntegerPartitions[n];
f2[list_] := Module[{n = 1, m = 0},
While[n <= Length[data1],
If[Or @@ (SameQ[data1[[n, 1]], #] & /@
NestList[RotateLeft, list, Length[list] - 1]), data1[[n, 2]]++;
m++; Break[]];
n++];
If[m == 0, AppendTo[data1, {list, 1}]]]
data1 = {{First@f[7], 1}};
f2 /@ Drop[f[7], 1];
Length[f[7]]
data1 // Length
AbsoluteTime[] - m

but it's too slow. When n = 7, it takes about 11 seconds, but I want to work with n is the range from 14 to 20. how can I improve efficiency the efficiency of my code?

-
Notice, that there is unscoped data1 in f2 definition. –  Kuba Oct 25 '13 at 8:59

I believe I'm missing some basic function that can easily reproduce the test here. But that's a detail, the main thing is to use Tally with the second argument specification:

test[x_List] := Sort@Array[RotateLeft[x, #] &, Length[x]]

Tally[f[3], test[#1] == test[#2] &] // MatrixForm

$\left( \begin{array}{cc} \{0,0,3\} & 3 \\ \{0,2,1\} & 3 \\ \{0,1,2\} & 3 \\ \{1,1,1\} & 1 \\ \end{array} \right)$

It's not the optimal way, for n = 10 it takes about 5 sec on my old pc. I will think about improvements.

-
@user10193 Please hold on with an accept a little, it is a good habit in order to not discourage others. I'm 100% sure that better answers will appear here. :) –  Kuba Oct 25 '13 at 8:57
Tkx very much.I considered about tally but I just know use Tally[list] but Tally[list, test].so thank you. –  Chenminqi Oct 25 '13 at 9:01
@Kuba do you mean First@Sort in test? Now you end up comparing lists of lists, whereas you only need to compare one representative. I agree there should probably be some trick to do this step :) –  Jacob Akkerboom Oct 25 '13 at 10:58
@JacobAkkerboom No I didn't, but good idea with First it may help with long lists. I was thinking about something like built in testing if two lists are related with an odd/even permutation. But I must admit my math skils are not existant in this area. I don't even know if what I'm thinking about is called even permutation in english :). I was trying to avoid to many Sorting with MemberQ[test[#],#2]& as the second argument but it seems it is longer. –  Kuba Oct 25 '13 at 11:10
@Kuba it is an interesting problem. Odd/even permutations are a big thing, so its probably the right word ;). If you can tackle it like that I'd be curious. For me the main problem becomes finding that the "lowest subsequence" of length 3 of {0,1,2,0,0,3} is {0,0,3} and not {0,1,2}. Hrm :P –  Jacob Akkerboom Oct 25 '13 at 11:38

Introduction

The key to concept to tackling this problem is rotational symmetry. Using this, it turns out that we can find out how many elements your classes have relatively easily (in terms of memory and CPU usage, it does take some math). Actually finding and storing the elements that represent the classes is more of a programming challenge than a mathematical one, and this is what will cost most computational resources. The algorithm I present finds exactly one representative of each class, so in this way the problem is nicely cut into two parts.

Theory

Now let's do some group theory. Throughout the text of this answer, let $n$ be the n of your question, which is the integer for which we want to describe such classes. In my code I will call this variable in for input. It turns out the classes you describe are orbits of the group $\mathbb{Z}_n$ acting on the set of weak compositions of $n$. Let's give the set of weak compositions a name

$$X_n = \lbrace \vec x \in (\mathbb{Z}_n)^n | \sum_{k=1}^n x_k = n \rbrace$$

We wish to know how many elements there are in any particular class a.k.a. orbit. The section on wikipedia article that explains about orbits gives a result that we can use here, in its subsection Orbit-stabilizer theorem and Burnside's lemma. The result states

$$|G.x| = |G|\; /\; |G_x|$$

On the LHS is the quantity we are after, i.e. the number of elements of the orbit of $x$. Formally, $G_x$ is called the stabiliser of x, a notion which is also explained in the article. However, we can forget about stabilisers and look directly at $|G_x|$. $|G_x|$ is the number of elements of $G$ for which $g.x =x$. For our group $G = \mathbb{Z}_n$ this is something quite intuitive. For example for $n = 6$ and

$$x=(1,1,1,1,1,1)$$

we see that all elements of $G$ map x to x. So $|G_x| = n = 6$. So for this particular $x$, $|G.x| = |G|\; /\; |G_x| = n/n = 1$. Of course it was quite clear that the class to which $x$ belongs has only one element. Now consider

$$x=(0,0,3,0,0,3)$$

the class to which this $x$ belongs has 3 elements, because there are 2 ways we can left shift this onto itself. We can shift by 0 or 3 spots. So in this case $|G.x| = 6/2 = 3$. In this last example let us say that $x$ has period 3, because the smallest repeating subsequence that comprises $x$ is $(0,0,3)$ which has length 3. It should be clear that if we know the period of a sequence $x$, it is easy to find the length of its orbit.

There is another advantage to considering the periods of sequences. We can partition the set of orbits by their periods. Then finding all the classes of which the elements have a certain period can be transformed into the original problem. If for $n = 6$, we wish to find all sequences with period 3, we simply have to solve the same problem for $n = 3$. That is, for $n=3$ we have the sequences

$$(1,1,1)\quad (0,1,2) \quad (0,2,1)\quad (0,0,3)$$

and so for $n=6$ we have the corresponding sequences

$$(1,1,1,1,1,1)\quad (0,1,2,0,1,2) \quad (0,2,1,0,1,2)\quad (0,0,3,0,0,3)$$

But both sequences that consist only of 1's have period 1 and not 3. So in the case for $n=3$, we have to consider the trivial subproblem for $n=1$. To get a proper one-to-one correspondence between such sequences, we should only consider the aperiodic elements in the subproblems. Here, by aperiodic I mean that an element of $x \in X_n$ is aperiodic if the period of $x$ is $n$.

One last nice bit of theory is the following. We can also derive how many orbits there are. It is nice to know how many orbits there will be, as this will tell us how long our arrays will have to be. We will first only consider the case where $n$ is prime, which will lead to a useful result when we work with aperiodic sequences. For $n$ prime, we can easily relate the number of orbits to $|X_n|$. Let $Y_n$ be the set of orbits. As every orbit contains $n$ elements, as $n$ is prime, we have

$$|Y_n| = |X_n|\; /\; n$$

Now recall that $X_n$ is the set of weak compositions of $n$. In the section Number of compositions of this wiki article, we find that the number of weak compositions is $\binom{2 n -1}{n -1}$ (use the formula with $k=n$). So we have

$$|Y_n| = \binom{2 n -1}{n -1}\; /\; n$$

For $n$ which are not prime, partition $X_n$ by period and count the elements in each of the parts. Maybe now the following function explains itself. The idea is that in later code there will be a big array main, consisting of sequences of length $n$ (in in the code). In this array the elements are ordered by period. Maybe the first f[1] will have period $n$ and the elements f[1]+1;;f[2] will have period $n/2$. We have that outSize is the length of array main and that subListLength gives the length of the parts (f[i_]:=subListLength[[i]]).

ClearAll[mInitialization, divs, divDivisors, divLen, terms, bins,
outSize]
mInitialization[in_] :=
(
divs = Divisors[in];

divDivisors =
Outer[If[# == #2, False, Divisible[#, #2]] &, divs, divs];

divLen = Length@divs;

terms = ConstantArray[0, divLen];

bins = Binomial[2 # - 1, #] & /@ divs;

Do[
terms[[iter]] =
bins[[iter]] -
Sum[If[divDivisors[[iter, kkkk]], terms[[kkkk]], 0], {kkkk,
divLen}]

,
{iter, divLen}

];

subListLengths = Reverse[terms/divs];

outSize = Total[subListLengths];

);

Compiled function

I will not go into the details of finding the representations of the classes. There is a little bit more interesting math here and maybe I will post that later.

First let's make a tidy overview of our variables. The variables in hConsts are basically values that will inlined in the compiled function.

hConsts = Hold[walkedBack, walkedForward, maxDepth];
hLocals =
Hold[test, depth, direction, total, iters, (*activeGap,*)
distanceToGap, initVal, candidate, storage, storeCount];
ClearAll @@ hLocals;
ClearAll @@ hConsts;
walkedBack = 0;
walkedForward = 1;
maxDepth := in - 1

Here is the initialization of the compiled function we will use. It is not actually used as a function, but it is inlined, as it will be part of a compiled function.

(*OwnValues of initialization are used*)
initialization :=
(
iters = Table[0, {in - 1}];
iters[[in - 1]] = in;
total = 0;

depth = maxDepth;

test = True;

(*activeGap=0;*)
direction = walkedForward;
distanceToGap = 0;

storage = ConstantArray[0, {outSize, in}];

storeCount = 0;
)

Here is the code that is used to store a sequence in our array. This code is also inlined in the compiled function.

store[] :=
(
Increment[storeCount];
Do[
storage[[storeCount, kkkk + 1]] = iters[[kkkk]]
,
{kkkk, in - 1}
];
);

This is the main code of the compiled function.

codezzz :=
(
While[
test
,
If[
depth < maxDepth
,
If[
direction == walkedBack
,

If[
total + iters[[depth]] <=
in - 2 (*we know a sequence cannot end in a 0,
so we need space for at least a 1. This argument should be \
expanded.*)
,

Increment[iters[[depth]]];
total += iters[[depth]];
Increment[depth];
direction = walkedForward;
(*activeGap=depth;*)
distanceToGap = 0;

unless depth \[Equal] maxDepth*)

,
Decrement[depth];
direction = walkedBack;
(*as we added 1 before prematurely*)

If[
depth == 0
,
test = False;
,
total = total - iters[[depth]];
]
]

,
(*if cont: walkedForward*)

If[
distanceToGap > 0,
initVal = iters[[distanceToGap]],
initVal = 0;
];

If[
total + initVal <= in - 1
,
(*initialization*)
iters[[depth]] = initVal;

Increment[depth];
direction = walkedForward;
Increment[distanceToGap];
total = total + initVal
,
Decrement[depth];
direction = walkedBack;
total -= iters[[depth]]

]

]

,

If[
distanceToGap == 0,

iters[[depth]] = in - total;
store[]
,

candidate = in - total;

If[
candidate > iters[[distanceToGap]]
,
iters[[depth]] = candidate;
store[]
]

];
Decrement[depth];
direction = walkedBack;
(*activeGap=0;*)
total -= iters[[depth]]

]

];
storage
)

This code creates the compiled function

cfu =
ReleaseHold[
Unevaluated[
Compile[{{in, _Integer}, {outSize, _Integer}},
Block[
#1
,
#2
]
, CompilationTarget :> "C"
]
]
] & @@
{
List @@@ Hold[Evaluate[hLocals]]
,
(
(
Hold[
initialization;
codezzz
] /. Join[OwnValues[codezzz], OwnValues[initialization]]
) /. Apply[Join, List @@ OwnValues /@ hConsts]
) /. DownValues[store]
};

The compiled function finds only aperiodic sequences. We need more functions! This function handles cacheing, which is especially useful as we need to solve subproblems. The W in cfuW is for wrapper.

<<Developer
cached[x_] := False;
ClearAll[cfuW];
cfuW[inSub_ /; inSub > 2, outSize_, isAperiodicSize_] :=

If[isAperiodicSize,
If[
TrueQ@cached[inSub],
cache[inSub],
{
cache[inSub] = cfu[inSub, outSize],
cached[inSub] = True
} // First
],
cfu[inSub, outSize]
];
cfuW[1, 1, True] := {{1}} // ToPackedArray;
cfuW[2, 1, True] := {{0, 2}} // ToPackedArray;

Another wrapper to localize some variables in the aperiodic case

findAperiodicComps[inSub_] :=
Block[
{in, outSize, divs, terms, subListLengths},
in = inSub;
mInitialization[in];
cfuW[in, Last[terms]/Last[divs], True]
]

Finally, the function that deals with the general case.

ClearAll[findComps]
findComps[inSub_] :=
Block[
{in, main, rest, spanLists, divs, terms, subListLengths}
,
in = inSub;
mInitialization[in]; (*sets outSize etc*)

main = ConstantArray[0, {outSize, in}];
main[[;; Last[terms]/Last[divs]]] =
cfuW[in, Last[terms]/Last[divs], True];
rest =
cfuW[#, #2, True] &
@@@
Reverse[
Delete[
Transpose[
{
divs,
terms/divs
}
]
,
{{-1}}
]
];
spanLists =
Transpose[
{1 + Delete[#, -1], Delete[#, 1]} &@
Accumulate@Reverse[terms/divs]
];
Function[
#
,
{0, {0, in - #2}}
,
"Periodic"
]
] @@@
Transpose[
{rest, Reverse[Delete[divs, -1]], spanLists}

];
{main, divs, subListLengths}
]

Functions to conform to OPs format

The format required by the OP forces the unpacking of arrays. But it is useful to show how get the data in this format.

take[result_, terms_, subListLengths_, a_ ;; b_] :=
Transpose[
{
result[[a ;; b]]
,
Flatten[
ConstantArray[#, #2] & @@@
Transpose[{Reverse@terms, subListLengths}], 1][[a ;; b]]
}
]

take[result_, terms_, subListLengths_, All] :=
Transpose[
{
result
,
Flatten[
ConstantArray[#, #2] & @@@
Transpose[{Reverse@terms, subListLengths}], 1]
}
]

takeSimple[in_] := take[##, All] & @@ findComps[in]

Result

We now have

takeSimple[3] // MatrixForm

Which has a different ordering than both the OPs code and Kuba's code, but sure enough is correct.

Comparison set up

f[n_]:=Join@@Permutations/@PadLeft@IntegerPartitions[n];
test[x_List]:=Sort@Array[RotateLeft[x,#]&,Length[x]]
representation[x_List] :=
First@test[x];
kuba[n_]:=Tally[f[n],test[#1]==test[#2]&]

Actual comparison

n = 10;
(resKubaShort = kuba[n][[All, 1]]) // Timing // First
(resJacobShort = findComps[n][[1]]) // Timing // First

 2.231080
0.004269

SameQ @@ Sort /@ {representation /@ resKubaShort, resJacobShort}

True

This also indicates that all the results in resJacobShort are canonical. For what its worth.

A timing for higher n would be

n = 15;
(resJacobShort = findComps[n][[1]]) // Timing // First

3.690403

I think I can also still run it for n=16. But for higher n, we run out of memory. Memory usage in this code does not display much CS skill. We store integers that cannot be larger than n` as 64 bit integers. No effort is made to for example store part of the list on the hard drive to load it on demand. Maybe someday..

-


text:
# [SOLVED] Complex integral

Printable View

• Sep 16th 2009, 09:30 AM
arbolis
[SOLVED] Complex integral
I must calculate $\int _1^3 (z-2)^3 dz$ where the path is an arbitrary contour between the limits of integration.

I simply calculated the integral as if $z$ was a real variable in order to get that it's worth $0$.
Am I right?
• Sep 16th 2009, 11:33 AM
shawsend
You can use antiderivatives because the integrand is analytic and single-valued over the contour.
• Sep 16th 2009, 11:36 AM
Opalg
Quote:

Originally Posted by arbolis
I must calculate $\int _1^3 (z-2)^3 dz$ where the path is an arbitrary contour between the limits of integration.

I simply calculated the integral as if $z$ was a real variable in order to get that it's worth $0$.
Am I right?

Yes. The function has an indefinite integral, so all you need to do is to evaluate that at the two ends of the path.

format: plain


text:
# Show that V is a direct sum

## Homework Statement

Let ##T\in L(V,V)## such that ##T^{2}=1##. Show that ##V=V_{+}\oplus V_{-}## where ##V_{+}=\{v\in V:T(v)=v\}## and ##V_{-}=\{v\in V:T(v)=-v\}##.

## The Attempt at a Solution

I was given a theorem that said that ##V## is the direct sum if and only if every vector in ##V## can be expressed as a sum ##v=v_{1}+v_{2}## where ##v_{1}\in V_{+}## and ##v_{2}\in V_{-}## and if ##v_{1}+v_{2}=0## then ##v_{1}=v_{2}=0##.

I was able to show that if ##v_{1}+v_{2}=0## then ##v_{1}=v_{2}=0## but I am not able to show that every vector in ##V## can be expressed as a sum ##v=v_{1}+v_{2}## where ##v_{1}\in V_{+}## and ##v_{2}\in V_{-}##.

HallsofIvy
Homework Helper
Let v be any vector in V. Let u= T(v). Since $T^2= 1$, T(u)= v. Then T(u- v)= T(u)- T(v)= v- u= -(u- v) and T(u+ v)= T(u)+ T(v)= v+ u= u+ v.

Let v be any vector in V. Let u= T(v). Since $T^2= 1$, T(u)= v. Then T(u- v)= T(u)- T(v)= v- u= -(u- v) and T(u+ v)= T(u)+ T(v)= v+ u= u+ v.

I am a little confused on how this shows that any v can be expressed as a sum of v1 and v2. It looks to me like it just shows that any vector is either in v1 or v2.

Dick
Homework Helper
I am a little confused on how this shows that any v can be expressed as a sum of v1 and v2. It looks to me like it just shows that any vector is either in v1 or v2.

Then you need to reread Hall's proof. v is ANY vector. u isn't any vector. u=T(v). v=(v+u)+(v-u). v+u is in ##V_{+}## and (v-u) is in ##V_{-}##.

Then you need to reread Hall's proof. v is ANY vector. u isn't any vector. u=T(v). v=(v+u)+(v-u). v+u is in ##V_{+}## and (v-u) is in ##V_{-}##.

AH! Thanks! I was a little too frustrated with this problem to be able to read his proof clearly...

Dick


text:
Functions

The CommandAPI has support to use Minecraft's functions within your plugins. This is handled by using a class provided by the CommandAPI called FunctionWrapper, which allows you to execute functions. The CommandAPI also provides support to let you run your own commands within Minecraft function files.

Functions in 1.16+

Developer's Note:

Minecraft 1.16+ change the way that datapacks are loaded on the server, so that they load before plugins are enabled. This means that non-vanilla commands that are declared in functions and tags will be detected as invalid, causing the server to throw a lot of errors at the very start.

The CommandAPI reloads datapacks once the server has finished loading using all declared commands, therefore the error messages at the start of the server can be ignored.

Using custom commands in functions

In order to use a command from your plugin in a .mcfunction file, you must register your command in your plugin's onLoad() method, instead of the onEnable() method. Failure to do so will not allow the command to be registered for Minecraft functions, causing the function file to fail to load during the server startup phase.

Developer's Note:

In short, if you want to register a command which can be used in Minecraft functions, register it in your plugin's onLoad() method.

Example - Registering command for use in a function

Say we have a command /killall that simply kills all entities in all worlds on the server. If we were to register this in our onLoad() method, this would allow us to use the /killall command in Minecraft functions and tags.

public class Main extends JavaPlugin {

@Override
//Commands which will be used in Minecraft functions are registered here

new CommandAPICommand("killall")
.executes((sender, args) -> {
//Kills all enemies in all worlds
Bukkit.getWorlds().forEach(w -> w.getLivingEntities().forEach(e -> e.setHealth(0)));
})
.register();
}

@Override
public void onEnable() {
//Register all other commands here
}
}


text:
# Roth IRA

Roth IRA is an individual retirement arrangement which does not entitle an individual to claim the contributions made to the account as tax deductions, but allows those after-tax contributions to accumulate tax-free and entitles the individual to tax-free distributions when some relevant conditions are met.

Unlike a traditional IRA which allows tax relief at the time a contribution is made to the account, a Roth IRA allows tax relief at the time of distributions from the account.

To Roth or not to Roth: Roth IRA should be preferred if the account holder expects his tax rate to be higher in future. The advantage of this strategy is demonstrated in the example below.

## Contribution limits

An individual or a family can designate a retirement account as a Roth IRA if they meet the following conditions related to contributions to the account:

• The total of contribution to all IRAs (both Roth IRA and traditional IRAs) is not more than $5,500 ($6,000 if aged 50 or older).
• The contributions are below the limits specific to Roth IRA given here.

## Qualified Distributions

Only qualified distributions out of Roth IRA enjoy tax advantage. Qualified distributions are withdrawals out of the Roth IRA that are made in a period after 5-years of contributions have been made, and they are made (a) on or after the date the individual reaches an age of 59½, (b) made (earlier than age of 59½) due to disability or (c) made to beneficiaries after death of the account holder.

Withdrawals that do not satisfy the criteria for qualified distributions may be taxable.

## Calculation Example

Tokuhisa Tajima is a 35 years old systems engineer. He and his family has modified adjusted gross income (AGI) of $120,000 in 20Y3. His employer does not offer any pension plan, so he is interested in setting up an IRA with annual contributions of$5,000. He plans to withdraw all the accumulated balance in the account at his retirement, which is due to occur at age 60. His current tax rate is 15% and his tax rate in 25 years will be 20%. He expects to earn 7% on his investments. Which type of individual retirement account should Tokuhisa prefer?

Solution:

Scottrade offers a good IRA calculator available here.

Feeding the data in the calculator, we get the following comparison:

Tukihisa should set up a Roth IRA because it will generate maximum after-tax value at retirement. It is because Roth IRA distributions are tax-free and hence the zero taxes due at retirement. Traditional IRA contributions are tax deductible but its distribution is taxable and hence the figure for taxes due at retirement for traditional IRA. The value of reinvested taxes represent the future value of tax saving due to tax deductibility of contributions in a traditional IRA.

The following publication by IRS explains the rules for Roth IRA eligibility, contributions and withdrawals in detail: Roth IRA.

Written by Obaidullah Jan


text:
#### Volume 25, issue 1 (2021)

 Recent Issues
 The Journal About the Journal Editorial Board Editorial Interests Subscriptions Submission Guidelines Submission Page Policies for Authors Ethics Statement ISSN (electronic): 1364-0380 ISSN (print): 1465-3060 Author Index To Appear Other MSP Journals
Holomorphic one-forms without zeros on threefolds

### Feng Hao and Stefan Schreieder

Geometry & Topology 25 (2021) 409–444
##### Abstract

We show that a smooth complex projective threefold admits a holomorphic one-form without zeros if and only if the underlying real $6$–manifold is a ${C}^{\infty }$–fibre bundle over the circle, and we give a complete classification of all threefolds with that property. Our results prove a conjecture of Kotschick in dimension three.

##### Keywords
topology of algebraic varieties, one-forms, minimal model program, classification, generic vanishing, threefolds
##### Mathematical Subject Classification 2010
Primary: 14F45, 14J30, 32Q55
Secondary: 32Q57


text:
### 136. Erasing Edges

time limit per test: 0.25 sec.
memory limit per test: 4096 KB

Little Johnny painted on a sheet of paper a polygon with N vertices. Then, for every edge of the polygon, he drew the middle point of the edge. After that, he went to school. When he came back, he found out that his brother had erased the polygon (both the edges and the vertices). The only thing left were the middle points of the edges of the polygon. Help Johnny redraw his polygon.

Input

The first line of the input contains the integer number N (3<=N<=10 000). Then, N lines will follow, each of them containing 2 real numbers, separated by blanks: xi and yi. (xi,yi) are the coordinates of the middle point of the edge #i. The coordinates will be given with at most 3 decimal places.

Output

Print a line containing the word "YES", if the polygon can be redrawn, or "NO", if there exists no polygon having the given coordinates for the middle points of its edges. If the answer is "YES", then you should print N more lines, each of them containing two real numbers, separated by a blank, representing the X and Y coordinates of the vetices of the polygon. The coordinates should be printed with at least 3 decimal places. You should output the cordinates for vertex #1 first, for vertex #2 second and so on.. In order to decide which vertex of the polygon is #1,#2,..,#N, you should know that for every 1<=i<=N-1, edge #i connects the vertices labeled i and i+1. Edge #N connects the vertices N and 1.

Hint

The polygon may contain self-intersections. Although in many geometric problems, self-intersections only make things more difficult, in this case, they make things a lot easier.

Sample Input #1

4
0 0
2 0
2 2
0 2

Sample Output #1

YES
-1.000 1.000
1.000 -1.000
3.000 1.000
1.000 3.000

Sample Input #2

4
0 0
2 0
2 2
1 3

Sample Output #2

NO

 Author : Mugurel Ionut Andreica Resource : SSU::Online Contester Fall Contest #2 Date : Fall 2002


text:
Share

# Write the Mathematical Expression of the First Law of Thermodynamics For Isothermal Process - Physics

ConceptChemical Thermodynamics and Energetic First Law of Thermodynamics

#### Question

Write the mathematical expression of the First Law of Thermodynamics for  Isothermal Process

#### Solution

Condition:  DeltaT=0  Hence DeltaU=0

Mathematical expression of the first law : W = -q

Is there an error in this question or solution?

#### APPEARS IN

2016-2017 (July) (with solutions)
Question 2.8 | 2.00 marks

#### Video TutorialsVIEW ALL [2]

Solution Write the Mathematical Expression of the First Law of Thermodynamics For Isothermal Process Concept: Chemical Thermodynamics and Energetic - First Law of Thermodynamics.
S


text:
# patch

Creates 2D or 3D patches in an axis.

## Syntax

h = patch(x, y, c)

h = patch(x, y, z, c)

h = patch('vertices', vertices_matrix, 'faces', faces_matrix)

h = patch(hAxes, ...)

## Inputs

x, y, z
Coordinates of patch vertices.
Type: double | integer
Dimension: vector | matrix
c
Patch color.
Type: char
Dimension: scalar
vertices_matrix
An Mx2 or Mx3 matrix that contains the coordinates of the patch vertices. M is the number of vertices.
Type: double | integer
Dimension: matrix
faces_matrix
An MxN matrix that contains the indices of the vertices of each patch. M is the number of patches and N is the number of vertices of each patch. NaN may be used if not all polygons have the same number of vertices (see the Examples section).
Type: double | integer
Dimension: matrix
hAxes
Axis handle.
Type: double
Dimension: scalar

## Outputs

h
Handle of the patch graphics object.

## Examples

2D patch plot example:
clf;
t1 = (1/16:1/8:1) * 2*pi;
t2 = ((1/16:1/8:1) + 1/32) * 2*pi;
x = tan (t1) - 0.8;
y = sin (t1);
h = patch (x',y','r')
2D patch plot defined by vertices and faces matrices examples:
x = [0 0.25 0.5 1 1 0.5 0.25 0 -0.5 -0.5]';
y = [0 0 0 0.5 1 1.5 1.5 1.5 1 0.5]';
verts = [x, y];

figure(1);
% Create one patch which constinst of 10 vertices
faces = [1:10];
h = patch('vertices',verts,'faces',faces);

figure(2);
% Create two patches each one consisting of 4 vertices
faces = [3 4 5 6; 8 9 10 1];
h = patch('vertices',verts,'faces',faces);

figure(3)
% Create two patches, the first patch consists of 6 vertices,
% the second patch consists of 4 vertices
faces = [2 3 4 5 6 7; 8 9 10 1 NaN NaN];
h = patch('vertices',verts,'faces',faces);
Example of 3D patch plot. Patch faces are triangles:
clf;
x = [0 1 1 0; 1 1 0 0; 0.5 0.5 0.5 0.5];
y = [0 0 1 1; 0 1 1 0; 0.5 0.5 0.5 0.5];
z = [0 0 0 0; 0 0 0 0; 1 1 1 1];
h = patch(x,y,z,'r');
Example of 3D patch plot. Patch faces are quads:
clf;
x = [0 1 1 0; 1 1 0 0; 1 1 0 0; 0 1 1 0];
y = [0 0 1 1; 0 1 1 0; 0 1 1 0; 0 0 1 1];
z = [0 0 0 0; 0 0 0 0; 1 1 1 1; 1 1 1 1];
h = patch(x,y,z,'r');
Example of 3D patch plot. Patch faces are polygons, triangulation is performed:
clf;
x = [0.5 0; 1.5 0; 2 0; 1.5, 0; 0.5 0; 0 0];
y = [0 0; 0 0.5; 0 1; 0 1.5; 0 1; 0 0.5];
z = [0 0.5; 0 0; 0.5 0; 1 0.5; 1 1; 0.5 1];
h = patch(x,y,z,'r');
Example of 3D patch plot defined by vertices and faces matrices:
clf;
verts = [0 2.5 0; 1 1.5 0; 1.5 1 0;   2 0.5 0; 2.5 0, 0.5; 2 0.5 1;
1.5, 1 1; 1 1.5 0.5; 1 1.5 1; 0 2.5 1; 0.5 2 0.5];
faces = [1 2 11 NaN NaN NaN; 9 10 11 NaN NaN NaN; 3 4 5 6 7 8];
h = patch('vertices',verts,'faces',faces);


text:
### Home > MC1 > Chapter 2 > Lesson 2.3.1 > Problem2-107

2-107.

Show the numbers of $+$ and $-$ pieces represented by each expression below. Sketch each model and state the number that it represents.

1.  $(-2)+(-6)$

If you need help starting the problem, look at the Math Notes box in Lesson 2.2.4.

Begin by sketching a model of the integers.

$-\quad - \ - \ -\\ - \quad - \ - \ - \\ -2 \quad \quad -6$

Use the model you just sketched to help you determine what number the expression represents.

This expression represents $-8$.

1.  $(-2)+4+(-2)$

Use part (a) as a guide for this problem. Remember to look for and eliminate zeros.

This expression represents $0$. Remember to draw a diagram to model this expression.

1.  $5+(-8)$

Use part (a) as a guide for solving this problem.


text:
This chapter explores the different functions of mlr3 when dealing with specific data sets that require further statistical modification to undertake sensible analysis. Following topics are discussed:

Survival Analysis

This sub-chapter explains how to conduct sound survival analysis in mlr3. Survival analysis is used to monitor the period of time until a specific event takes places. This specific event could be e.g. death, transmission of a disease, marriage or divorce. Two considerations are important when conducting survival analysis:

• Whether the event occurred within the frame of the given data
• How much time it took until the event occurred

In summary, this sub-chapter explains how to account for these considerations and conduct survival analysis using the mlr3proba extension package.

Density Estimation

This sub-chapter explains how to conduct (unconditional) density estimation in mlr3. Density estimation is used to estimate the probability density function of a continuous variable. Unconditional density estimation is an unsupervised task so there is no ‘value’ to predict, instead densities are estimated.

This sub-chapter explains how to estimate probability distributions for continuous variables using the mlr3proba extension package.

Spatiotemporal Analysis

Spatiotemporal analysis data observations entail reference information about spatial and temporal characteristics. One of the largest issues of spatiotemporal data analysis is the inevitable presence of auto-correlation in the data. Auto-correlation is especially severe in data with marginal spatiotemporal variation. The sub-chapter on Spatiotemporal analysis provides instructions on how to account for spatiotemporal data.

Ordinal Analysis

This is work in progress. See mlr3ordinal for the current state.

Functional Analysis

Functional analysis contains data that consists of curves varying over a continuum e.g. time, frequency or wavelength. This type of analysis is frequently used when examining measurements over various time points. Steps on how to accommodate functional data structures in mlr3 are explained in the functional analysis sub-chapter.

Multilabel Classification

Multilabel classification deals with objects that can belong to more than one category at the same time. Numerous target labels are attributed to a single observation. Working with multilabel data requires one to use modified algorithms, to accommodate data specific characteristics. Two approaches to multilabel classification are prominently used:

• The problem transformation method

Instructions on how to deal with multilabel classification in mlr3 can be found in this sub-chapter.

Cost Sensitive Classification

This sub-chapter deals with the implementation of cost-sensitive classification. Regular classification aims to minimize the misclassification rate and thus all types of misclassification errors are deemed equally severe. Cost-sensitive classification is a setting where the costs caused by different kinds of errors are not assumed to be equal. The objective is to minimize the expected costs.

Analytical data for a big credit institution is used as a use case to illustrate the different features. Firstly, the sub-chapter provides guidance on how to implement a first model. Subsequently, the sub-chapter contains instructions on how to modify cost sensitivity measures, thresholding and threshold tuning.

Cluster Analysis

Cluster analysis aims to group data into clusters such that objects that are similar end up in the same cluster.
Fundamentally, clustering and classification are similar. However, clustering is an unsupervised task because observations do not contain true labels while in classification, labels are needed in order to train a model.

This sub-chapter explains how to perform cluster analysis in mlr3 with the help of mlr3cluster extension package.

## 8.1 Survival Analysis

Survival analysis is a sub-field of supervised machine learning in which the aim is to predict the survival distribution of a given individual. Arguably the main feature of survival analysis is that unlike classification and regression, learners are trained on two features:

1. the time until the event takes place
2. the event type: either censoring or death.

At a particular time-point, an individual is either: alive, dead, or censored. Censoring occurs if it is unknown if an individual is alive or dead. For example, say we are interested in patients in hospital and every day it is recorded if they are alive or dead, then after a patient leaves it is unknown if they are alive or dead, hence they are censored. If there was no censoring, then ordinary regression analysis could be used instead. Furthermore, survival data contains solely positive values and therefore needs to be transformed to avoid biases.

Note that survival analysis accounts for both censored and uncensored observations while adjusting respective model parameters.

The package mlr3proba extends mlr3 with the following objects for survival analysis:

For a good introduction to survival analysis see Modelling Survival Data in Medical Research .

Unlike TaskClassif and TaskRegr which have a single ‘target’ argument, TaskSurv mimics the survival::Surv object and has three-four target arguments (dependent on censoring type). A TaskSurv can be constructed with the function as_task_surv():

library("mlr3")
library("mlr3proba")
library("survival")

time = "start", time2 = "stop", type = "interval")
## <TaskSurv:interval_censored> (178 x 7)
## * Target: start, stop, event
## * Properties: -
## * Features (4):
##   - dbl (2): enum, rx
##   - int (2): number, size
# type = "right" is default
time = "time", event = "status", type = "right")

print(task)
## <TaskSurv:right_censored> (300 x 5)
## * Target: time, status
## * Properties: -
## * Features (3):
##   - int (1): litter
##   - dbl (1): rx
##   - chr (1): sex
# the target column is a survival object:
head(task$truth()) ## [1] 101+ 49 104+ 91+ 104+ 102+ # kaplan-meier plot library("mlr3viz") autoplot(task) ## Registered S3 method overwritten by 'GGally': ## method from ## +.gg ggplot2 ### 8.1.2 Predict Types - crank, lp, and distr Every PredictionSurv object can predict one or more of: • lp - Linear predictor calculated as the fitted coefficients multiplied by the test data. • distr - Predicted survival distribution, either discrete or continuous. Implemented in distr6. • crank - Continuous risk ranking. lp and crank can be used with measures of discrimination such as the concordance index. Whilst lp is a specific mathematical prediction, crank is any continuous ranking that identifies who is more or less likely to experience the event. So far the only implemented learner that only returns a continuous ranking is surv.svm. If a PredictionSurv returns an lp then the crank is identical to this. Otherwise crank is calculated as the expectation of the predicted survival distribution. Note that for linear proportional hazards models, the ranking (but not necessarily the crank score itself) given by lp and the expectation of distr, is identical. The example below uses the rats task shipped with mlr3proba. task = tsk("rats") learn = lrn("surv.coxph") train_set = sample(task$nrow, 0.8 * task$nrow) test_set = setdiff(seq_len(task$nrow), train_set)

learn$train(task, row_ids = train_set) prediction = learn$predict(task, row_ids = test_set)

print(prediction)
## <PredictionSurv> for 60 observations:
##     row_ids time status   crank      lp     distr
##           6  102  FALSE -3.1870 -3.1870 <list[1]>
##          10   91  FALSE -2.2719 -2.2719 <list[1]>
##          17   62  FALSE -3.1621 -3.1621 <list[1]>
## ---
##         291  104  FALSE  0.2882  0.2882 <list[1]>
##         297   79   TRUE  0.3007  0.3007 <list[1]>
##         299  104  FALSE -2.5765 -2.5765 <list[1]>

### 8.1.3 Composition

Finally we take a look at the PipeOps implemented in mlr3proba, which are used for composition of predict types. For example, a predict linear predictor does not have a lot of meaning by itself, but it can be composed into a survival distribution. See mlr3pipelines for full tutorials and details on PipeOps.

library("mlr3pipelines")
library("mlr3learners")
# PipeOpDistrCompositor - Train one model with a baseline distribution,
# (Kaplan-Meier or Nelson-Aalen), and another with a predicted linear predictor.
# remove the factor column for support with glmnet
task$select(c("litter", "rx")) learner_lp = lrn("surv.glmnet") learner_distr = lrn("surv.kaplan") prediction_lp = learner_lp$train(task)$predict(task) prediction_distr = learner_distr$train(task)$predict(task) prediction_lp$distr

# Doesn't need training. Base = baseline distribution. ph = Proportional hazards.

pod = po("compose_distr", form = "ph", overwrite = FALSE)
prediction = pod$predict(list(base = prediction_distr, pred = prediction_lp))$output

# Now we have a predicted distr!

prediction$distr # This can all be simplified by using the distrcompose pipeline glm.distr = ppl("distrcompositor", learner = lrn("surv.glmnet"), estimator = "kaplan", form = "ph", overwrite = FALSE, graph_learner = TRUE) glm.distr$train(task)$predict(task) ### 8.1.4 Benchmark Experiment Finally, we conduct a small benchmark study on the rats task using some of the integrated survival learners: library("mlr3learners") task = tsk("rats") # some integrated learners learners = lrns(c("surv.coxph", "surv.kaplan", "surv.ranger")) print(learners) ## [[1]] ## <LearnerSurvCoxPH:surv.coxph> ## * Model: - ## * Parameters: list() ## * Packages: survival, distr6 ## * Predict Type: distr ## * Feature types: logical, integer, numeric, factor ## * Properties: weights ## ## [[2]] ## <LearnerSurvKaplan:surv.kaplan> ## * Model: - ## * Parameters: list() ## * Packages: survival, distr6 ## * Predict Type: crank ## * Feature types: logical, integer, numeric, character, factor, ordered ## * Properties: missings ## ## [[3]] ## <LearnerSurvRanger:surv.ranger> ## * Model: - ## * Parameters: num.threads=1 ## * Packages: ranger ## * Predict Type: distr ## * Feature types: logical, integer, numeric, character, factor, ordered ## * Properties: importance, oob_error, weights # Harrell's C-Index for survival measure = msr("surv.cindex") print(measure) ## <MeasureSurvCindex:surv.harrell_c> ## * Packages: - ## * Range: [0, 1] ## * Minimize: FALSE ## * Parameters: list() ## * Properties: - ## * Predict type: crank ## * Return type: Score set.seed(1) bmr = benchmark(benchmark_grid(task, learners, rsmp("cv", folds = 3))) bmr$aggregate(measure)
##    nr      resample_result task_id  learner_id resampling_id iters
## 1:  1 <ResampleResult[20]>    rats  surv.coxph            cv     3
## 2:  2 <ResampleResult[20]>    rats surv.kaplan            cv     3
## 3:  3 <ResampleResult[20]>    rats surv.ranger            cv     3
##    surv.harrell_c
## 1:         0.7671
## 2:         0.5000
## 3:         0.7737
autoplot(bmr, measure = measure)

The experiment indicates that both the Cox PH and the random forest have better discrimination than the Kaplan-Meier baseline estimator, but that the machine learning random forest is not consistently better than the interpretable Cox PH.

## 8.2 Density Estimation

Density estimation is the learning task to find the unknown distribution from which an i.i.d. data set is generated. We interpret this broadly, with this distribution not necessarily being continuous (so may possess a mass not density). The conditional case, where a distribution is predicted conditional on covariates, is known as ‘probabilistic supervised regression’, and will be implemented in mlr3proba in the near-future. Unconditional density estimation is viewed as an unsupervised task. For a good overview to density estimation see Density estimation for statistics and data analysis .

The package mlr3proba extends mlr3 with the following objects for density estimation:

In this example we demonstrate the basic functionality of the package on the faithful data from the datasets package. This task ships as pre-defined TaskDens with mlr3proba.

library("mlr3")
library("mlr3proba")

print(task)
## <TaskDens:precip> (70 x 1)
## * Target: -
## * Properties: -
## * Features (1):
##   - dbl (1): precip
# histogram and density plot
library("mlr3viz")
autoplot(task, type = "overlay")
## stat_bin() using bins = 30. Pick better value with binwidth.

Unconditional density estimation is an unsupervised method. Hence, TaskDens is an unsupervised task which inherits directly from Task unlike TaskClassif and TaskRegr. However, TaskDens still has a target argument and a $truth field defined by: • target - the name of the variable in the data for which to estimate density • $truth - the values of the target column (which is not the true density, which is always unknown)

### 8.2.1 Train and Predict

Density learners have train and predict methods, though being unsupervised, ‘prediction’ is actually ‘estimation’. In training, a distr6 object is created, see here for full tutorials on how to access the probability density function, pdf, cumulative distribution function, cdf, and other important fields and methods. The predict method is simply a wrapper around self$model$pdf and if available self$model$cdf, i.e. evaluates the pdf/cdf at given points. Note that in prediction the points to evaluate the pdf and cdf are determined by the target column in the TaskDens object used for testing.

# create task and learner

task_faithful = TaskDens$new(id = "eruptions", backend = datasets::faithful$eruptions)
learner = lrn("dens.hist")

# train/test split
train_set = sample(task_faithful$nrow, 0.8 * task_faithful$nrow)
test_set = setdiff(seq_len(task_faithful$nrow), train_set) # fitting KDE and model inspection learner$train(task_faithful, row_ids = train_set)
learner$model ##$distr
## Histogram()
##
## $hist ##$breaks
## [1] 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5
##
## $counts ## [1] 39 30 5 7 22 59 52 3 ## ##$density
## [1] 0.35945 0.27650 0.04608 0.06452 0.20276 0.54378 0.47926 0.02765
##
## $mids ## [1] 1.75 2.25 2.75 3.25 3.75 4.25 4.75 5.25 ## ##$xname
## [1] "dat"
##
## $equidist ## [1] TRUE ## ## attr(,"class") ## [1] "histogram" ## ## attr(,"class") ## [1] "dens.hist" class(learner$model)
## [1] "dens.hist"
# make predictions for new data
prediction = learner$predict(task_faithful, row_ids = test_set) Every PredictionDens object can estimate: • pdf - probability density function Some learners can estimate: • cdf - cumulative distribution function ### 8.2.2 Benchmark Experiment Finally, we conduct a small benchmark study on the precip task using some of the integrated survival learners: # some integrated learners learners = lrns(c("dens.hist", "dens.kde")) print(learners) ## [[1]] ## <LearnerDensHistogram:dens.hist> ## * Model: - ## * Parameters: list() ## * Packages: distr6 ## * Predict Type: pdf ## * Feature types: integer, numeric ## * Properties: - ## ## [[2]] ## <LearnerDensKDE:dens.kde> ## * Model: - ## * Parameters: kernel=Epan, bandwidth=silver ## * Packages: distr6 ## * Predict Type: pdf ## * Feature types: integer, numeric ## * Properties: missings # Logloss for probabilistic predictions measure = msr("dens.logloss") print(measure) ## <MeasureDensLogloss:dens.logloss> ## * Packages: - ## * Range: [0, Inf] ## * Minimize: TRUE ## * Parameters: list() ## * Properties: - ## * Predict type: pdf set.seed(1) bmr = benchmark(benchmark_grid(task, learners, rsmp("cv", folds = 3))) bmr$aggregate(measure)
##    nr      resample_result task_id learner_id resampling_id iters dens.logloss
## 1:  1 <ResampleResult[20]>  precip  dens.hist            cv     3        4.396
## 2:  2 <ResampleResult[20]>  precip   dens.kde            cv     3        4.818
autoplot(bmr, measure = measure)

The results of this experiment show that the sophisticated Penalized Density Estimator does not outperform the baseline Histogram, but that the Kernel Density Estimator has at least consistently better (i.e. lower logloss) results.

## 8.3 Spatiotemporal Analysis

Data observations may entail reference information about spatial or temporal characteristics. Spatial information is stored as coordinates, usually named “x” and “y” or “lat”/“lon”. Treating spatiotemporal data using non-spatial data methods can lead to over-optimistic performance estimates. Hence, methods specifically designed to account for the special nature of spatiotemporal data are needed.

In the mlr3 framework, the following packages relate to this field:

The following (sub-)sections introduce the potential pitfalls of spatiotemporal data in machine learning and how to account for it. Note that not all functionality will be covered, and that some of the used packages are still in early lifecycles. If you want to contribute to one of the packages mentioned above, please contact Patrick Schratz.

### 8.3.1 Creating a spatial Task

To make use of spatial resampling methods, a {mlr3} task that is aware of its spatial characteristic needs to be created. Two child classes exist in {mlr3spatiotempcv} for this purpose:

• TaskClassifST
• TaskRegrST

To create one of these, one can either pass a sf object as the “backend” directly:

# create 'sf' object
data_sf = sf::st_as_sf(ecuador, coords = c("x", "y"), crs = 32717)
task = TaskClassifST$new("ecuador_sf", backend = data_sf, target = "slides", positive = "TRUE" ) or use a plain data.frame. In this case, the constructor of TaskClassifST needs a few more arguments: data = mlr3::as_data_backend(ecuador) task = TaskClassifST$new("ecuador",
backend = data, target = "slides",
positive = "TRUE", extra_args = list(coordinate_names = c("x", "y"),
crs = 32717)
)

Now this Task can be used as a normal {mlr3} task in any kind of modeling scenario.

### 8.3.2 Autocorrelation

Data which includes spatial or temporal information requires special treatment in machine learning (similar to survival, ordinal and other task types listed in the special tasks chapter). In contrast to non-spatial/non-temporal data, observations inherit a natural grouping, either in space or time or in both space and time . This grouping causes observations to be autocorrelated, either in space (spatial autocorrelation (SAC)), time (temporal autocorrelation (TAC)) or both space and time (spatiotemporal autocorrelation (STAC)). For simplicity, the acronym STAC is used as a generic term in the following chapter for all the different characteristics introduced above.

What effects does STAC have in statistical/machine learning?

The overarching problem is that STAC violates the assumption that the observations in the train and test datasets are independent . If this assumption is violated, the reliability of the resulting performance estimates, for example retrieved via cross-validation, is decreased. The magnitude of this decrease is linked to the magnitude of STAC in the dataset, which cannot be determined easily.

One approach to account for the existence of STAC is to use dedicated resampling methods. mlr3spatiotemporal provides access to the most frequently used spatiotemporal resampling methods. The following example showcases how a spatial dataset can be used to retrieve a bias-reduced performance estimate of a learner.

The following examples use the ecuador dataset created by Jannes Muenchow. It contains information on the occurrence of landslides (binary) in the Andes of Southern Ecuador. The landslides were mapped from aerial photos taken in 2000. The dataset is well suited to serve as an example because it it relatively small and of course due to the spatial nature of the observations. Please refer to Muenchow, Brenning, and Richter (2012) for a detailed description of the dataset.

To account for the spatial autocorrelation probably present in the landslide data, we will make use one of the most used spatial partitioning methods, a cluster-based k-means grouping , ("spcv_coords" in mlr3spatiotemporal). This method performs a clustering in 2D space which contrasts with the commonly used random partitioning for non-spatial data. The grouping has the effect that train and test data are more separated in space as they would be by conducting a random partitioning, thereby reducing the effect of STAC.

By contrast, when using the classical random partitioning approach with spatial data, train and test observations would be located side-by-side across the full study area (a visual example is provided further below). This leads to a high similarity between train and test sets, resulting in “better” but biased performance estimates in every fold of a CV compared to the spatial CV approach. However, these low error rates are mainly caused due to the STAC in the observations and the lack of appropriate partitioning methods and not by the power of the fitted model.

### 8.3.3 Spatial CV vs. Non-Spatial CV

In the following a spatial and a non-spatial CV will be conducted to showcase the mentioned performance differences.

The performance of a simple classification tree ("classif.rpart") is evaluated on a random partitioning ("repeated_cv") with four folds and two repetitions. The chosen evaluation measure is “classification error” ("classif.ce"). The only difference in the spatial setting is that "repeated_spcv_coords" is chosen instead of "repeated_cv".

#### 8.3.3.1 Non-Spatial CV

library("mlr3")
library("mlr3spatiotempcv")
set.seed(42)

# be less verbose
lgr::get_logger("bbotk")$set_threshold("warn") lgr::get_logger("mlr3")$set_threshold("warn")

learner = lrn("classif.rpart", maxdepth = 3, predict_type = "prob")
resampling_nsp = rsmp("repeated_cv", folds = 4, repeats = 2)
rr_nsp = resample(
resampling = resampling_nsp)

rr_nsp$aggregate(measures = msr("classif.ce")) ## classif.ce ## 0.3389 #### 8.3.3.2 Spatial CV task = tsk("ecuador") learner = lrn("classif.rpart", maxdepth = 3, predict_type = "prob") resampling_sp = rsmp("repeated_spcv_coords", folds = 4, repeats = 2) rr_sp = resample( task = task, learner = learner, resampling = resampling_sp) rr_sp$aggregate(measures = msr("classif.ce"))
## classif.ce
##     0.4125

Here, the classification tree learner is around 0.05 percentage points worse when using Spatial Cross-Validation (SpCV) compared to Non-Spatial Cross-Validation (NSpCV). The magnitude of this difference is variable as it depends on the dataset, the magnitude of STAC and the learner itself. For algorithms with a higher tendency of overfitting to the training set, the difference between the two methods will be larger.

### 8.3.4 Visualization of Spatiotemporal Partitions

Every partitioning method in mlr3spatiotemporal comes with a generic plot() method to visualize the created groups. In a 2D space this happens via ggplot2 while for spatiotemporal methods 3D visualizations via plotly are created.

autoplot(resampling_sp, task, fold_id = c(1:4), size = 0.7) *
ggplot2::scale_y_continuous(breaks = seq(-3.97, -4, -0.01)) *
ggplot2::scale_x_continuous(breaks = seq(-79.06, -79.08, -0.01))

Note that setting the correct CRS for the given data is important which is done during task creation Spatial offsets of up to multiple meters may occur if the wrong CRS is supplied initially.

This example used an already created task via the sugar function tsk(). In practice however, one needs to create a spatiotemporal task via TaskClassifST()/TaskRegrST() and set the crs argument.

The spatial grouping of the k-means based approach above contrasts visually ver well compared to the NSpCV (random) partitioning:

autoplot(resampling_nsp, task, fold_id = c(1:4), size = 0.7) *
ggplot2::scale_y_continuous(breaks = seq(-3.97, -4, -0.01)) *
ggplot2::scale_x_continuous(breaks = seq(-79.06, -79.08, -0.01))

### 8.3.5 Spatial Block Visualization

The spcv-block method makes use of rectangular blocks to divide the study area into equally-sized parts. These blocks can be visualized by their spatial location and fold ID to get a better understanding how these influenced the final partitions.

task = tsk("ecuador")
resampling = rsmp("spcv_block", range = 1000L)
resampling$instantiate(task) ## Visualize train/test splits of multiple folds autoplot(resampling, task, size = 0.7, fold_id = c(1, 2), show_blocks = TRUE, show_labels = TRUE) * ggplot2::scale_x_continuous(breaks = seq(-79.085, -79.055, 0.01)) ### 8.3.6 Choosing a Resampling Method While the example used the "spcv_coords" method, this does not mean that this method is the best or only method suitable for this task. Even though this method is quite popular, it was mainly chosen because of the clear visual grouping differences compared to random partitioning. In fact, most often multiple spatial partitioning methods can be used for a dataset. It is recommended (required) that users familiarize themselves with each implemented method and decide which method to choose based on the specific characteristics of the dataset. For almost all methods implemented in mlr3spatiotemporal, there is a scientific publication describing the strengths and weaknesses of the respective approach (either linked in the help file of mlr3spatiotemporal or its respective dependency packages). In the example above, a cross-validation without hyperparameter tuning was shown. If a nested CV is desired, it is recommended to use the same spatial partitioning method for the inner loop (= tuning level). See Schratz et al. (2019) for more details and chapter 11 of Geocomputation with R 3. A list of all implemented methods in mlr3spatiotemporal can be found in the Getting Started vignette of the package. If you want to learn even more about the field of spatial partitioning, STAC and the problems associated with it, the work of Prof. Hanna Meyer is very much recommended for further reference. ### 8.3.7 Spatial Prediction Experimental support for spatial prediction with terra, raster, stars and sf objects is available in mlr3spatial. Until the package is released on CRAN, please see the package vignettes for usage examples. ## 8.4 Ordinal Analysis This is work in progress. See mlr3ordinal for the current state of the implementation. ## 8.5 Functional Analysis Functional data is data containing an ordering on the dimensions. This implies that functional data consists of curves varying over a continuum, such as time, frequency, or wavelength. ### 8.5.1 How to model functional data? There are two ways to model functional data: • Modification of the learner, so that the learner is suitable for the functional data • Modification of the task, so that the task matches the standard- or classification-learner The development has not started yet, we are looking for contributors. Open an issue in mlr3fda if you are interested! ## 8.6 Multilabel Classification Multilabel classification deals with objects that can belong to more than one category at the same time. The development has not started yet, we are looking for contributes. Open an issue in mlr3multioutput if you are interested! ## 8.7 Cost-Sensitive Classification In regular classification the aim is to minimize the misclassification rate and thus all types of misclassification errors are deemed equally severe. A more general setting is cost-sensitive classification. Cost sensitive classification does not assume that the costs caused by different kinds of errors are equal. The objective of cost sensitive classification is to minimize the expected costs. Imagine you are an analyst for a big credit institution. Let’s also assume that a correct decision of the bank would result in 35% of the profit at the end of a specific period. A correct decision means that the bank predicts that a customer will pay their bills (hence would obtain a loan), and the customer indeed has good credit. On the other hand, a wrong decision means that the bank predicts that the customer’s credit is in good standing, but the opposite is true. This would result in a loss of 100% of the given loan. Good Customer (truth) Bad Customer (truth) Good Customer (predicted) + 0.35 - 1.0 Bad Customer (predicted) 0 0 Expressed as costs (instead of profit), we can write down the cost-matrix as follows: costs = matrix(c(-0.35, 0, 1, 0), nrow = 2) dimnames(costs) = list(response = c("good", "bad"), truth = c("good", "bad")) print(costs) ## truth ## response good bad ## good -0.35 1 ## bad 0.00 0 An exemplary data set for such a problem is the German Credit task: library("mlr3") task = tsk("german_credit") table(task$truth())
##
##  700  300

The data has 70% customers who are able to pay back their credit, and 30% bad customers who default on the debt. A manager, who doesn’t have any model, could decide to give either everybody a credit or to give nobody a credit. The resulting costs for the German credit data are:

# nobody:
(700 * costs[2, 1] + 300 * costs[2, 2]) / 1000
## [1] 0
# everybody
(700 * costs[1, 1] + 300 * costs[1, 2]) / 1000
## [1] 0.055

If the average loan is $20,000, the credit institute would lose more than one million dollar if it would grant everybody a credit: # average profit * average loan * number of customers 0.055 * 20000 * 1000 ## [1] 1100000 Our goal is to find a model which minimizes the costs (and thereby maximizes the expected profit). ### 8.7.1 A First Model For our first model, we choose an ordinary logistic regression (implemented in the add-on package mlr3learners). We first create a classification task, then resample the model using a 10-fold cross validation and extract the resulting confusion matrix: library("mlr3learners") learner = lrn("classif.log_reg") rr = resample(task, learner, rsmp("cv")) confusion = rr$prediction()$confusion print(confusion) ## truth ## response good bad ## good 598 156 ## bad 102 144 To calculate the average costs like above, we can simply multiply the elements of the confusion matrix with the elements of the previously introduced cost matrix, and sum the values of the resulting matrix: avg_costs = sum(confusion * costs) / 1000 print(avg_costs) ## [1] -0.0533 With an average loan of$20,000, the logistic regression yields the following costs:

avg_costs * 20000 * 1000
## [1] -1066000

Instead of losing over $1,000,000, the credit institute now can expect a profit of more than$1,000,000.

### 8.7.2 Cost-sensitive Measure

Our natural next step would be to further improve the modeling step in order to maximize the profit. For this purpose we first create a cost-sensitive classification measure which calculates the costs based on our cost matrix. This allows us to conveniently quantify and compare modeling decisions. Fortunately, there already is a predefined measure Measure for this purpose: MeasureClassifCosts:

cost_measure = msr("classif.costs", costs = costs)
print(cost_measure)
## <MeasureClassifCosts:classif.costs>
## * Packages: -
## * Range: [-Inf, Inf]
## * Minimize: TRUE
## * Parameters: normalize=TRUE
## * Predict type: response

If we now call resample() or benchmark(), the cost-sensitive measures will be evaluated. We compare the logistic regression to a simple featureless learner and to a random forest from package ranger :

learners = list(
lrn("classif.log_reg"),
lrn("classif.featureless"),
lrn("classif.ranger")
)
cv3 = rsmp("cv", folds = 3)
bmr$aggregate(cost_measure) ## nr resample_result task_id learner_id resampling_id ## 1: 1 <ResampleResult[20]> german_credit classif.log_reg cv ## 2: 2 <ResampleResult[20]> german_credit classif.featureless cv ## 3: 3 <ResampleResult[20]> german_credit classif.ranger cv ## iters classif.costs ## 1: 3 -0.06014 ## 2: 3 0.05502 ## 3: 3 -0.04792 As expected, the featureless learner is performing comparably bad. The logistic regression and the random forest work equally well. ### 8.7.3 Thresholding Although we now correctly evaluate the models in a cost-sensitive fashion, the models themselves are unaware of the classification costs. They assume the same costs for both wrong classification decisions (false positives and false negatives). Some learners natively support cost-sensitive classification (e.g., XXX). However, we will concentrate on a more generic approach which works for all models which can predict probabilities for class labels: thresholding. Most learners can calculate the probability $$p$$ for the positive class. If $$p$$ exceeds the threshold $$0.5$$, they predict the positive class, and the negative class otherwise. For our binary classification case of the credit data, the we primarily want to minimize the errors where the model predicts “good”, but truth is “bad” (i.e., the number of false positives) as this is the more expensive error. If we now increase the threshold to values $$> 0.5$$, we reduce the number of false negatives. Note that we increase the number of false positives simultaneously, or, in other words, we are trading false positives for false negatives. # fit models with probability prediction learner = lrn("classif.log_reg", predict_type = "prob") rr = resample(task, learner, rsmp("cv")) p = rr$prediction()
print(p)
## <PredictionClassif> for 1000 observations:
##     row_ids truth response prob.good prob.bad
##          29  good     good    0.9125  0.08754
## ---
##         965  good      bad    0.4222  0.57780
##         987  good      bad    0.1881  0.81189
##         988  good     good    0.9511  0.04886
# helper function to try different threshold values interactively
with_threshold = function(p, th) {
p$set_threshold(th) list(confusion = p$confusion, costs = p$score(measures = cost_measure, task = task)) } with_threshold(p, 0.5) ##$confusion
##         truth
##     good  603 155
##
## $costs ## classif.costs ## -0.05605 with_threshold(p, 0.75) ##$confusion
##         truth
##     good  468  77
##
## $costs ## classif.costs ## -0.0868 with_threshold(p, 1.0) ##$confusion
##         truth
##     good    0   1
##
## $costs ## classif.costs ## 0.001 # TODO: include plot of threshold vs performance Instead of manually trying different threshold values, one uses use optimize() to find a good threshold value w.r.t. our performance measure: # simple wrapper function which takes a threshold and returns the resulting model performance # this wrapper is passed to optimize() to find its minimum for thresholds in [0.5, 1] f = function(th) { with_threshold(p, th)$costs
}
best = optimize(f, c(0.5, 1))
print(best)
## $minimum ## [1] 0.7411 ## ##$objective
## classif.costs
##      -0.08895
# optimized confusion matrix:
with_threshold(p, best$minimum)$confusion
##         truth
##     good  477  78
##     bad   223 222

Note that the function optimize() is intended for unimodal functions and therefore may converge to a local optimum here. See below for better alternatives to find good threshold values.

### 8.7.4 Threshold Tuning

Before we start, we have load all required packages:

library("mlr3")
library("mlr3pipelines")
library("mlr3tuning")
## Loading required package: paradox

### 8.7.5 Adjusting thresholds: Two strategies

Currently mlr3pipelines offers two main strategies towards adjusting classification thresholds. We can either expose the thresholds as a hyperparameter of the Learner by using PipeOpThreshold. This allows us to tune the thresholds via an outside optimizer from mlr3tuning.

Alternatively, we can also use PipeOpTuneThreshold which automatically tunes the threshold after each learner is fit.

In this blog-post, we’ll go through both strategies.

### 8.7.6 PipeOpThreshold

PipeOpThreshold can be put directly after a Learner.

A simple example would be:

gr = lrn("classif.rpart", predict_type = "prob") %>>% po("threshold")
l = as_learner(gr)

Note, that predict_type = “prob” is required for po("threshold") to have any effect.

The thresholds are now exposed as a hyperparameter of the GraphLearner we created:

l$param_set ## <ParamSetCollection> ## id class lower upper nlevels default ## 1: classif.rpart.cp ParamDbl 0 1 Inf 0.01 ## 2: classif.rpart.keep_model ParamLgl NA NA 2 FALSE ## 3: classif.rpart.maxcompete ParamInt 0 Inf Inf 4 ## 4: classif.rpart.maxdepth ParamInt 1 30 30 30 ## 5: classif.rpart.maxsurrogate ParamInt 0 Inf Inf 5 ## 6: classif.rpart.minbucket ParamInt 1 Inf Inf <NoDefault[3]> ## 7: classif.rpart.minsplit ParamInt 1 Inf Inf 20 ## 8: classif.rpart.surrogatestyle ParamInt 0 1 2 0 ## 9: classif.rpart.usesurrogate ParamInt 0 2 3 2 ## 10: classif.rpart.xval ParamInt 0 Inf Inf 10 ## 11: threshold.thresholds ParamUty NA NA Inf <NoDefault[3]> ## value ## 1: ## 2: ## 3: ## 4: ## 5: ## 6: ## 7: ## 8: ## 9: ## 10: 0 ## 11: 0.5 We can now tune those thresholds from the outside as follows: Before tuning, we have to define which hyperparameters we want to tune over. In this example, we only tune over the thresholds parameter of the threshold pipeop. you can easily imagine, that we can also jointly tune over additional hyperparameters, i.e. rpart’s cp parameter. As the Task we aim to optimize for is a binary task, we can simply specify the threshold param: library("paradox") ps = ps(threshold.thresholds = p_dbl(lower = 0, upper = 1)) We now create a AutoTuner, which automatically tunes the supplied learner over the ParamSet we supplied above. at = AutoTuner$new(
learner = l,
resampling = rsmp("cv", folds = 3L),
measure = msr("classif.ce"),
search_space = ps,
terminator = trm("evals", n_evals = 5L),
tuner = tnr("random_search")
)

at$train(tsk("german_credit")) ## INFO [09:57:40.254] [bbotk] Starting to optimize 1 parameter(s) with '<OptimizerRandomSearch>' and '<TerminatorEvals> [n_evals=5, k=0]' ## INFO [09:57:40.300] [bbotk] Evaluating 1 configuration(s) ## INFO [09:57:40.651] [bbotk] Result of batch 1: ## INFO [09:57:40.653] [bbotk] threshold.thresholds classif.ce runtime_learners ## INFO [09:57:40.653] [bbotk] 0.2554 0.288 0.186 ## INFO [09:57:40.653] [bbotk] uhash ## INFO [09:57:40.653] [bbotk] 43270072-7e63-4372-9c9f-518bc558d851 ## INFO [09:57:40.656] [bbotk] Evaluating 1 configuration(s) ## INFO [09:57:41.014] [bbotk] Result of batch 2: ## INFO [09:57:41.016] [bbotk] threshold.thresholds classif.ce runtime_learners ## INFO [09:57:41.016] [bbotk] 0.04085 0.301 0.168 ## INFO [09:57:41.016] [bbotk] uhash ## INFO [09:57:41.016] [bbotk] 0c978bb4-d125-4e67-bf76-e33d56edc7a0 ## INFO [09:57:41.019] [bbotk] Evaluating 1 configuration(s) ## INFO [09:57:41.335] [bbotk] Result of batch 3: ## INFO [09:57:41.337] [bbotk] threshold.thresholds classif.ce runtime_learners ## INFO [09:57:41.337] [bbotk] 0.6273 0.287 0.178 ## INFO [09:57:41.337] [bbotk] uhash ## INFO [09:57:41.337] [bbotk] 825dc589-505d-4056-b0ee-681e02b72299 ## INFO [09:57:41.340] [bbotk] Evaluating 1 configuration(s) ## INFO [09:57:41.656] [bbotk] Result of batch 4: ## INFO [09:57:41.658] [bbotk] threshold.thresholds classif.ce runtime_learners ## INFO [09:57:41.658] [bbotk] 0.2061 0.291 0.172 ## INFO [09:57:41.658] [bbotk] uhash ## INFO [09:57:41.658] [bbotk] ff3c4a0a-ea59-45d0-9592-15330bbf2aec ## INFO [09:57:41.661] [bbotk] Evaluating 1 configuration(s) ## INFO [09:57:41.972] [bbotk] Result of batch 5: ## INFO [09:57:41.974] [bbotk] threshold.thresholds classif.ce runtime_learners ## INFO [09:57:41.974] [bbotk] 0.9274 0.688 0.171 ## INFO [09:57:41.974] [bbotk] uhash ## INFO [09:57:41.974] [bbotk] 2625beca-03bb-4f01-98e6-d6a49a008cf5 ## INFO [09:57:41.983] [bbotk] Finished optimizing after 5 evaluation(s) ## INFO [09:57:41.984] [bbotk] Result: ## INFO [09:57:41.985] [bbotk] threshold.thresholds learner_param_vals x_domain classif.ce ## INFO [09:57:41.985] [bbotk] 0.6273 <list[2]> <list[1]> 0.287 Inside the trafo, we simply collect all set params into a named vector via map_dbl and store it in the threshold.thresholds slot expected by the learner. Again, we create a AutoTuner, which automatically tunes the supplied learner over the ParamSet we supplied above. One drawback of this strategy is, that this requires us to fit a new model for each new threshold setting. While setting a threshold and computing performance is relatively cheap, fitting the learner is often more computationally demanding. A better strategy is therefore often to optimize the thresholds separately after each model fit. ### 8.7.7 PipeOpTunethreshold PipeOpTuneThreshold on the other hand works together with PipeOpLearnerCV. It directly optimizes the cross-validated predictions made by this PipeOp. This is done in order to avoid over-fitting the threshold tuning. A simple example would be: gr = po("learner_cv", lrn("classif.rpart", predict_type = "prob")) %>>% po("tunethreshold") l2 = as_learner(gr) Note, that predict_type = “prob” is required for po("tunethreshold") to work. Additionally, note that this time no threshold parameter is exposed, it is automatically tuned internally. l2$param_set
## <ParamSetCollection>
##                                         id    class lower upper nlevels
##  1:        classif.rpart.resampling.method ParamFct    NA    NA       2
##  2:         classif.rpart.resampling.folds ParamInt     2   Inf     Inf
##  3: classif.rpart.resampling.keep_response ParamLgl    NA    NA       2
##  4:                       classif.rpart.cp ParamDbl     0     1     Inf
##  5:               classif.rpart.keep_model ParamLgl    NA    NA       2
##  6:               classif.rpart.maxcompete ParamInt     0   Inf     Inf
##  7:                 classif.rpart.maxdepth ParamInt     1    30      30
##  8:             classif.rpart.maxsurrogate ParamInt     0   Inf     Inf
##  9:                classif.rpart.minbucket ParamInt     1   Inf     Inf
## 10:                 classif.rpart.minsplit ParamInt     1   Inf     Inf
## 11:           classif.rpart.surrogatestyle ParamInt     0     1       2
## 12:             classif.rpart.usesurrogate ParamInt     0     2       3
## 13:                     classif.rpart.xval ParamInt     0   Inf     Inf
## 14:           classif.rpart.affect_columns ParamUty    NA    NA     Inf
## 15:                  tunethreshold.measure ParamUty    NA    NA     Inf
## 16:                tunethreshold.optimizer ParamUty    NA    NA     Inf
## 17:                tunethreshold.log_level ParamUty    NA    NA     Inf
##            default      value
##  1: <NoDefault[3]>         cv
##  2: <NoDefault[3]>          3
##  3: <NoDefault[3]>      FALSE
##  4:           0.01
##  5:          FALSE
##  6:              4
##  7:             30
##  8:              5
##  9: <NoDefault[3]>
## 10:             20
## 11:              0
## 12:              2
## 13:             10          0
## 14:  <Selector[1]>
## 15: <NoDefault[3]> classif.ce
## 16: <NoDefault[3]>      gensa
## 17:  <function[1]>       warn

Note that we can set rsmp("intask") as a resampling strategy for “learner_cv” in order to evaluate predictions on the “training” data. This is generally not advised, as it might lead to over-fitting on the thresholds but can significantly reduce runtime.

For more information, see the post on Threshold Tuning on the mlr3 gallery.

## 8.8 Cluster Analysis

Cluster analysis is a type of unsupervised machine learning where the goal is to group data into clusters, where each cluster contains similar observations. The similarity is based on specified metrics that are task and application dependent. Cluster analysis is closely related to classification in a sense that each observation needs to be assigned to a cluster or a class. However, unlike classification problems where each observation is labeled, clustering works on data sets without true labels or class assignments.

The package mlr3cluster extends mlr3 with the following objects for cluster analysis:

Since clustering is a type of unsupervised learning, TaskClust is slightly different from TaskRegr and TaskClassif objects. More specifically:

• truth() function is missing because observations are not labeled.
• target field is empty and will return character(0) if accessed anyway.

Additionally, LearnerClust provides two extra fields that are absent from supervised learners:

• assignments returns cluster assignments for training data. It return NULL if accessed before training.
• save_assignments is a boolean field that controls whether or not to store training set assignments in a learner.

Finally, PredictionClust contains additional two fields:

• partition stores cluster partitions.
• prob stores cluster probabilities for each observation.

### 8.8.1 Train and Predict

Clustering learners provide both train and predict methods. The analysis typically consists of building clusters using all available data. To be consistent with the rest of the library, we refer to this process as training.

Some learners can assign new observations to existing groups with predict. However, prediction does not always make sense, as it is the case for hierarchical clustering. In hierarchical clustering, the goal is to build a hierarchy of nested clusters by either splitting large clusters into smaller ones or merging smaller clusters into bigger ones. The final result is a tree or dendrogram which can change if a new data point is added. For consistency with the rest of the ecosystem, mlr3cluster offers predict method for hierarchical clusterers but it simply assigns all points to a specified number of clusters by cutting the resulting tree at a corresponding level. Moreover, some learners estimate the probability of each observation belonging to a given cluster. predict_types field gives a list of prediction types for each learner.

After training, the model field stores a learner’s model that looks different for each learner depending on the underlying library. predict returns a PredictionClust object that gives a simplified view of the learned model. If the data given to the predict method is the same as the one on which the learner was trained, predict simply returns cluster assignments for the “training” observations. On the other hand, if the test set contains new data, predict will estimate cluster assignments for that data set. Some learners do not support estimating cluster partitions on new data and will instead return assignments for training data and print a warning message.

In the following example, a $k$-means learner is applied on the US arrest data set. The class labels are predicted and the contribution of the task features to assignment of the respective class are visualized.

library("mlr3")
library("mlr3cluster")
library("mlr3viz")
set.seed(1L)

print(task)
## <TaskClust:usarrests> (50 x 4)
## * Target: -
## * Properties: -
## * Features (4):
##   - int (2): Assault, UrbanPop
##   - dbl (2): Murder, Rape
autoplot(task)
# create a k-means learner
learner = lrn("clust.kmeans")

# assigning each observation to one of the two clusters (default in clust.kmeans)
learner$train(task) learner$model
## K-means clustering with 2 clusters of sizes 21, 29
##
## Cluster means:
##   Assault Murder  Rape UrbanPop
## 1   255.0 11.857 28.11    67.62
## 2   109.8  4.841 16.25    64.03
##
## Clustering vector:
##  [1] 1 1 1 1 1 1 2 1 1 1 2 2 1 2 2 2 2 1 2 1 2 1 2 1 2 2 2 1 2 2 1 1 1 2 2 2 2 2
## [39] 2 1 2 1 1 2 2 2 2 2 2 2
##
## Within cluster sum of squares by cluster:
## [1] 41637 54762
##  (between_SS / total_SS =  72.9 %)
##
## Available components:
##
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
# make "predictions" for the same data
prediction = learner$predict(task) autoplot(prediction, task) ### 8.8.2 Measures The difference between supervised and unsupervised learning is that there is no ground truth data in unsupervised learning. In a supervised setting, such as classification, we would need to compare our predictions to true labels. Since clustering is an example of unsupervised learning, there are no true labels to which we can compare. However, we can still measure the quality of cluster assignments by quantifying how closely objects within the same cluster are related (cluster cohesion) as well as how distinct different clusters are from each other (cluster separation). To assess the quality of clustering, there are a few built-in evaluation metrics available. One of them is within sum of squares (WSS) which calculates the sum of squared differences between observations and centroids. WSS is useful because it quantifies cluster cohesion. The range of this measure is $$[0, \infty)$$ where a smaller value means that clusters are more compact. Another measure is silhouette quality index that quantifies how well each point belongs to its assigned cluster versus neighboring cluster. Silhouette values are in $$[-1, 1]$$ range. Points with silhouette closer to: • 1 are well clustered • 0 lie between two clusters • -1 likely placed in the wrong cluster The following is an example of conducting a benchmark experiment with various learners on iris data set without target variable and assessing the quality of each learner with both within sum of squares and silhouette measures. design = benchmark_grid( tasks = TaskClust$new("iris", iris[-5]),
learners = list(
lrn("clust.kmeans", centers = 3L),
lrn("clust.pam", k = 2L),
lrn("clust.cmeans", centers = 3L)),
resamplings = rsmp("insample"))
print(design)
##               task                  learner               resampling
## 3: <TaskClust[43]> <LearnerClustCMeans[36]> <ResamplingInsample[19]>
# execute benchmark
bmr = benchmark(design)

# define measure
measures = list(msr("clust.wss"), msr("clust.silhouette"))
bmr$aggregate(measures) ## nr resample_result task_id learner_id resampling_id iters clust.wss ## 1: 1 <ResampleResult[20]> iris clust.kmeans insample 1 78.85 ## 2: 2 <ResampleResult[20]> iris clust.pam insample 1 153.33 ## 3: 3 <ResampleResult[20]> iris clust.cmeans insample 1 79.03 ## clust.silhouette ## 1: 0.5555 ## 2: 0.7158 ## 3: 0.5493 The experiment shows that using k-means algorithm with three centers produces a better within sum of squares score than any other learner considered. However, pam (partitioning around medoids) learner with two clusters performs the best when considering silhouette measure which takes into the account both cluster cohesion and separation. ### 8.8.3 Visualization Cluster analysis in mlr3 is integrated with mlr3viz which provides a number of useful plots. Some of those plots are shown below. task = TaskClust$new("iris", iris[-5])
learner = lrn("clust.kmeans")
learner$train(task) prediction = learner$predict(task)

# performing PCA on task and showing assignments
autoplot(prediction, task, type = "pca")
# same as above but with probability ellipse that assumes normal distribution
autoplot(prediction, task, type = "pca", frame = TRUE, frame.type = 'norm')
task = tsk("usarrests")
learner = lrn("clust.agnes")
learner$train(task) # dendrogram for hierarchical clustering autoplot(learner) # advanced dendrogram options from factoextra::fviz_dend autoplot(learner, k = learner$param_set$values$k, rect_fill = TRUE,
rect = TRUE, rect_border = c("red", "cyan"))

Silhouette plots can help to visually assess the quality of the analysis and help choose a number of clusters for a given data set. The red dotted line shows the mean silhouette value and each bar represents a data point. If most points in each cluster have an index around or higher than mean silhouette, the number of clusters is chosen well.

# silhouette plot allows to visually inspect the quality of clustering
task = TaskClust$new("iris", iris[-5]) learner = lrn("clust.kmeans") learner$param_set$values = list(centers = 5L) learner$train(task)
prediction = learner$predict(task) autoplot(prediction, task, type = "sil") The plot shows that all points in cluster 5 and almost all points in clusters 4, 2 and 1 are below average silhouette index. This means that a lot of observations lie either on the border of clusters or are likely assigned to the wrong cluster. learner = lrn("clust.kmeans") learner$param_set$values = list(centers = 2L) learner$train(task)
autoplot(prediction, task, type = "sil")


text:
# Variable inductance problem?

Discussion in 'General Electronics Chat' started by electronice123, Jul 2, 2014.

1. ### electronice123 Thread Starter Senior Member

Oct 10, 2008
304
0
Hi everyone,

I recently made an adjustable inductor using a E core and coil. I adjust the inductance by gapping the core using screws and nuts which I mounted to it. When the core is tight I get an inductance of 5H. The problem is when I turn the 10-32 screw just 1/2 turn the inductance changes by an entire Henry (at that point the gap is only about 2 thousandth of an inch!) The core I am using has an Ae of 225mm^2, a Iu of 2300 and an AL of 3100.

I need the inductance change to be much more precise. I was hoping to get something that I could change the inductance by just a few mH per turn. How can I get more precision out of the inductor?

Last edited: Jul 2, 2014
2. ### wayneh Expert

Sep 9, 2010
12,598
3,409
The screw is adjusting the air gap? The air gap has a very much lower permeability than your core and the gap's size will dominate the calculation of combined permeability, and thus inductance.

3. ### electronice123 Thread Starter Senior Member

Oct 10, 2008
304
0
Yeah the screw is adjusting the air gap.
I have looked into fine thread screws (200TPI) but they get a little pricey. Not only that but they are very delicate and I think the threads would strip easily if the screw and nut were not perfectly aligned.

What I am wondering is if a different size or shape of core would work better? Or any other options I might have to make the inductance more precise when I adjust it.

4. ### alfacliff Well-Known Member

Dec 13, 2013
2,449
428
try moving a magnet near the core while reading the inductance. look up magnetic amplifier, a changing magnetic field in the core can change the inductance. an exgtra winding can supply the magnetic bias to adjust the coil.

5. ### MrAl Distinguished Member

Jun 17, 2014
2,706
556
Hi

What it sounds like you are doing is trying to adjust the gap. That's a standard procedure for adjusting inductance by small factors, but you should realize that this is a very precise parameter that usually has to be measured down to the thousandth of an inch or better. The gap reluctance could be thousands of times higher than the core, and the overall permeability is affected by the ratio of reluctances and distance, so changing the gap by even 0.001 inch could change the inductance twofold or even tenfold, depending on other dimensions.

So your attempt to change the gap is an effective means to change the inductance, but setting that gap to get a specific inductance requires a precise movement on the order of what you would measure using a micrometer.

What helps a little is if you have a core that already has a gap to begin with. That means increasing the gap causes less change per thousandth of an inch than if the core had no gap to begin with.

Removing turns is less problematic but of course this requires physically removing turns, unless you can make a slider with some turns bare on one side so the slider makes contact. This isnt very easy to do either.
If you could make a tapped inductor you could at least have several values to choose from, but of course that's not as variable as changing the gap.

When the whole gap gets changed it changes the magnetic gap by two times, because the flux passes through the gap twice in an EI core. This means lifting only one end could improve the adjustment resolution somewhat, although it is still a precise setting.

Pieces of "I" that are brought close to the gap also will increase the inductance, probably with better resolution. This would mean at least one side would need an additional set of "I' laminations mounted on a movable platform maybe using 4-40 screws or even 2-56 screws for finer adjustment.

electronice123 likes this.
6. ### t_n_k AAC Fanatic!

Mar 6, 2009
5,448
783
I guess one shouldn't be surprised at the outcome. Inductance will be essentially proportional to the inverse of the air gap length for very small airgaps. The anticipated change in inductance ΔL for a small change in gap Δg would be

$\Delta L=-L_o \times \frac {\Delta g }{g }$

where Lo is the inductance with air gap length g.

If Δg is commensurate with g then the effect can be significant.

7. ### umphrey Member

Dec 1, 2012
39
1
What's the current? I would recommend multiple taps with contactors or SCRs.

8. ### Alec_t AAC Fanatic!

Sep 17, 2013
6,053
1,172
If the core is laminated, removing or shifting laminations will perhaps offer less critical adjustment.

9. ### electronice123 Thread Starter Senior Member

Oct 10, 2008
304
0
Thanks for the suggestions everyone.
They have helped me a great deal with my variable inductor project.

MrAl, your suggestion on using a core that already has a gap is great. After looking at core specs I can see that the AL value does not decrease linearly with the gap. So if the gap already exists I can gap it further and the change in the AL value will be smaller than what I would get using an ungapped core. Just the insight I was hoping for.

Thank you very much for the help everyone!


text:
# 3.7E: Exercises for Section 3.7

In exercises 1 - 4, use the graph of $$y=f(x)$$ to

a. sketch the graph of $$y=f^{−1}(x)$$, and

b. use part a. to estimate $$\big(f^{−1}\big)′(1)$$.

1)

2)

a.

b. $$(f^{−1})′(1)\approx 2$$

3)

4)

a.

b. $$(f^{−1})′(1)\approx −1/\sqrt{3}$$

For exercises 5 - 8, use the given function $$y=f(x)$$ to find

a. $$\dfrac{df}{dx}$$ at $$x=a$$ and

b. $$x=f^{−1}(y)$$.

c. Then use part b. to find $$\dfrac{df^{−1}}{dy}$$ at $$y=f(a).$$

5) $$f(x)=6x−1,\; x=−2$$

6) $$f(x)=2x^3−3,\; x=1$$

a. $$\dfrac{df}{dx} = 6$$
b. $$x=f^{−1}(y)=\left(\dfrac{y+3}{2}\right)^{1/3}$$
c. $$\dfrac{df^{−1}}{dy} = \frac{1}{6}$$

7) $$f(x)=9−x^2,\; 0≤x≤3,x=2$$

8) $$f(x)=\sin x,\; x=0$$

a. $$\dfrac{df}{dx} = 1$$
b. $$x=f^{−1}(y)=\sin^{−1}y$$
c. $$\dfrac{df^{−1}}{dy} = 1$$

For each function in exercises 9 - 14, find $$\big(f^{−1}\big)′(a)$$.

9) $$f(x)=x^2+3x+2,\; x≥−1,\; a=2$$

10 $$f(x)=x^3+2x+3,\; a=0$$

$$\big(f^{−1}\big)′(1) = \frac{1}{5}$$

11) $$f(x)=x+\sqrt{x},\; a=2$$

12) $$f(x)=x−\frac{2}{x},\; x<0,\; a=1$$

$$\big(f^{−1}\big)′(1) = \frac{1}{3}$$

13) $$f(x)=x+\sin x,\; a=0$$

14) $$f(x)=\tan x+3x^2,\; a=0$$

$$\big(f^{−1}\big)′(0) = 1$$

For each function $$y=f(x)$$, given in exercises 15 - 19,

a. find the slope of the tangent line to its inverse function $$f^{−1}$$ at the indicated point $$P$$, and

b. find the equation of the tangent line to the graph of $$f^{−1}$$ at the indicated point.

15) $$f(x)=\dfrac{4}{1+x^2},\quad P(2,1)$$

16) $$f(x)=\sqrt{x−4},\quad P(2,8)$$

a. $$4$$
b. $$y=4x$$

17) $$f(x)=(x^3+1)^4,\quad P(16,1)$$

18) $$f(x)=−x^3−x+2,\quad P(−8,2)$$

a. $$−\frac{1}{96}$$
b. $$y=−\frac{1}{13}x+\frac{18}{13}$$

19) $$f(x)=x^5+3x^3−4x−8,\quad P(−8,1)$$

In exercises 20 - 29, find $$\dfrac{dy}{dx}$$ for the given function.

20) $$y=\sin^{−1}(x^2)$$

$$\dfrac{dy}{dx} = \dfrac{2x}{\sqrt{1−x^4}}$$

21) $$y=\cos^{−1}\left(\sqrt{x}\right)$$

22) $$y=\sec^{−1}\left(\frac{1}{x}\right)$$

$$\dfrac{dy}{dx} = \dfrac{−1}{\sqrt{1−x^2}}$$

23) $$y=\sqrt{\csc^{−1}x}$$

24) $$y=(1+\tan^{−1}x)^3$$

$$\dfrac{dy}{dx} = \dfrac{3(1+\tan^{−1}x)^2}{1+x^2}$$

25) $$y=\cos^{−1}(2x)⋅\sin^{−1}(2x)$$

26) $$y=\dfrac{1}{\tan^{−1}(x)}$$

$$\dfrac{dy}{dx} = \dfrac{−1}{(1+x^2)(\tan^{−1}x)^2}$$

27) $$y=\sec^{−1}(−x)$$

28) $$y=\cot^{−1}\sqrt{4−x^2}$$

$$\dfrac{dy}{dx} = \dfrac{x}{(5−x^2)\sqrt{4−x^2}}$$

29) $$y=x⋅\csc^{−1}x$$

In exercises 30 - 35, use the given values to find $$\big(f^{−1}\big)′(a)$$.

30) $$f(π)=0,f'(π)=−1,a=0$$

$$\big(f^{−1}\big)′(0) = −1$$

31) $$f(6)=2,\; f′(6)=\frac{1}{3},\; a=2$$

32) $$f(\frac{1}{3})=−8,\; f'(\frac{1}{3})=2,\; a=−8$$

$$\big(f^{−1}\big)′(-8) = \frac{1}{2}$$

33) $$f(\sqrt{3})=\frac{1}{2},f'(\sqrt{3})=\frac{2}{3},a=\frac{1}{2}$$

34) $$f(1)=−3,\; f'(1)=10,\; a=−3$$

$$\big(f^{−1}\big)′(-3) =\frac{1}{10}$$

35) $$f(1)=0,\; f'(1)=−2,\; a=0$$

36) [T] The position of a moving hockey puck after $$t$$ seconds is $$s(t)=tan^{−1}t$$ where $$s$$ is in meters.

a. Find the velocity of the hockey puck at any time $$t$$.

b. Find the acceleration of the puck at any time $$t$$.

c. Evaluate parts a. and b. for $$t=2,\, 4$$,and $$6$$ seconds.

d. What conclusion can be drawn from the results in c.?

a. $$v(t)=\dfrac{1}{1+t^2}$$
b. $$a(t)=\dfrac{−2t}{(1+t^2)^2}$$
c. (a) $$0.2,\, 0.06,\, 0.03$$; (b) $$−0.16,\, −0.028,\, −0.0088$$

d. The hockey puck is decelerating/slowing down at 2, 4, and 6 seconds.

Solution:

37) [T] A building that is 225 feet tall casts a shadow of various lengths $$x$$ as the day goes by. An angle of elevation $$θ$$ is formed by lines from the top and bottom of the building to the tip of the shadow, as seen in the following figure. Find the rate of change of the angle of elevation $$\frac{dθ}{dx}$$ when $$x=272$$ feet.

38) [T] A pole stands 75 feet tall. An angle $$θ$$ is formed when wires of various lengths of $$x$$ feet are attached from the ground to the top of the pole, as shown in the following figure. Find the rate of change of the angle $$\frac{dθ}{dx}$$ when a wire of length 90 feet is attached.

$$−0.0168$$ radians per foot

39) [T] A television camera at ground level is 2000 feet away from the launching pad of a space rocket that is set to take off vertically, as seen in the following figure. The angle of elevation of the camera can be found by $$θ=\tan^{−1}\left(\frac{x}{2000}\right)$$, where $$x$$ is the height of the rocket. Find the rate of change of the angle of elevation after launch when the camera and the rocket are 5000 feet apart.

40) [T] A local movie theater with a 30-foot-high screen that is 10 feet above a person’s eye level when seated has a viewing angle $$θ$$ (in radians) given by $$θ=\cot^{−1}\frac{x}{40}−\cot^{−1}\frac{x}{10}$$,

where $$x$$ is the distance in feet away from the movie screen that the person is sitting, as shown in the following figure.

a. Find $$\dfrac{dθ}{dx}$$.

b. Evaluate $$\dfrac{dθ}{dx}$$ for $$x=5,\,10,\,15,$$ and $$20$$.

c. Interpret the results in part b.

d. Evaluate $$\dfrac{dθ}{dx}$$ for $$x=25,\,30,\,35$$, and $$40$$.

e. Interpret the results in part d. At what distance $$x$$ should the person stand to maximize his or her viewing angle?

a. $$\dfrac{dθ}{dx}=\dfrac{10}{100+x^2}−\dfrac{40}{1600+x^2}$$
b. $$\frac{18}{325},\,\frac{9}{340},\,\frac{42}{4745},\,0$$
c. As a person moves farther away from the screen, the viewing angle is increasing, which implies that as he or she moves farther away, his or her screen vision is widening. d. $$−\frac{54}{12905},\,−\frac{3}{500},\,−\frac{198}{29945},\,−\frac{9}{1360}$$


text:
# Plugin Toc

• Used in the structure's 'root' page, a full table of contents for the entire structure will be created.
• Used in a sub-page, a chapter table of contents will be created (showing only the sub-pages to that page).

## Parameters

Default options for the possible parameters are shown below in bold.

Parameter
Value
Description
order asc or desc order
showdesc 0 or 1 show the description of the page
shownum 0 or 1 show the numbering
type plain or fancy if fancy, show automatically the description of the page and use the fancytoclevel class for each line instead of toclevel class
structId number (default: structure ID that the page belongs to) the id of the structure, or the name of the structure (tw >2), or the page_ref_id of a page within a structure (see below for more information)
maxdepth number (default: 0) maximum depth of tree to be created, any number starting from 0, which means no limit
pagename string (default: current page name) the name of the page to create a toc for

### Same Page in Multiple Structures

Navigating to a page that is included in multiple structures can cause a PluginToc used on that page to behave unexpectedly. In these cases the structId parameter should be used to set behavior.

For example, assume we have one structure called "Full" and one called "Shell" and we have a page called "Examples" that is included in both. In the Full structure, the Examples page has three pages under it called "Example 1", "Example 2" and "Example 3", whereas in the Shell structure there are no pages under the Examples page.

If you want the three example pages to show in PluginToc every time the Examples page is brought up, then the structId parmeter should be set to be the page_ref_id of the Examples page in the Full structure. To determine what this page_ref_id is, do the following:
• Click on the name of the structure ("Full" in this example)
• On the page that comes up, mouse over the page name where PluginToc is being used ("Examples" in this example)
• Note the page_ref_id that is part of the URL when you mouse over the page name
• Set the structId parameter in PluginToc to equal the page_ref_id noted
Now PluginToc on the Examples page will show the three pages underneath it in the Full structure.

### Example 1: type plain

This code:
{toc order=asc shownum=1 type=plain }

Would produce on the main page of a structure (using the All the Documentation page in this example):

### Example 2: type fancy

This code:
{toc order=asc shownum=1 type=fancy }

Would produce on the main page of a structure (using the All the Documentation page in this example):

### Example 3: type fancy, showdesc

This code:
{toc order=asc shownum=1 type=fancy showdesc=1 }

Would produce on the main page of a structure (using the All the Documentation page in this example):

Note that in this example, the description is shown first and is the hyperlink, and the title field shown second. If a page has no description field (like in many pages of the structure in this example), no description, link or title will be shown. So only use this option if ALL the pages in the table of contents have the description field set.

### Example 4: pagename

This code:
{toc pagename="Documentation"}

Passing the pagename is useful in (at least) two situations:
1. When you want to have a master table of contents page of a structure as the last page in the structure.
2. When you want to include a page (using PluginInclude) with a toc tag in another page.
If you include the page with the toc tag without passing the name of the page to the toc tag, the toc will show the table of contents for the page where it is included, instead of showing the toc for the included page.
This is useful for overview/portal pages.

Note: If you need to include a page with a toc from a different struture, you might need to pass the structure ID as well.
You can do a dynamic side menu out from a table of contents of a structure of wiki pages through the module wikistructure.

# Alias

### Keywords

These keywords serve as "hubs" for navigation within the Tiki documentation. They correspond to development keywords (bug reports and feature requests):


text:
# Colors¶

Any place you need to specify a color in the game (at the moment this is just with VECDRAW, HIGHLIGHT. and HUDTEXT) You do so with a rgba color structure defined as follows:

Method 1: Use one of these pre-arranged named colors:

• RED
• GREEN
• BLUE
• YELLOW
• CYAN
• MAGENTA
• WHITE
• BLACK
RGB(r,g,b)

This global function creates a color from red green and blue values:

SET myColor TO RGB(r,g,b).

where:

r
A floating point number from 0.0 to 1.0 for the red component.
g
A floating point number from 0.0 to 1.0 for the green component.
b
A floating point number from 0.0 to 1.0 for the blue component.
RGBA(r,g,b,a)

Same as RGB() but with an alpha (transparency) channel:

SET myColor TO RGBA(r,g,b,a).

r, g, b are the same as above.

a
A floating point number from 0.0 to 1.0 for the alpha component. (1.0 means opaque, 0.0 means invisibly transparent).
structure RGBA
Members
Suffix Type Description
:R or :RED scalar the red component of the color
:G or :GREEN scalar the green component of the color
:B or :BLUE scalar the blue component of the color
:A or :ALPHA scalar the alpha (how opaque: 1 = opaque, 0 = transparent) component of the color
:HTML or :HEX string the color rendered into a HTML tag string i.e. “#ff0000”. This format ignores the alpha channel and treats all colors as opaque.

Examples:

SET myarrow TO VECDRAW.
SET myarrow:VEC to V(10,10,10).
SET myarrow:COLOR to YELLOW.
SET mycolor TO YELLOW.
SET myarrow:COLOR to mycolor.
SET myarrow:COLOR to RGB(1.0,1.0,0.0).

// COLOUR spelling works too
SET myarrow:COLOUR to RGB(1.0,1.0,0.0).

// half transparent yellow.
SET myarrow:COLOR to RGBA(1.0,1.0,0.0,0.5).

PRINT GREEN:HTML. // prints #00ff00

HSV(h,s,v)

This global function creates a color from hue, saturation and value:

SET myColor TO HSV(h,s,v).

More Information about HSV <http://en.wikipedia.org/wiki/HSL_and_HSV>_,

where:

h
A floating point number from 0.0 to 1.0 for the hue component.
s
A floating point number from 0.0 to 1.0 for the saturation component.
v
A floating point number from 0.0 to 1.0 for the value component.
HSVA(h,s,v,a)

Same as HSV() but with an alpha (transparency) channel:

SET myColor TO HSVA(h,s,v,a).

h, s, v are the same as above.

a
A floating point number from 0.0 to 1.0 for the alpha component. (1.0 means opaque, 0.0 means invisibly transparent).
structure HSVA

The HSVA structure contains all of the suffixes from the RGBA structure in addition to these

Members
Suffix Type Description
:H or :HUE scalar the hue component of the color. It is a value from 0.0 to 360.0
:S or :SATURATION scalar the saturation component of the color. It has a value from 0.0 to 1.0
:V or :VALUE scalar the value component of the color. It has a value from 0.0 to 1.0

Examples:

SET myarrow TO VECDRAW.
SET myarrow:VEC to V(10,10,10).
SET myarrow:COLOR to HSV(60,1,1). // Yellow
SET myarrow:COLOR:S to 0.5. // Light yellow
SET myarrow:COLOR:H to 0. // pink