如何为数组列中的每个元素分配其顺序位置?

时间:2019-11-16 22:35:33

标签: python pandas numpy tuples

我有一个看起来像这样的数据框:

df = pd.DataFrame({'group':[1,1,1,1,1,2,2,2,2,3,3,4,4],
                  'x':[np.nan,np.nan,3,np.nan,2,np.nan,3,3,4,2,1,1,3],
                  'y':[np.nan,np.nan,2,np.nan,1,np.nan,1,1,5,1,5,1,1]})


group   x   y
  1    nan  nan
  1    nan  nan 
  1    3.0  2.0
  1    nan  nan 
  1    2.0  1.0
  2    nan  nan 
  2    3.0  1.0
  2    3.0  1.0
  2    4.0  5.0
  3    2.0  1.0
  3    1.0  5.0
  4    1.0  1.0
  4    3.0  1.0

基本上,可以说我有4个组,每个组包含具有x,y坐标的点。点可以具有相同的坐标。例如,(3,1)在组2和组4中存在(两次)。此外,如果x为nan,则y也应为nan

我想为每对(x,y)分配相对于元组排序列表的对应位置。如果x=y=nan,则应返回零。 因此,输出应为:

group    x    y   label_global
  1     nan  nan       0
  1     nan  nan       0
  1     3.0  2.0       5
  1     nan  nan       0
  1     2.0  1.0       3
  2     nan  nan       0
  2     3.0  1.0       4
  2     3.0  1.0       4
  2     4.0  5.0       6
  3     2.0  1.0       3
  3     1.0  5.0       2
  4     1.0  1.0       1
  4     3.0  1.0       4

我要做的是以下事情:

centroids = sorted(set([x for x in zip(df.dropna().x.values, df.dropna().y.values)]))
df['label_global'] = [centroids.index(d) + 1 if d[1]==d[1] else 0 for d in zip(df.x.values, df.y.values)]

请问有更好的方法吗?我的数据框长约200万行,完成任务大约需要3分钟

作为旁注:在最后一个列表理解中,表达式if d[1]==d[1] else的意思是用nan过滤出元组,因为np.nan==np.nan的值为False。我最初尝试使用if np.nan not in d else,即:

df['label_global'] = [centroids.index(d) + 1 if np.nan not in d else 0 for d in zip(df.x.values, df.y.values)]

但这不起作用,我也不知道为什么。返回值错误:

ValueError: (nan, nan) is not in list

对我来说,表明if else循环无效。任何见解都非常欢迎。

我发现

也有点奇怪

(np.nan, np.nan)==(np.nan, np.nan)返回True

甚至

(np.nan,)==(np.nan,)返回True

但是

np.nan==np.nan返回False

1 个答案:

答案 0 :(得分:2)

按x,y对排序,先设置nan,然后使用累加来设置组号

df['label_global'] = df.sort_values(['x','y'], na_position='first') \ 
                     [['x','y']].fillna(0).diff().ne([0,0]).any(1).cumsum()-1

   group    x    y  label_global
0       1  NaN  NaN             0
1       1  NaN  NaN             0
2       1  3.0  2.0             5
3       1  NaN  NaN             0
4       1  2.0  1.0             3
5       2  NaN  NaN             0
6       2  3.0  1.0             4
7       2  3.0  1.0             4
8       2  4.0  5.0             6
9       3  2.0  1.0             3
10      3  1.0  5.0             2
11      4  1.0  1.0             1
12      4  3.0  1.0             4