在pandas数据框上执行复杂搜索的最快方法

15
我正在尝试找出在pandas数据框上执行搜索和排序的最快方法。以下是我想实现的数据框之前和之后的情况。
之前:
flightTo  flightFrom  toNum  fromNum  toCode  fromCode
   ABC       DEF       123     456     8000    8000
   DEF       XYZ       456     893     9999    9999
   AAA       BBB       473     917     5555    5555
   BBB       CCC       917     341     5555    5555

搜索/排序后:

flightTo  flightFrom  toNum  fromNum  toCode  fromCode
   ABC       XYZ       123     893     8000    9999
   AAA       CCC       473     341     5555    5555

在这个例子中,我基本上试图过滤掉存在于终点之间的“航班”。这应该通过使用某种去重方法来完成,但让我困惑的是如何处理所有列。二分搜索是否是实现这一目标的最佳方法?欢迎提示,我正在努力解决这个问题。

可能的边缘情况:

如果数据被调换,我们的终点连接在同一列中怎么办?

flight1  flight2      1Num    2Num     1Code   2Code
   ABC       DEF       123     456     8000    8000
   XYZ       DEF       893     456     9999    9999

搜索/排序后:

flight1  flight2      1Num    2Num     1Code   2Code
   ABC       XYZ       123     893     8000    9999

这种情况从逻辑上讲是不可能发生的。毕竟,你怎么能同时到达 DEF-ABC 和 DEF-XYZ 呢?你不能,但“端点”仍将是 ABC-XYZ。


连接航班在数据框中总是相邻的吗? - Mike
np.where(condition) - Dadu Khan
df['flightFrom'].shift() != df['fightTo'] 怎么样? - IanS
@Mike DataFrame中的信息可以是完全随机的。 - MaxB
1
@IanS请检查fromNum, fromCode的值,期望输出是什么,这就是我认为这个问题复杂的原因。 - Erfan
2个回答

16

这是网络问题,因此我们使用 networkx ,请注意,此处可以有两个以上的站点,这意味着您可能会遇到像 NY-DC-WA-NC 这样的情况

import networkx as nx
G=nx.from_pandas_edgelist(df, 'flightTo', 'flightFrom')

# create the nx object from pandas dataframe

l=list(nx.connected_components(G))

# then we get the list of components which as tied to each other , 
# in a net work graph , they are linked 
L=[dict.fromkeys(y,x) for x, y in enumerate(l)]

# then from the above we can create our map dict , 
# since every components connected to each other , 
# then we just need to pick of of them as key , then map with others

d={k: v for d in L for k, v in d.items()}

# create the dict for groupby , since we need _from as first item and _to as last item 
grouppd=dict(zip(df.columns.tolist(),['first','last']*3))
df.groupby(df.flightTo.map(d)).agg(grouppd) # then using agg with dict yield your output 

Out[22]: 
         flightTo flightFrom  toNum  fromNum  toCode  fromCode
flightTo                                                      
0             ABC        XYZ    123      893    8000      9999
1             AAA        CCC    473      341    5555      5555

安装 networkx

  • Pip: pip install networkx
  • Anaconda: conda install -c anaconda networkx

2
很棒的回答!我已经看了几次networkx,现在会更多地学习它! - Erfan
2
这个答案值得更详细地解释一下 :)(这样我就可以从中学习呵呵) - Erfan
1
我读过的最佳答案。是否可能使用信息名称来编辑变量,而不是字母,并扩展解决方案。或者最好在Medium(或其他地方)撰写一篇文章/帖子,解释这种方法论。 - Prayson W. Daniel
@MaxB 我感觉数据可能已经损坏了,因为 from 到 from 不应该在同一个网络中考虑。 - BENY
1
@MaxB,我只能建议您将数据框分成两部分。一部分是正常网络,另一部分是边缘情况。使用 df1 = df[df.ID.duplicated(keep=False)];df2 = df2.drop(df1.index);df1.groupby('flightFrom').agg(....),df2则按照上述步骤操作。 - BENY
显示剩余3条评论

6
这里提供一个NumPy解决方案,如果性能很关键的话可能是很方便的:
def remove_middle_dest(df):
    x = df.to_numpy()
    # obtain a flat numpy array from both columns
    b = x[:,0:2].ravel()
    _, ix, inv = np.unique(b, return_index=True, return_inverse=True)
    # Index of duplicate values in b
    ixs_drop = np.setdiff1d(np.arange(len(b)), ix) 
    # Indices to be used to replace the content in the columns
    replace_at = (inv[:,None] == inv[ixs_drop]).argmax(0) 
    # Col index of where duplicate value is, 0 or 1
    col = (ixs_drop % 2) ^ 1
    # 2d array to index and replace values in the df
    # index to obtain values with which to replace
    keep_cols = np.broadcast_to([3,5],(len(col),2))
    ixs = np.concatenate([col[:,None], keep_cols], 1)
    # translate indices to row indices
    rows_drop, rows_replace = (ixs_drop // 2), (replace_at // 2)
    c = np.empty((len(col), 5), dtype=x.dtype)
    c[:,::2] = x[rows_drop[:,None], ixs]
    c[:,1::2] = x[rows_replace[:,None], [2,4]]
    # update dataframe and drop rows
    df.iloc[rows_replace, 1:] = c
    return df.drop(rows_drop)

哪个提出的数据框产生了预期的输出:
print(df)
    flightTo flightFrom  toNum  fromNum  toCode  fromCode
0      ABC        DEF    123      456    8000      8000
1      DEF        XYZ    456      893    9999      9999
2      AAA        BBB    473      917    5555      5555
3      BBB        CCC    917      341    5555      5555

remove_middle_dest(df)

    flightTo flightFrom  toNum  fromNum  toCode  fromCode
0      ABC        XYZ    123      893    8000      9999
2      AAA        CCC    473      341    5555      5555

这种方法不假设任何特定的行重复顺序,同样适用于列(以涵盖问题描述中的边缘情况)。如果我们例如使用以下数据框:

    flightTo flightFrom  toNum  fromNum  toCode  fromCode
0      ABC        DEF    123      456    8000      8000
1      XYZ        DEF    893      456    9999      9999
2      AAA        BBB    473      917    5555      5555
3      BBB        CCC    917      341    5555      5555

remove_middle_dest(df)

     flightTo flightFrom  toNum  fromNum  toCode  fromCode
0      ABC        XYZ    123      456    8000      9999
2      AAA        CCC    473      341    5555      5555

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