使用熊猫,如何过滤两列中具有相似值的行

时间:2019-04-01 13:04:56

标签: python pandas

我有一个大数据框(约10毫米行)。每行都有:

  • 类别
  • 开始位置
  • 结束位置

如果两行属于同一类别,并且开始和结束位置重叠且公差为+ -5,我只想保留其中一行。 例如

1, cat1, 10, 20
2, cat1, 12, 21
3, cat2, 10, 25

我要过滤掉1或2。

我现在正在做的不是很有效,

import pandas as pd
df = pd.read_csv('data.csv', sep='\t', header=None)
dfs = []
for seq in df.category.unique():
    dfs[seq] = df[df.category == seq]
for index, row in df.iterrows():
    if index in discard:
        continue
    df_2 = dfs[row.category]
    res = df_2[(abs(df_2.start - row.start) <= params['min_distance']) & (abs(df_2.end - row.end) <= params['min_distance'])]
    if len(res.index) > 1:
        discard.extend(res.index.values)
    rows.append(row)
df = pd.DataFrame(rows)

我还尝试了使用数据框排序版本的另一种方法。

my_index = 0
indexes = []
discard = []
count = 0
curr = 0
total_len = len(df.index)
while my_index < total_len - 1:
    row = df.iloc[[my_index]]
    cond = True
    next_index = 1
    while cond:
        second_row = df.iloc[[my_index + next_index]]
        c1 = (row.iloc[0].category == second_row.iloc[0].category)
        c2 = (abs(second_row.iloc[0].sstart - row.iloc[0].sstart) <= params['min_distance'])
        c3 = (abs(second_row.iloc[0].send - row.iloc[0].send) <= params['min_distance'])
        cond =  c1 and c2 and c3
        if cond and (c2 amd c3):
            indexes.append(my_index)
            cond = True
        next_index += 1
    indexes.append(my_index)
    my_index += next_index
indexes.append(total_len - 1)

问题是此解决方案并不完美,有时会漏掉一行,因为重叠可能在前面几行,而不是在下一行

我正在寻找有关如何以更友好的方式解决此问题的想法,如果存在的话。

3 个答案:

答案 0 :(得分:1)

此处的方法应为:

  1. pandas.groupby按类别
  2. agg(Func)关于分组依据结果
  3. Func应该执行在类别(排序搜索,平衡树或其他任何类别)内找到最佳范围的逻辑

答案 1 :(得分:0)

您要合并所有相似的或仅合并两个连续的文档吗? 如果都相似,建议您先按类别对行进行排序,然后再对其他2列进行排序,并将相似的行压缩为一行。 如果仅连续2个,则检查下一个值是否在您设置的范围内,如果是,则将其合并。在这里,您可以了解如何:

merge rows pandas dataframe based on condition

答案 2 :(得分:0)

我不相信没有循环就可以进行数字比较,但是您可以至少使这种更简洁,更高效的一部分成为可能:

dfs = []
for seq in df.category.unique():
    dfs[seq] = df[df.category == seq]

请改为使用df.groupby('category').apply(drop_duplicates).droplevel(0),其中drop_duplicates是包含第二个循环的函数。然后将针对每个类别分别调用该函数,其数据框仅包含已过滤的行。输出将被组合回到单个数据帧中。数据框将是一个MultiIndex,其值为“ category”作为外部级别;可以使用droplevel(0)删除。

第二,在类别中,您可以按两个数字列中的第一列进行排序,以进一步提高速度:

def drop_duplicates(df):
    df = df.sort_values("sstart")
    ...

这将允许您在sstart列值超出范围时立即停止内部循环,而不是将每一行与其他行进行比较。