【问题标题】:How to assign each element in an array column its ordered position?如何为数组列中的每个元素分配其有序位置?
【发布时间】:2019-11-16 22:35:33
【问题描述】:

我有一个如下所示的数据框:

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

【问题讨论】:

  • 为什么4,5在第2组6
  • @Erfan:因为来自第 1 组的对 (3,2) 已被指定为 label 5。对 (4, 5) 紧随其后,并已分配给 label 6
  • 这对您没有帮助,因为您正在对多个列进行排序并希望将相同的值分组到相同的组中,但相关的函数是 df.x.argsort(),它为您提供了可以放置的索引按顺序列(将-1 分配给nan 值)。

标签: python pandas numpy tuples


【解决方案1】:

按x,y对排序,先设置nan,再用cumsum设置组数

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

【讨论】:

  • 太棒了!比我的好多了,非常感谢。没有事件知道.ne() 方法
猜你喜欢
  • 2022-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-19
  • 2018-12-28
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多