Chu Chu - 1 year ago 52
Python Question

How to define an element belongs to other categories?

I know the topic is really hard to understand but I don't know how to describe my problem in one sentence...T^T

Here is what I'm trying to do.

I have a set of 1-dimensional points in three categories.

A = [[0,1], [0,2], [0,3], [1,1], [2,1], [3,2], [3,3], [4,2], [4,3], [5,3], [6,3]]

First number is x-coordinate and second number is label in each [ ]

And I want to insert a cut point into every pair of adjacent points [x1, L1], [x2, L2] if at least one of them has more than one kinds of label and L2 belongs to those categories that differ from L1.;;;

For example,

[0,1], [0,2], [0,3]

they are all on x = 0 but there are three kinds of labels


belongs to only one categories, so I would like to add a cut point x=0.5 in the middle of 0 and 1.

3 x
2 x
1 x 1

but like

[1,1] and [2,1]

they both has only one and identical label, there is no need to add a cut point here.

So the result should be
[0.5, 2.5, 3.5, 4.5]

and maybe looks like this

3 x x 3 x 3 x 3 3 <--Label
2 x x 2 x 2 x <--Label
1 x 1 1 x x x <--Label
x x x x
-0-x-1---2-x-3-x-4-x-5---6--- <--X-axis
0.5 2.5 3.5 4.5 <--Cut points

The code I want to write will looks like this form

A = [[0,1], [0,2], [0,3], [1,1], [2,1], [3,2], [3,3], [4,2], [4,3], [5,3], [6,3]]
X = []
for a in A:
X = sorted(list(set(X)))

labels = [[1], [2], [3]]
group = []
for i in range(len(labels)):

for a in A:
for i in range(3):
if a[1] in labels[i]:

cutpoints = []

for i, x in enumerate(X):
for j in range(len(group)):
if x in group[j] and (X[i+1] in group[ other than j ]):

But I stuck at the part "other than j"
In this case there are only 3 categories so maybe I can do that manually but I'm looking for a more clever way to do it so I don't need to rewrite this part every time I meet a new data with different number of categories.

Is there any function I can use to do the "other than j" operation??

Any comment or answer will be appreciated.
Thanks in advance T^T

Answer Source

This is sort of a weird problem you've got, but here's a functional way to do.

from itertools import groupby

groupby will let us easily merge your X coordinates, assuming the array is pre-sorted by them.

l = [(i, [x[1] for x in g]) for i, g in groupby(A, lambda x: x[0])]

This looks a bit daunting, but is conceptually pretty easy. The groupby pulls together all the things that share an X, and the inner list comprehension just dumps the X values out:


[(0, [1, 2, 3]),
 (1, [1]),
 (2, [1]),
 (3, [2, 3]),
 (4, [2, 3]),
 (5, [3]),
 (6, [3])]

Then if we group each together with the next element using zip we can just pick out the pairs that meet your criteria and get the midpoint between them:

[(i1+i2) / 2.
 for (i1, l1), (i2, l2)
 in zip(l, l[1:])
 if l1 != l2 or len(l1) > 1]

[0.5, 2.5, 3.5, 4.5]