# A problem involving classification of data

Toady, I encountered a problem while trying to classify certain data.

I have the coordinates of six points.

data = {{0.349661, 0.380297}, {0.858156, 0.8442}, {0.906745, 0.171579},
{0.0847783, 0.277227}, {0.198453, 0.40206}, {0.941614, 0.347187}};


I want to perform some operation on the x coordinate. The operation is as follows. If the x coordinate in one of the following ranges

{{0.0423892, 0.141616}, {0.141616, 0.274057}, {0.274057, 0.603909},
{0.603909, 0.882451}, {0.882451, 0.924179}, {0.924179, 0.959049}}


The new x coordinate will have the value 1, 2, 3, 4, 5, 6 respectively.

I tried the following:

judge = {{0.0423892, 0.141616}, {0.141616, 0.274057}, {0.274057, 0.603909},
{0.603909, 0.882451}, {0.882451, 0.924179}, {0.924179, 0.959049}};
Which[Sequence @@
Flatten@Table[{judge[[i, 1]] < # < judge[[i, 2]] &, i}, {i, 1, 6}]] /@
data[[All, 1]]


However, it failed. I discovered the mistake was

Table[{judge[[i, 1]] < # < judge[[i, 2]] &, i}, {i, 1, 6}]


I got

{{judge[[i, 1]] < #1 < judge[[i, 2]] &, 1},
{judge[[i, 1]] < #1 < judge[[i, 2]] &, 2},
{judge[[i, 1]] < #1 < judge[[i, 2]] &, 3},
{judge[[i, 1]] < #1 < judge[[i, 2]] &, 4},
{judge[[i, 1]] < #1 < judge[[i, 2]] &, 5},
{judge[[i, 1]] < #1 < judge[[i, 2]] &, 6}}


rather than

 {{judge[[1, 1]] < #1 < judge[[1, 2]] &, 1},
{judge[[2, 1]] < #1 < judge[[2, 2]] &, 2},
{judge[[3, 1]] < #1 < judge[[3, 2]] &, 3},
{judge[[4, 1]] < #1 < judge[[4, 2]] &, 4},
{judge[[5, 1]] < #1 < judge[[5, 2]] &, 5},
{judge[[6, 1]] < #1 < judge[[6, 2]] &, 6}}

-
Do I understand this correctly: You want to get a list of which range number each of the first entries in the data list belong to? – ciao Jul 3 '14 at 5:37
You could try Evaluate. Or inject a value for i using With. – Sjoerd C. de Vries Jul 3 '14 at 6:27

If I'm interpreting your question correctly...

data = {{0.349661, 0.380297}, {0.858156, 0.8442}, {0.906745, 0.171579},
{0.0847783, 0.277227}, {0.198453, 0.40206}, {0.941614, 0.347187}};

intervals =
Interval /@ {{0.0423892, 0.141616}, {0.141616, 0.274057}, {0.274057, 0.603909},
{0.603909, 0.882451}, {0.882451, 0.924179}, {0.924179, 0.959049}};

result=First@Pick[Range@Length@intervals, IntervalMemberQ[intervals, #]] & /@ data[[All, 1]]

(* {3, 4, 5, 1, 2, 6} *)


If you actually want to change the data itself, follow by

data[[All, 1]] += result


If you want to replace the x data, follow instead with

data[[All, 1]] = result

-
I think data[[All, 1]] = result is what the OP wants. – m_goldberg Jul 3 '14 at 12:02
Lots of options, but I think your use of Interval is the "right" approach given the OPs intent. – bobthechemist Jul 3 '14 at 13:27
data = {{0.349661, 0.380297}, {0.858156, 0.8442}, {0.906745, 0.171579},
{0.0847783, .277227},  {0.198453, 0.40206}, {0.941614, 0.347187}};
ints = {{0.0423892, 0.141616}, {0.141616, 0.274057}, {0.274057, 0.603909},
{0.603909, 0.882451}, {0.882451, 0.924179}, {0.924179, 0.959049}};

{IntegerPart@ InverseFunction[Interpolation[ints[[All, 1]], InterpolationOrder -> 1]]
@#[[1]], #[[2]]} & /@ data

(*
{{3, 0.380297}, {4, 0.8442}, {5, 0.171579}, {1, 0.277227}, {2,  0.40206}, {6, 0.347187}}
*)

-
I spy... two fives... – ciao Jul 3 '14 at 6:25
@rasher Oh, I forgot the InterpolationOrder part. Thanks for checking. – Dr. belisarius Jul 3 '14 at 7:23
data = {{0.349661, 0.380297}, {0.858156, 0.8442}, {0.906745,
0.171579}, {0.0847783, 0.277227}, {0.198453, 0.40206}, {0.941614, 0.347187}};
data2 = {{0.0423892, 0.141616}, {0.141616, 0.274057}, {0.274057,
0.603909}, {0.603909, 0.882451}, {0.882451, 0.924179}, {0.924179, 0.959049}};
data3 = Range[6]
f[{x_, y_}] :=
Evaluate@Piecewise@Transpose@{{#, y} & /@ data3, #1 < x <= #2 & @@@ data2};
f /@ data

-

Just for variety:

data = {{0.349661, 0.380297}, {0.858156, 0.8442}, {0.906745,
0.171579}, {0.0847783, 0.277227}, {0.198453, 0.40206}, {0.941614,
0.347187}};
int = {{0.0423892, 0.141616}, {0.141616, 0.274057}, {0.274057,
0.603909}, {0.603909, 0.882451}, {0.882451, 0.924179}, {0.924179,
0.959049}};


Changing the intervals and sorting data:

ord = Union[Flatten@int];
s = SortBy[data, First];


Deriving (sorted) result:

ans = MapThread[{Total[Map[Function[x, Boole[#1 > x]], ord]], #2} &,
Transpose@s]


yields:

{{1, 0.277227}, {2, 0.40206}, {3, 0.380297}, {4, 0.8442}, {5,
0.171579}, {6, 0.347187}}


If original order desired:

ans[[Ordering@Ordering[data[[All, 1]]]]]


->

{{3, 0.380297}, {4, 0.8442}, {5, 0.171579}, {1, 0.277227}, {2,
0.40206}, {6, 0.347187}}


Generalizing:

fun[list_, i_, p_: 0] := Module[{st, res, a},
st = SortBy[list, First];
res = MapThread[{Total[Map[Function[x, Boole[#1 > x]], i]], #2} &,
Transpose@st];
If[p != 0, a = res[[Ordering@Ordering[list[[All, 1]]]]], a = res];
a
]


(default is p=0 sorted, otherwise original).

Test: consider sorting random reals between 0 and 10 for intervals:{{0, 2}, {2, 4}, {4, 6}, {6, 8}, {8, 10}}:

test = RandomReal[{0, 10}, {10, 2}]
Grid[{#1, #2 /.
Thread[Range[5] -> Partition[Range[0, 10, 2], 2, 1]], #2} & @@@
Transpose[{test, fun[test, Range[0, 10, 2], 1]}], Frame -> All]


-
indexF = Function[{x}, Piecewise[MapIndexed[{First@#2, #[[1]] <= x <= #[[2]]} &, #]]]&;
h = MapAt[indexF[#2], #1, {All, 1}] &;

data = {{0.349661, 0.380297}, {0.858156, 0.8442}, {0.906745,  0.171579},
{0.0847783, .277227}, {0.198453, 0.40206}, {0.941614, 0.347187}};
ints = {{0.0423892, 0.141616}, {0.141616, 0.274057}, {0.274057, 0.603909},
{0.603909, 0.882451}, {0.882451, 0.924179}, {0.924179,  0.959049}};

h[data, ints]
(*{{3,0.380297},{4,0.8442},{5,0.171579},{1,0.277227},{2,0.40206},{6,0.347187}} *)

-
@kguker,Sorry, I can not achieve a result witj your solution, namely, it give some information. – Shutao TANG Sep 12 '14 at 7:13

Fixing the OP's original function :-

data = {{0.349661, 0.380297}, {0.858156, 0.8442}, {0.906745, 0.171579},
{0.0847783, 0.277227}, {0.198453, 0.40206}, {0.941614, 0.347187}};

judge = {{0.0423892, 0.141616}, {0.141616, 0.274057}, {0.274057, 0.603909},
{0.603909, 0.882451}, {0.882451, 0.924179}, {0.924179, 0.959049}};

Which @@ Flatten@
Table[{judge[[i, 1]] < # < judge[[i, 2]], i}, {i, 1, 6}] & /@ data[[All, 1]]


{3, 4, 5, 1, 2, 6}

-

For more variety, using a rule replacement

data = {{0.349661, 0.380297}, {0.858156, 0.8442}, {0.906745,
0.171579}, {0.0847783, 0.277227}, {0.198453, 0.40206}, {0.941614,
0.347187}};
range = {{0.0423892, 0.141616}, {0.141616, 0.274057}, {0.274057,
0.603909}, {0.603909, 0.882451}, {0.882451, 0.924179}, {0.924179,
0.959049}};
data[[All, 1]] /. (x_ /; x < #[[2]] -> #[[1]] & /@
Transpose[{Range[1, 6], Last /@ range}])


I sacrifice rigor for compactness here, since the rules will assign x < 0.0423892 -> 1 instead of undefined.

## update

Borrowing from @rasher and using Association in v10

#[[1]] -> #[[2]] & /@ Transpose[{Range[1, 6], Interval /@ range}]
assoc = Association[%]
With[{dlist = #}, Keys@Select[assoc, IntervalMemberQ[#, dlist] &]] & /@
data[[All, 1]] // Flatten

-