Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Re: How would you code this?

by graff (Chancellor)
on Apr 07, 2016 at 06:14 UTC ( #1159787=note: print w/replies, xml ) Need Help??


in reply to How would you code this?

First, I have to wonder if the "desired" output you showed is "definitively correct" (in some sense), or whether it's simply "good enough to move along" (and other possible outputs - discarding a slightly different set of data rows - might be just as good, if not better).

Second, I'm curious about this distinctive property of your data sample: there is exact repetition of particular X values in the regions where certain data rows need to be discarded. Is this simply an artifact of how you created this data sample? If not, then would it happen to be a stable, reliable property of the actual data? If it is stable, this is something an algorithm could exploit. For example:

(a) if the current x is lower than the previous x: (a.1) if the current x has been seen before, discard the current p +oint (a.2) else discard the previous point. (b) elsif the current x is identical to the prev. x (due to a.1 on pre +v.iteration) (b.1) discard previous point
That logic will discard a different set of points than your "desired" output, but the selected points will be monotonic (if that property of repeating x values holds true).

If your pipeline streams get really huge, you might need to worry about not keeping track of too many "previously seen x values", but perhaps that's not a concern.

Here's the perl code for my approach (minus the input __DATA__):

#! perl -slw use strict; printf "%s", scalar <DATA>; my @points = map[ split ' ', $_ ], <DATA>; my @modified; my %xseen; push @modified, shift @points; $xseen{$modified[-1][0]} = undef; while ( @points ) { if ( $points[0][0] < $modified[-1][0] ) { if ( exists( $xseen{$points[0][0]} )) { shift @points; next; } else { pop @modified; } } elsif ( $points[0][0] eq $modified[-1][0] ) { pop @modified; } push @modified, shift @points; $xseen{$modified[-1][0]} = undef; } print join ' ', @$_ for @modified;
And below is the output, pasted next to your "desired" output - mine is on the left side, and yours is on the right. Note that my code outputs 40 points compared to your 35 (I have the corresponding x's aligned so you can see the differences more easily). Also, there's one point where I kept the same x value as you, but selected a different y value at that x.
0.0036759 0.4018006 0.0036759 0.4018006 0.0036962 0.4074616 0.0036962 0.4074616 0.0037064 0.4216399 0.0037064 0.4216399 0.0037166 0.4438854 0.0037166 0.4438854 0.0037268 0.4628417 0.0037268 0.4628417 0.0037370 0.4894152 0.0037370 0.4894152 0.0037471 0.4952320 0.0037471 0.4952320 0.0037675 0.4979326 0.0037675 0.4979326 0.0037879 0.5014988 0.0037879 0.5014988 0.0038082 0.5057747 0.0038082 0.5057747 0.0038184 0.5166984 0.0038184 0.5558402 0.0038286 0.5613627 0.0038286 0.5613627 0.0038388 0.6026338 0.0038388 0.6026338 0.0038490 0.6257104 0.0038693 0.6709805 0.0038693 0.6709805 0.0038795 0.6808655 0.0038795 0.6808655 0.0038897 0.6866130 0.0038897 0.6866130 0.0039202 0.6981425 0.0039202 0.6981425 0.0039406 0.7057251 0.0039406 0.7057251 0.0039508 0.7161121 0.0039610 0.7216518 0.0039610 0.7216518 0.0039712 0.7433434 0.0039712 0.7433434 0.0039813 0.7577987 0.0039915 0.7713018 0.0039915 0.7713018 0.0040017 0.7981869 0.0040017 0.7981869 0.0040119 0.8014242 0.0040119 0.8014242 0.0040221 0.8264223 0.0040221 0.8264223 0.0040526 0.8290191 0.0040526 0.8290191 0.0040628 0.8323083 0.0040628 0.8323083 0.0040933 0.8361688 0.0040933 0.8361688 0.0041035 0.8409814 0.0041035 0.8409814 0.0041137 0.8527880 0.0041239 0.8591068 0.0041239 0.8591068 0.0041341 0.864785 0.0041443 0.8760895 0.0041443 0.8760895
(As a general rule, other things being relatively equal, I'd expect it might be desirable to discard fewer data points - but I suppose that depends on the nature of your test equipment.)

(updated to fix the wording in the 2nd paragraph and pseudo-code)

Replies are listed 'Best First'.
Re^2: How would you code this?
by BrowserUk (Pope) on Apr 07, 2016 at 13:35 UTC

    Graff. You've certainly given me considerable food for thought. And a bunch of extra work to do. So "Thank you" and "thaaaanks a bunch" :)

    Here is a composite zoom on the 5 differences between your output and mine.

    • Top left: You're algorithm picks two points to the left of the two mine picks.

      I think the ideal would be to pick my first point, your second point and the point slap bang in between all four points; but I see no algorithm that would make that choice without hard coding a special case.

      In the end, I think either chosen pair is equally valid.

    • Top right: Your algorithm retains one extra point that happens fall almost exactly on the line between the two points mine retains.

      I concur with you that discarding less is a good thing; in this case, I think the difference would be negligible.

    • Bottom left: Your's retains two extra points.

      The upper extra point is much the same as the previous; negligible difference beyond keeping an extra point.

      The lower extra point, the difference is bigger, more significant.

    • Lower right (inset): Two extra points; the difference about the same as the lower point above.

      I'm undecided if these differences are important; but they are extra points retained, which I like.

    One of, if not the, primary goals of using a discrete filter algorithm, rather than a continuous fitting or smoothing algorithm, is the desire to retain as much of the actual data as possible. Continuous algorithms like moving average, 3-point median and Loess, all have affects upon all the points, not just those at and around the discontinuities; often inventing new points, and subtly shifting existing points well away from the discontinuities; and they also don't guarantee to remove all inflections.

    Upshot: I'm going to have to run your algorithm against mine on a few much larger samples and check to ensure that there are no significant downsides to your algorithm. If not, I will be dumping mine in favour of yours.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I noticed that some x values are repeated up to five times, and that the selection of a trajectory through such a region (depending on what the algorithm does) could vary between:
      c c c vs b vs b b a a a
      (i.e. after dropping some number of points from the input series, the middle point either falls midway between the other two, or creates an "elbow" close to the previous or following point).

      I thought about working out a way to maintain a stack, such that from the first (bottom) to the last (top) stack element, there would be at most three distinct x values (that seems to be the extent of the "oscillation" you're seeing).

      Once a fourth x value appears in the next point, review the stack and output the points that comprise the smoothest trajectory. But that's a lot of work for a potentially insignificant gain in "accuracy".

      UPDATE: As for your "primary" goal of "preserving the original data" as much as possible, as opposed to creating a smoothed sequence with adjustments affecting all data points: given that the input appears to be quantized, any desire to preserve that original data is actually going to preserve the nature of the measuring device, rather than the nature of the thing being measured. Maybe Certainly there's value in that, but depending on what your downstream processes are supposed to do with the data, you might rather let those processes get a "fully smoothed" version of the data, because this represents a presumably reasonable fiction, as opposed to the quantized, jagged fiction being created by your measuring device.

      Another update: obviously, by preserving the original data - but not necessarily using it as-is for certain downstream processes - you'll get to do comparisons if/when you use a different device (or a different configuration of the current device).

        given that the input appears to be quantized,

        I agree the data is quantized. It appears to be, (still waiting for confirmation from the equipment manufacturer), an artifact of the digitisation of the analogue values produced by the sensing device.

        depending on what your downstream processes are supposed to do with the data,

        The cleanup is required because the downstream processing -- FEM software -- interpolates between the supplied values using a cubic spline interpolation, as the simulation converges. Thus, it requires that the input data be monotonic in order that it can produce a 'single-valued cubic spline fit'.

        My choice to avoid producing a "fully smoothed" fit, is because I've seen bad interactions between pre-processed fitting, and the fitting done internally by the software. These manifest themselves as interminable oscillations in the Newton-Raphson iterations resulting in extremely extended run times.

        you'll get to do comparisons if/when you use a different device (or a different configuration of the current device).

        The data is supplied to me; I only get one dataset per sample, but lots of (physically and chemically) different samples. I have no control over how it is produced.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
        In the absence of evidence, opinion is indistinguishable from prejudice.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1159787]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (5)
As of 2021-03-01 10:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?