Diciamo che si dispone di un DataFrame di regioni (inizio, fine) coordinate e un altro DataFrame di posizioni che possono o meno rientrare in una determinata regione. Ad esempio:Unione di dataframe pandas in base alla relazione in più colonne
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
Una posizione rientra un'area se:
position['BP'] >= region['start'] &
position['BP'] <= region['end'] &
position['chromosome'] == region['chromosome']
Ogni posizione è garantita a cadere entro un massimo di una regione anche se potrebbe non cadere in nessuna.
Qual è il modo migliore per unire questi due dataframe in modo tale da accodare colonne aggiuntive per posizionarsi con la regione in cui ricade se cade in qualsiasi regione. Dando in questo caso più o meno il seguente output:
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
Un approccio è quello di scrivere una funzione per calcolare il rapporto che voglio e quindi utilizzare il metodo DataFrame.apply come segue:
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
Ma io spero che ci sia un modo più ottimizzato rispetto a fare ogni confronto in tempo O (N). Grazie!
Questo migliora decisamente le prestazioni. Grazie! – dylkot
Sfortunatamente, i miei file di dati sono troppo grandi per contenere df in memoria. Sto cercando di trovare una soluzione alternativa in cui carico la posizione e la regione in dataframes con un multiindice con cromosoma come indice esterno e quindi eseguo l'unione in modo indipendente per ciascun cromosoma. Sto elaborando questo codice ora, ma se qualcuno vede un modo migliore per farlo, per favore fatemelo sapere. Grazie. – dylkot