【问题标题】:Finding and deleting repeated data entries with two identical features identified by a third unique feature查找和删除具有由第三个唯一特征标识的两个相同特征的重复数据条目
【发布时间】:2013-02-13 07:04:21
【问题描述】:

所以我使用此代码在主序列中打印子序列的开始和停止位置,表示为 SOURCE。主序列由 GENE 识别。 GENE 中的一些序列有 DIRECTION 两个组成部分,+ 和 -,它们被视为唯一序列。但是,我没有意识到的是,在首先生成数据集时(通过将许多 SOURCE 序列的文件与 GENE 序列进行比对),我有多个实例存在多个 SOURCE 序列的“有效”比对针对基因序列。我需要一种方法从 SOURCE 序列中删除条目,在相同数量的 SOURCE 序列的情况下,GENE 序列中出现次数最少或 POS1 到最终 POS2 的最小范围。我在下面有一个示例输出,其中包含一个说明性示例。

这是我的 Python 代码:

import pandas
import pandas as pd
import sys
import csv

##sys.stdout = open("Sampletest2d.txt", "w")
##data = pd.read_csv('Sampletest2.txt', sep='\t')
sys.stdout = open("ExonFileTry1Part3.txt", "w")
data = pd.read_csv('ExonFileTry1.txt', sep='\t')
groups = data.groupby(['GENE', 'DIRECTION'])

fixedgroups = []

for (gene_id, strand), group in groups:
    #print gene_id, strand
    if strand == '+':
        group['POS-1'] = group.POS1
        group['POS-2'] = group.POS2
    else:
        group['POS-1'] = group.POS2
        group['POS-2'] = group.POS1
    #print group
    fixedgroups.append(group)
print fixedgroups

数据集(制表符分隔)

GENE    DIRECTION   POS1    POS2    SOURCE
TT-1    +   1   16  A1
TT-1    +   130 289 A1
TT-1    +   353 438 A1
TT-1    +   519 580 A1
TT-1    +   665 742 A1
TT-1    +   813 864 A1
TT-1    +   931 975 A1
TT-1    +   1053    1166    A1
TT-1    +   1   16  B2
TT-1    +   130 289 B2
TT-1    +   353 438 B2
TT-1    +   519 580 B2
TT-1    +   665 742 B2
TT-1    +   813 864 B2
TT-1    +   931 975 B2
TT-1    +   1053    1161    B2
BB-2    +   3   659 C3
BB-2    +   3   640 D4
BB-2    -   1093    426 E5
BB-2    -   1093    508 F6
EE-3    +   1   95  G7
EE-3    +   155 377 G7
EE-3    +   439 513 G7
EE-3    +   577 840 G7
EE-3    +   1   95  H8
EE-3    +   155 377 H8
EE-3    +   439 513 H8
EE-3    -   840 577 I9
EE-3    -   513 439 I9
EE-3    -   377 155 I9
EE-3    -   840 577 J10
EE-3    -   513 458 J10

有时一个 GENE 有多个 SOURCE 序列,并且来自一个 SOURCE 的序列比另一个多。但是,有时来自两个不同 SOURCE 的序列数量相同,在这种情况下,我需要保留该 SOURCE 的第一个 POS1 和最后一个 POS2 之间具有最大值范围的 SOURCE。

例如,在 + DIRECTION 的 GENE TT-1 中,有两个 SOURCE 集 A1 和 B2,它们都有 8 个条目。但是,SOURCE A1 的最终 POS2 为 1166,而 B2 的最终 POS2 为 1161,因此 B2 的范围较小,应该删除。

我花了令人难以置信的时间来了解如何做我已经做过的事情,而且那是基于类似的代码开始的。我觉得我知道我想在这里做什么,但我只是不知道语法,因为我的计算机科学知识非常有限。提前感谢您的帮助!

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    这是@D.A. 答案的一个变体:

    首先,一些样板设置:

    import pandas as pd
    import io
    
    data = '''\
    GENE    DIRECTION   POS1    POS2    SOURCE
    TT-1    +   1   16  A1
    TT-1    +   130 289 A1
    TT-1    +   353 438 A1
    TT-1    +   519 580 A1
    TT-1    +   665 742 A1
    TT-1    +   813 864 A1
    TT-1    +   931 975 A1
    TT-1    +   1053    1166    A1
    TT-1    +   1   16  B2
    TT-1    +   130 289 B2
    TT-1    +   353 438 B2
    TT-1    +   519 580 B2
    TT-1    +   665 742 B2
    TT-1    +   813 864 B2
    TT-1    +   931 975 B2
    TT-1    +   1053    1161    B2
    BB-2    +   3   659 C3
    BB-2    +   3   640 D4
    BB-2    -   1093    426 E5
    BB-2    -   1093    508 F6
    EE-3    +   1   95  G7
    EE-3    +   155 377 G7
    EE-3    +   439 513 G7
    EE-3    +   577 840 G7
    EE-3    +   1   95  H8
    EE-3    +   155 377 H8
    EE-3    +   439 513 H8
    EE-3    -   840 577 I9
    EE-3    -   513 439 I9
    EE-3    -   377 155 I9
    EE-3    -   840 577 J10
    EE-3    -   513 458 J10'''
    
    df = pd.read_table(io.BytesIO(data), sep='\t')
    

    现在我们添加RANGESUMRANGE 列,就像@D.A.做了:

    df['RANGE'] = abs(df['POS2']-df['POS1'])
    df['SUMRANGE'] = df.groupby(["GENE", "DIRECTION", "SOURCE"])['RANGE'].cumsum()
    print(df)
    #     GENE DIRECTION  POS1  POS2 SOURCE  RANGE  SUMRANGE
    # 0   TT-1         +     1    16     A1     15        15
    # 1   TT-1         +   130   289     A1    159       174
    # 2   TT-1         +   353   438     A1     85       259
    # 3   TT-1         +   519   580     A1     61       320
    # 4   TT-1         +   665   742     A1     77       397
    # 5   TT-1         +   813   864     A1     51       448
    # 6   TT-1         +   931   975     A1     44       492
    # 7   TT-1         +  1053  1166     A1    113       605
    # 8   TT-1         +     1    16     B2     15        15
    # 9   TT-1         +   130   289     B2    159       174
    # 10  TT-1         +   353   438     B2     85       259
    # 11  TT-1         +   519   580     B2     61       320
    # 12  TT-1         +   665   742     B2     77       397
    # 13  TT-1         +   813   864     B2     51       448
    # 14  TT-1         +   931   975     B2     44       492
    # 15  TT-1         +  1053  1161     B2    108       600
    # 16  BB-2         +     3   659     C3    656       656
    # 17  BB-2         +     3   640     D4    637       637
    # 18  BB-2         -  1093   426     E5    667       667
    # 19  BB-2         -  1093   508     F6    585       585
    # 20  EE-3         +     1    95     G7     94        94
    # 21  EE-3         +   155   377     G7    222       316
    # 22  EE-3         +   439   513     G7     74       390
    # 23  EE-3         +   577   840     G7    263       653
    # 24  EE-3         +     1    95     H8     94        94
    # 25  EE-3         +   155   377     H8    222       316
    # 26  EE-3         +   439   513     H8     74       390
    # 27  EE-3         -   840   577     I9    263       263
    # 28  EE-3         -   513   439     I9     74       337
    # 29  EE-3         -   377   155     I9    222       559
    # 30  EE-3         -   840   577    J10    263       263
    # 31  EE-3         -   513   458    J10     55       318
    

    对于每一个具有共同GENE和DIRECTION的组,记录SUMRANGE最大的行的索引:

    idx = df.groupby(["GENE", "DIRECTION"])['SUMRANGE'].agg(lambda col: col.idxmax())
    print(idx)
    # GENE  DIRECTION
    # BB-2  +            16
    #       -            18
    # EE-3  +            23
    #       -            29
    # TT-1  +             7
    # Name: SUMRANGE
    

    选择df 的子DataFrame,其列GENE、DIRECTION 和SOURCE 以及idx 给出的行:

    dfm = df.ix[idx, ['GENE','DIRECTION','SOURCE']]
    print(dfm)
    #     GENE DIRECTION SOURCE
    # 16  BB-2         +     C3
    # 18  BB-2         -     E5
    # 23  EE-3         +     G7
    # 29  EE-3         -     I9
    # 7   TT-1         +     A1
    

    dfdfm 进行内部合并。键是dfdfm 的公共列的交集——即GENE、DIRECTION 和SOURCE。 “内部”合并只保留dfdfm 共享相同键的那些行。所以在合并的 DataFrame 中,df 的 GENE、DIRECTION 和 SOURCE 必须匹配 dfm 的 GENE、DIRECTION 和 SOURCE。因此,所有带有错误 SOURCE 的行都会被删除:

    result = pd.merge(df, dfm, how = 'inner')
    print(result)
    #     GENE DIRECTION  POS1  POS2 SOURCE  RANGE  SUMRANGE
    # 0   TT-1         +     1    16     A1     15        15
    # 1   TT-1         +   130   289     A1    159       174
    # 2   TT-1         +   353   438     A1     85       259
    # 3   TT-1         +   519   580     A1     61       320
    # 4   TT-1         +   665   742     A1     77       397
    # 5   TT-1         +   813   864     A1     51       448
    # 6   TT-1         +   931   975     A1     44       492
    # 7   TT-1         +  1053  1166     A1    113       605
    # 8   BB-2         +     3   659     C3    656       656
    # 9   BB-2         -  1093   426     E5    667       667
    # 10  EE-3         +     1    95     G7     94        94
    # 11  EE-3         +   155   377     G7    222       316
    # 12  EE-3         +   439   513     G7     74       390
    # 13  EE-3         +   577   840     G7    263       653
    # 14  EE-3         -   840   577     I9    263       263
    # 15  EE-3         -   513   439     I9     74       337
    # 16  EE-3         -   377   155     I9    222       559
    

    【讨论】:

    • 您好,感谢您的好评。通读一遍,看起来你完全符合我的要求。尽管line 60, in <module> result = pd.merge(data, dfm, how = 'inner') AttributeError: 'module' object has no attribute 'merge' 我应该导入其他东西以使熊猫正常工作,但最后我得到了一个错误?谢谢!
    • 对不起;我想不出pd.merge 应该引发AttributeError 的合理原因。 The merge function 至少从 0.6 版开始就成为 pandas 的一部分。如果您在交互式提示或 IDE 中工作,您可能想尝试将代码保存到文件(例如 script.py)并从命令行运行 python script.py。这可能会消除一些可能的错误来源。
    • 我从 IDLE 运行它,但我尝试了命令行选项并得到了同样的错误。这可能与我加载数据的方式有关吗?我阅读了您链接的文档,似乎我应该是这里的薄弱环节,因为 pd.merge 绝对是一件事......
    • 等等——应该是pd.merge(...)而不是data.merge(...)
    • 不知道这是怎么回事。固定的。非常感谢你的帮助。我什至想出了如何让它打印:P
    【解决方案2】:

    我不是 100% 确定我理解您写的所有内容,但我跳过了您的数据和“例如”段落,其中说“源 A1 的最终 POS2 为 1166,而 B2 的最终 POS2 是1161,所以B2的范围较小,应该删除”。我将“TT-1 +”和“TT-1 -”视为不同的实体,并且我正在对每一行的范围求和。我想这就是你想要的。

    向 DataFrame 添加一个 RANGE 列

    df['RANGE'] = abs(df['POS2']-df['POS1'])
    

    现在为每个序列、来源组合累积每个来源。

    df['SUMRANGE'] = df.groupby(["GENE", "DIRECTION", "SOURCE"])['RANGE'].cumsum()
    

    为每个序列提取具有最大 'SUMRANGE' 的行的索引。

    dfm = pandas.DataFrame(df.ix[df.groupby(["GENE", "DIRECTION"]).agg(lambda df: df.idxmax())['SUMRANGE']])
    

    设置索引以用于接下来的join 函数。

    dfm.index = pandas.MultiIndex.from_arrays([dfm['GENE'], dfm['DIRECTION']])
    

    加入 df 和 dfm。

    dfj = df.join(other=dfm['SOURCE'], on=['GENE', 'DIRECTION'], rsuffix='.r')
    

    现在根据“SOURCE”是否与“SOURCE.r”相同来过滤 dfj。

    dfj[dfj.apply(lambda x: x['SOURCE'] == x['SOURCE.r'], axis=1)]
    
        GENE DIRECTION  POS1  POS2 SOURCE  RANGE  SUMRANGE SOURCE.r
    0   TT-1         +     1    16     A1     15        15       A1
    1   TT-1         +   130   289     A1    159       174       A1
    2   TT-1         +   353   438     A1     85       259       A1
    3   TT-1         +   519   580     A1     61       320       A1
    4   TT-1         +   665   742     A1     77       397       A1
    5   TT-1         +   813   864     A1     51       448       A1
    6   TT-1         +   931   975     A1     44       492       A1
    7   TT-1         +  1053  1166     A1    113       605       A1
    16  BB-2         +     3   659     C3    656       656       C3
    18  BB-2         -  1093   426     E5    667       667       E5
    20  EE-3         +     1    95     G7     94        94       G7
    21  EE-3         +   155   377     G7    222       316       G7
    22  EE-3         +   439   513     G7     74       390       G7
    23  EE-3         +   577   840     G7    263       653       G7
    27  EE-3         -   840   577     I9    263       263       I9
    28  EE-3         -   513   439     I9     74       337       I9
    29  EE-3         -   377   155     I9    222       559       I9
    

    当然,您可以根据需要从dfj 中删除不需要的列。作为参考,这是我开始使用的 DataFrame。

    In [2]: df
    Out[2]: 
        GENE DIRECTION  POS1  POS2 SOURCE
    0   TT-1         +     1    16     A1
    1   TT-1         +   130   289     A1
    2   TT-1         +   353   438     A1
    3   TT-1         +   519   580     A1
    4   TT-1         +   665   742     A1
    5   TT-1         +   813   864     A1
    6   TT-1         +   931   975     A1
    7   TT-1         +  1053  1166     A1
    8   TT-1         +     1    16     B2
    9   TT-1         +   130   289     B2
    10  TT-1         +   353   438     B2
    11  TT-1         +   519   580     B2
    12  TT-1         +   665   742     B2
    13  TT-1         +   813   864     B2
    14  TT-1         +   931   975     B2
    15  TT-1         +  1053  1161     B2
    16  BB-2         +     3   659     C3
    17  BB-2         +     3   640     D4
    18  BB-2         -  1093   426     E5
    19  BB-2         -  1093   508     F6
    20  EE-3         +     1    95     G7
    21  EE-3         +   155   377     G7
    22  EE-3         +   439   513     G7
    23  EE-3         +   577   840     G7
    24  EE-3         +     1    95     H8
    25  EE-3         +   155   377     H8
    26  EE-3         +   439   513     H8
    27  EE-3         -   840   577     I9
    28  EE-3         -   513   439     I9
    29  EE-3         -   377   155     I9
    30  EE-3         -   840   577    J10
    31  EE-3         -   513   458    J10
    

    【讨论】:

    • 感谢您的精彩帖子。哈哈抱歉有点含糊,我想是因为我花了这么多时间,我忘了它可能不清楚。我首先尝试了 Unutbu 的解决方案,只是因为我更好地理解了他的解释。但是,我在使用.join 加入数据框和dfm 时遇到了类似的错误。我得到KeyError: "no item named <class 'pandas.core.frame.DataFrame'>\nIndex: 700 entries, 330.0 to 1226.0\nData columns:\nGENE 700 non-null values\nDIRECTION 700 non-null values\nSOURCE 700 non-null values\ndtypes: object(3)"
    猜你喜欢
    • 2017-11-21
    • 2019-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 2022-04-26
    • 1970-01-01
    相关资源
    最近更新 更多