Skip to main content
Announcements
Join us at Qlik Connect for 3 magical days of learning, networking,and inspiration! REGISTER TODAY and save!
cancel
Showing results for 
Search instead for 
Did you mean: 
irura
Contributor
Contributor

Find nth smallest value

Hi All,

I would like to ask how can QlikSense return the nth smallest value for an array. 

My data set is:

ValueCount
44001
45501
49003
50002
51001
52002
54001
55004
55501
56002
57004
58001
59501
60004
60921
61005

 

For example, I want the 4th smallest number, which is 4900, but Qlik Sense function Min(Value, 4) would give me result 5000. How can I solve this? Thank you.

Labels (1)
7 Replies
tresesco
MVP
MVP

What is the logic that makes 4900 the 4th smallest?

irura
Contributor
Contributor
Author

its count is 3

tresesco
MVP
MVP

Count wise - you have 1,2,3,4,5.....then how come count 3 is 4th? Sorry, a bit more explanation would be helpful.

irura
Contributor
Contributor
Author

No, the array should be like 4400, 4550, 4900, 4900, 4900, 5000, 5000, 5100...... so 4th smallest is 4900

tresesco
MVP
MVP

Ok,,got it. Where are you going to display this 4th smallest value..in kpi object?

ArnadoSandoval
Specialist II
Specialist II

Hi Irura,

It is a very interesting challenge, I do not know about any function that could directly return the result you expect, but with some transformations, it will be possible; you initially presented a frequencies array, then you changed it to an array with the frequency removed (expanded); I worked with the frequencies array while preparing this reply.

I will be using Interval (mathematics) in my solution; first of all, I added two new columns defining the start-end points of each interval:

Your data with intervals

ValueCountab
4400111
4450122
4900335
5000267
............

So, when you ask, who is the n-th smallest value? or the 4th in your example, the result is in the interval between 3 and 4, e.g. 4900; while if we ask for the 7th smallest value, the interval [6, 7] contains the answer, e.g. 5000.

Creating the Interval columns in Qlik's data load script:

The RangeSum function helps with finding your frequency array intervals, note, the frequency array must be ordered by the Value column; this community post was of great help:  Running Sum on Load Script 

 

WORK:
Load *, 
     Num(RangeSum(peek(I_b), Count))             as I_b,
     Num(RangeSum(peek(I_b), Count)) - Count + 1 as I_a;
Load Value,
     Count
Resident Frequencies_array
Order by Value;

 

The script above generates each value interval as shown:

Frequency_Array_Intervals.jpg

Finding the interval for the n-th smallest value:

The figure below shows how to find the n-th smallest value within the intervals.

Interval_handling.jpgIncluding these formulas in the Qlik script is simple; we want to return 1 when the condition is true, 0 otherwise, just like this:

 

WORK:
Load *, 
     if($(vPosition)>=I_a, 1, 0) as Inside_a,
     if($(vPosition)<=I_b, 1, 0) as Inside_b;
Load *, 
     Num(RangeSum(peek(I_b), Count))             as I_b,
     Num(RangeSum(peek(I_b), Count)) - Count + 1 as I_a;
Load Value,
     Count
Resident Frequencies_array
Order by Value;

 

The variable vPosition plays a very important role in this solution, as it allows us to change the n-th position we want to find; the WORK table with these Inside columns now look like this:

Finding_the_Nth_smallest.jpg

To be continued ...

 

Arnaldo Sandoval
A journey of a thousand miles begins with a single step.
ArnadoSandoval
Specialist II
Specialist II

Hi Irura,

It is a very interesting challenge, I do not know about any function that could directly return the result you expect, but with some transformations, it will be possible; you initially presented a frequencies array, then you changed it to an array with the frequency removed (expanded); I worked with the frequencies array while preparing this reply.

I will be using Interval (mathematics) in my solution; first of all, I added two new columns defining the start-end points of each interval:

Your data with intervals

ValueCountab
4400111
4450122
4900335
5000267
............

So, when you ask, who is the n-th smallest value? or the 4th in your example, the result is in the interval between 3 and 4, e.g. 4900; while if we ask for the 7th smallest value, the interval [6, 7] contains the answer, e.g. 5000.

Creating the Interval columns in Qlik's data load script:

The RangeSum function helps with finding your frequency array intervals, note, the frequency array must be ordered by the Value column; this community post was of great help:  Running Sum on Load Script 

 

 

 

WORK:
Load *, 
     Num(RangeSum(peek(I_b), Count))             as I_b,
     Num(RangeSum(peek(I_b), Count)) - Count + 1 as I_a;
Load Value,
     Count
Resident Frequencies_array
Order by Value;

 

 

 

The script above generates each value interval as shown:

Frequency_Array_Intervals.jpg

Finding the interval for the n-th smallest value:

The figure below shows how to find the n-th smallest value within the intervals.

Interval_handling.jpg

Including these formulas in the Qlik script is simple; we want to return 1 when the condition is true, 0 otherwise, just like this:

 

 

 

WORK:
Load *, 
     if($(vPosition)>=I_a, 1, 0) as Inside_a,
     if($(vPosition)<=I_b, 1, 0) as Inside_b;
Load *, 
     Num(RangeSum(peek(I_b), Count))             as I_b,
     Num(RangeSum(peek(I_b), Count)) - Count + 1 as I_a;
Load Value,
     Count
Resident Frequencies_array
Order by Value;

 

 

 

The variable vPosition plays a very important role in this solution, as it allows us to change the n-th position we want to find; the WORK table with these Inside columns now look like this:

Finding_the_Nth_smallest.jpg

The columns (In a) and (In b) shows the evaluation of the conditions for the requested position, both of them returns 1 when we are inside of the range for the position 15 (our example). The final implementation does not require you to create the columns (In a) and (In b), they are here to illustrate its logic.

We know that two conditions linked by the logical AND is equivalent to multiplying their results, so when we multiply (In a) * (In b) we get the result we want, and only the row with the figure 5500 (the 15th slowest value) contains one which is true. If our condition is (In a) * (In b) * Value, the result column contains 5500, the solution we want.

The reply editor is giving me a lot of troubles, so I am having difficulties writing my reply, I will keep trying !!!

Should we use the if statements or convert them to a more mathematical form:

I used "if($(vPosition)<=I_a, 1, 0)" above, which is using a full featured if statement, but it is equivalent to this expression using the SIGN function:  Sign(1 + Sign($(vPosition) - I_a)) ; while the condition for the interval ending point b, become: Sign(1 - Sign( $(vPosition) - I_b));  so we could use these expression returning the n-th lowest value:

 

Sign(1 + Sign($(vPosition) - I_a)) * Sign(1 - Sign( $(vPosition) - I_b)) * Value

 

Solution:

1. Your load script should create the interval's start and ending points columns, e.g: columns I_a and I_b.

 

Let Position = 0;
WORK:
Load *, 
     Num(RangeSum(peek(I_b), Count))             as I_b,
     Num(RangeSum(peek(I_b), Count)) - Count + 1 as I_a;
Load Value,
     Count
Resident Frequencies_array
Order by Value;

 

2. After running the Load Script, create a new sheet.

3. Add a text input field: Custom Objects --> About Qlik Dashboard bundle --> Variable Input

4.  Assign the variable vPosition to your variable input.

5. Add a straight table showing the Frequency Array (optional)

6. Add another straight table, pick Value as its first column, modify the Chart-Type to Treemap, modify its Value column to use the  n-th lowest value expression (shown above), change its label to anything you want.

7. Add another column to the Treemap chart, its expression is also the n-th lowest value expression, change its label to anything you want.

8. Enter different positions in the Position textbox while testing your solution.

Result_01.jpg

Hope this helps

Arnaldo Sandoval

 

Arnaldo Sandoval
A journey of a thousand miles begins with a single step.