我有一个看起来像这样的数据框:
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
答案 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