2014-07-23 3 views
5

영역 (시작, 끝) 좌표의 데이터 프레임과 주어진 영역 내에 있거나없는 위치의 다른 DataFrame이 있다고 가정 해 보겠습니다. 예를 들어 각각의 위치는에 속하지하지 않을 수도 있지만, 한 지역의 최대 내에 보장여러 열의 관계를 기반으로 한 팬더 데이터 프레임 병합

position['BP'] >= region['start'] & 
position['BP'] <= region['end'] & 
position['chromosome'] == region['chromosome'] 

:

region = pd.DataFrame({'chromosome': [1, 1, 1, 1, 2, 2, 2, 2], 'start': [1000, 2000, 3000, 4000, 1000, 2000, 3000, 4000], 'end': [2000, 3000, 4000, 5000, 2000, 3000, 4000, 5000]}) 
position = pd.DataFrame({'chromosome': [1, 2, 1, 3, 2, 1, 1], 'BP': [1500, 1100, 10000, 2200, 3300, 400, 5000]}) 
print region 
print position 


    chromosome end start 
0   1 2000 1000 
1   1 3000 2000 
2   1 4000 3000 
3   1 5000 4000 
4   2 2000 1000 
5   2 3000 2000 
6   2 4000 3000 
7   2 5000 4000 

     BP chromosome 
0 1500   1 
1 1100   2 
2 10000   1 
3 2200   3 
4 3300   2 
5 400   1 
6 5000   1 

위치가있는 경우 지역 내에.

이 두 데이터 프레임을 병합하는 가장 좋은 방법은 어떤 영역에 속하더라도 해당 영역에 속하는 추가 열을 추가하는 것입니다. 이 경우주기 대략 다음과 같은 출력 :

def within(pos, regs): 
    istrue = (pos.loc['chromosome'] == regs['chromosome']) & (pos.loc['BP'] >= regs['start']) & (pos.loc['BP'] <= regs['end']) 
    if istrue.any(): 
     ind = regs.index[istrue].values[0] 
     return(regs.loc[ind ,['start', 'end']]) 
    else: 
     return(pd.Series([None, None], index=['start', 'end'])) 

position[['start', 'end']] = position.apply(lambda x: within(x, region), axis=1) 
print position 

     BP chromosome start end 
0 1500   1 1000 2000 
1 1100   2 1000 2000 
2 10000   1 NaN NaN 
3 2200   3 NaN NaN 
4 3300   2 3000 4000 
5 400   1 NaN NaN 
6 5000   1 4000 5000 

하지만을 :

 BP chromosome start end 
0 1500   1 1000 2000 
1 1100   2 1000 2000 
2 10000   1 NA  NA 
3 2200   3 NA  NA 
4 3300   2 3000 4000 
5 400   1 NA  NA 
6 5000   1 4000 5000 

한 가지 방법은 다음과 같이 DataFrame.apply 방법을 사용하여 다음 내가 원하는 관계를 계산하는 함수를 작성하는 것입니다 O (N) 시간에 각 비교를하는 것보다 더 최적화 된 방법이 있기를 바란다. 감사!

답변

5

하나의 해결책은 할 것이다 내부 조인 position와 조인 왼쪽 수행 한 후 위반 행을 제외, chromosome에, 그리고 : 나는 내 자신이 문제를 해결하기 위해 발견

>>> df = pd.merge(position, region, on='chromosome', how='inner') 
>>> idx = (df['BP'] < df['start']) | (df['end'] < df['BP']) # violating rows 
>>> pd.merge(position, df[~idx], on=['BP', 'chromosome'], how='left') 
     BP chromosome end start 
0 1500   1 2000 1000 
1 1100   2 2000 1000 
2 10000   1 NaN NaN 
3 2200   3 NaN NaN 
4 3300   2 4000 3000 
5 400   1 NaN NaN 
6 5000   1 5000 4000 
+0

성능이 확실히 향상됩니다. 감사! – dylkot

+0

아쉽게도 데이터 파일이 너무 커서 메모리에 df를 유지할 수 없습니다. 저는 외부 인덱스로 염색체가있는 다중 인덱스를 사용하여 위치와 영역을 데이터 프레임에로드 한 다음 각 염색체에 대해 독립적으로 병합을 수행하는 대체 솔루션을 찾으려고합니다. 지금이 코드를 작성 중이지만 누구든지이 작업을 수행하는 더 좋은 방법을 알고 있다면 알려 주시기 바랍니다. 감사. – dylkot

0

가장 좋은 방법은 큰 데이터 셋은 pybedtools (http://pythonhosted.org/pybedtools/)에 의해 파이썬으로 싸여있는 bedtools의 intersect 메소드를 사용하고있었습니다. 문제는 실제로 두 세트의 영역을 인터레이킹하는 것입니다 (이 중 하나는 길이가 1입니다).

관련 문제