检查Pandas中的一对值是否在一对列中

9

基本上,我有两列不同的纬度和经度(在网格上)。我获取了一个新的坐标集的两个元素列表(可以是numpy数组),我想在添加之前检查它是否为重复项。

例如,我的数据:

df = pd.DataFrame([[4,8, 'wolf', 'Predator', 10],
              [5,6,'cow', 'Prey', 10],
              [8, 2, 'rabbit', 'Prey', 10],
              [5, 3, 'rabbit', 'Prey', 10],
              [3, 2, 'cow', 'Prey', 10],
              [7, 5, 'rabbit', 'Prey', 10]],
              columns = ['lat', 'long', 'name', 'kingdom', 'energy'])

newcoords1 = [4,4]
newcoords2 = [7,5]

是否有可能编写一个if语句,告诉我是否已经存在具有该纬度和经度的行。伪代码如下:

if newcoords1 in df['lat', 'long']:
    print('yes! ' + str(newcoords1))

在这个例子中,newcoords1 应该是 false,而且 newcoords2 应该是 true
另外注意事项:(newcoords1[0] in df['lat']) & (newcoords1[1] in df['long']) 无法正常工作,因为它会独立地检查它们,但我需要知道是否在一行中出现了这种组合。
提前感谢你!
4个回答

11

您可以按照以下方式完成:

In [140]: df.query('@newcoords2[0] == lat and @newcoords2[1] == long')
Out[140]:
   lat  long    name kingdom  energy
5    7     5  rabbit    Prey      10

In [146]: df.query('@newcoords2[0] == lat and @newcoords2[1] == long').empty
Out[146]: False

以下代码将返回找到的行数:

In [147]: df.query('@newcoords2[0] == lat and @newcoords2[1] == long').shape[0]
Out[147]: 1

或者使用NumPy方法:

In [103]: df[(df[['lat','long']].values == newcoords2).all(axis=1)]
Out[103]:
   lat  long    name kingdom  energy
5    7     5  rabbit    Prey      10

这将显示是否至少找到了一行:

In [113]: (df[['lat','long']].values == newcoords2).all(axis=1).any()
Out[113]: True

In [114]: (df[['lat','long']].values == newcoords1).all(axis=1).any()
Out[114]: False

解释:

In [104]: df[['lat','long']].values == newcoords2
Out[104]:
array([[False, False],
       [False, False],
       [False, False],
       [False, False],
       [False, False],
       [ True,  True]], dtype=bool)

In [105]: (df[['lat','long']].values == newcoords2).all(axis=1)
Out[105]: array([False, False, False, False, False,  True], dtype=bool)

我有一个问题,它是基于这个问题的扩展; 特别是numpy方法:df[(df[['lat','long']].values == newcoords2).all(axis=1)]。如果newcoords是值对的DataFrame或数组,并且我想避免使用大型Python for循环,我该如何应用它? - Marses

4

对于像我这样通过搜索如何检查大型数据框中一对列中的多个值是否存在来到这里的人,这里有一个答案。

假设有一个列表newscoord = [newscoord1, newscoord2, ...],您想要提取与该列表元素匹配的df的行。那么对于上面的例子:

v = pd.Series( [ str(i) + str(j) for i,j in df[['lat', 'long']].values ] )
w = [ str(i) + str(j) for i,j in newscoord ]

df[ v.isin(w) ]

这将产生与 @MaxU 相同的输出,但它允许一次提取多行。

在我的计算机上,对于具有 10,000 行的 df,运行时间为 0.04s。

当然,如果您的元素已经是字符串,则使用 join 而不是连接更简单。

此外,如果成对元素的顺序无关紧要,则必须先进行排序:

v = pd.Series( [ str(i) + str(j) for i,j in np.sort( df[['lat','long']] ) ] )
w = [ str(i) + str(j) for i,j in np.sort( newscoord ) ]

需要注意的是,如果将变量 v 不转换成序列,并使用 np.isin(v,w),或者将变量 w 转换为序列,当 newscoord 达到数千个元素时,会需要更多的运行时间。希望这能有所帮助。

它确实帮了我一把。与其在数据框中检查几个值,你将它们转换成了一个字符串。这样比较起来肯定更容易!谢谢! - Idriss Brahimi

2
x, y = newcoords1

>>> df[(df.lat == x) & (df.long == y)].empty
True  # Coordinates are not in the dataframe, so you can add it.

x, y = newcoords2

>>> df[(df.lat == x) & (df.long == y)].empty
False  # Coordinates already exist.

((df.lat == x) & (df.long == y)).any() 可以节省查询。 - Cramer

0

如果您想一次检查多个数据对,可以将DataFrame的列和值放入MultiIndexes中,然后使用Index.isin。我认为这比将它们连接成字符串更清晰:

df = pd.DataFrame([[4,8, 'wolf', 'Predator', 10],
          [5,6,'cow', 'Prey', 10],
          [8, 2, 'rabbit', 'Prey', 10],
          [5, 3, 'rabbit', 'Prey', 10],
          [3, 2, 'cow', 'Prey', 10],
          [7, 5, 'rabbit', 'Prey', 10]],
          columns = ['lat', 'long', 'name', 'kingdom', 'energy'])

new_coords = pd.MultiIndex.from_tuples([(4,4), (7,5)])
existing_coords = pd.MultiIndex.from_frame(df[["lat", "long"]])
~new_coords.isin(existing_coords)
>>> array([ True, False])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接