根据熊猫中的其他数据框过滤一个数据框

时间:2019-11-07 03:10:20

标签: python pandas dataframe

我在熊猫中有两个DataFrame:

import pandas as pd

df1 = pd.DataFrame({'Name': ["A", "B", "C", "C","D","D","E"],
                   'start': [50, 124, 1, 159, 12, 26,110],
                   'stop': [60, 200, 19, 200, 24, 30,160]})
df2 = pd.DataFrame({'Name': ["B", "C","D","E"],
                   'start': [126, 143, 19, 159],
                   'stop': [129, 220, 27, 200]})

print(df1)

  Name  start  stop
0    A     50    60
1    B    124   200
2    C      1    19
3    C    159   200
4    D     12    24
5    D     26    30
6    E    110   160

print(df2)

  Name  start  stop
0    B    126   129
1    C    143   220
2    D     19    27
3    E    159   200

我要使用以下条件过滤df1以删除基于df2的行:

  1. 名称应同时出现在df1和df2中
  2. 在另一个DataFrame中,该名称从开始到终止的范围与该名称从开始到终止的范围重叠

这将给出:

  Name  start  stop
0    B    124   200
1    C    159   200
2    D     12    24
3    D     26    30
4    E    110   160

位置:

  • 由于df2中没有A,因此A已被删除
  • B保持不变,因为df2中B的起始和终止与df1中B的起始和终止嵌套
  • 由于df1的一个C与df2不重叠,因此删除了一个C,而保留了另一个,因为它嵌套在df2中C的起始和终止范围内
  • 两个D都被保留,因为它们都与df2中的D的范围重叠
  • E被保留,因为其范围与df2中的E重叠

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:1)

为解决您的问题,我采用了一种类似于SQL的方式来模仿以下查询:

SELECT
  df.Name, df.start_x AS start, df.stop_x AS stop
FROM (
  SELECT
    df1.Name, df1.start AS start_x, df1.stop AS stop_x,
              df2.start AS start_y, df2.stop AS stop_y
    FROM df1
    INNER JOIN df2
      ON df1.Name = df2.Name
) AS df
WHERE (df.stop_y >= df.start_x) AND (df.stop_x >= df.start_y)

此查询已转换为使用pandas.merge方法的以下代码片段。请注意,必须在表达式(df.stop_y> = df.start_x) & (df.stop_x> = df.start_y)中使用括号。没有它们,代码将引发异常

  

ValueError:系列的真值不明确。使用a.empty,a.bool(),a.item(),a.any()或a.all()。

import pandas as pd

df1 = pd.DataFrame({'Name': ["A", "B", "C", "C","D","D","E"],
                   'start': [50, 124, 1, 159, 12, 26,110],
                   'stop': [60, 200, 19, 200, 24, 30,160]})
df2 = pd.DataFrame({'Name': ["B", "C","D","E"],
                   'start': [126, 143, 19, 159],
                   'stop': [129, 220, 27, 200]})
df = pd.merge(df1, df2, on=['Name'])
df = df[(df.stop_y >= df.start_x) & (df.stop_x >= df.start_y)]
df.rename(columns={'start_x':'start', 'stop_x':'stop'}, inplace=True)
df.drop(['start_y', 'stop_y'], axis=1, inplace=True)
df.reset_index(drop=True, inplace=True)
print(df)

输出:

  Name  start  stop
0    B    124   200
1    C    159   200
2    D     12    24
3    D     26    30
4    E    110   160

Repl.it上演示。

答案 1 :(得分:0)

对于感兴趣的人,我想出了一种方法...

df3=[]
for index1, row1 in df1.iterrows():
    for index2, row2 in df2.iterrows():
        if row1["Name"] == row2["Name"]:
            x = range(row1["start"],row1["stop"])
            x = set(x)
            y = range(row2["start"],row2["stop"])
            if len(x.intersection(y)) > 0:
                df3.append(row1)
df3 = pd.DataFrame(df3).reset_index(drop=True)
print(df3)

  Name  start  stop
0    B    124   200
1    C    159   200
2    D     12    24
3    D     26    30
4    E    110   160

完成工作,尽管有点笨拙。

如果有人可以提出一种不太杂乱的方式,将会很感兴趣!