Fråga:
Sammanfoga sängposter baserat på namn
bli
2017-08-10 17:46:40 UTC
view on stackexchange narkive permalink

Jag genererade en fil som börjar med följande sängrader:

  $ head -6 /tmp/bed_with_gene_ids.bedI 3746 3909 "WBGene00023193". -I 3746 3909 "WBGene00023193". -I 4118 4220 "WBGene00022277". -I 4118 4358 "WBGene00022277". -I 4118 10230 "WBGene00022277". -I 4220 4223 "WBGene00022277". -  

Jag vill slå samman dem baserat på namnfältet (den fjärde kolumnen), med min för start och max för slutet. Andra fält förväntas vara desamma för alla poster med samma namn.

Förväntat resultat:

  I 3746 3909 "WBGene00023193". -I 4118 10230 "WBGene00022277". -  

Jag hittade en potentiell lösning baserad på bedtools groupby här: https://www.biostars.org/p/145751/#145775


Exempeldata:

  cat genes.bedchr14 49894259 49895806 ENSMUST00000053290 0.000000 ... chr14 49894873 49894876 ENSMUST00000053290 0.000000. ..chr14 49894876 49895800 ENSMUST00000053291 0,000000 ... chr14 49895797 49895800 ENSMUST00000053291 0,000000 ... chr14 49901908 49901941 ENSMUST00000053291 0,000000 ...  

Exempel på utdataqu:

  sortera -k4,4 gener.bädd \ | groupBy -g 1,4 -c 4,2,3 -o antal, min, max \ | awk -v OFS = '\ t' '{skriv ut $ 1, $ 4, $ 5, $ 2, $ 3}' chr14 49894259 49895806 ENSMUST00000053290 2chr14 49894876 49901941 ENSMUST00000053291 3  

Men:

  1. Jag förstår inte gruppenBet beteende (Varför -g 1,4 och inte bara -g 4 ?, Varför -c 4,2,3 i den här ordningen och ordna sedan om saker med awk?)

  2. Den här koden fungerar inte fungerar för mig.

Det här är vad som händer när jag försöker lösningen ovan:

  $ head -3 /tmp/bed_with_gene_ids.bed | sängverktyg gruppby -g 1,4 -c 4,2,3 -o antal, min, max | awk -v OFS = '\ t' '{print $ 1, $ 4, $ 5, $ 2, $ 3}' 3 3746 4220  

Här är försök baserat på vad jag trodde kunde fungera enligt dokumentationen:

  $ head -6 /tmp/bed_with_gene_ids.bed | sängverktyg gruppby -g 4 -c 1,2,3,4,5,6 -o först, min, max, distinkt, först, förstI 3746 10230 "WBGene00022277", "WBGene00023193". - $ head -6 /tmp/bed_with_gene_ids.bed | sängverktyg gruppby -g 4 -c 1,2,3,4,5,6 -o först, min, max, sista, första, förstI 3746 10230 "WBGene00022277". - $ head -6 /tmp/bed_with_gene_ids.bed | sängverktyg gruppby -g 4 -c 1,2,3,5,6 -o först, min, max, första, förstI 3746 10230. -  

Jag förstår inte varför när jag grupperar baserat på den fjärde kolumnen, för vilken jag har två distinkta värden, kan jag inte få två rader i den resulterande utdata.

Jag förstår utifrån kommentarerna på dokumentationssidan att dokumentationen inte är uppdaterad. I synnerhet finns det ett -fullt -alternativ som behövs om man vill att alla fält ska matas ut. Efter att ha läst igen ovan nämnda lösning tror jag att jag nu förstår orsaken till de flera kolumnerna för -g-alternativet och för awk -omläggningen. Därav följande försök.

  $ head -6 /tmp/bed_with_gene_ids.bed | sängverktyg gruppby -g 1,4,5,6 -c 2,3 -o min, max -full I 3746 3909 "WBGene00023193". - 3746 10230  

Men detta ger mig fortfarande inte två rader.

Finns det andra verktyg som kan göra vad jag vill effektivt?


Redigera: Lösning

Enligt detta svar är problemet med sängverktyg att det finns ett fel i den senaste versionen (2.26.0 från augusti 2017). För att ha en funktionell bedtools groupby måste man hämta utvecklingsversionen från github.

Med github-versionen av sängverktyg kan jag nu få det förväntade resultatet enligt följande:

  $ head -6 /tmp/bed_with_gene_ids.bed | sängverktyg gruppby -g 1,4,5,6 -c 2,3 -o min, max | awk -v OFS = "\ t" '{skriv ut $ 1, $ 5, $ 6, $ 2, $ 3, $ 4}' I 3746 3909 "WBGene00023193". -I 4118 10230 "WBGene00022277". -  

Jag inkluderar fält 1, 5 och 6 i -g (förutom fält 4) för att få dem att skrivas ut. I min sängfil ska de vara desamma för ett visst värde i fält 4. awk -delen behövs eftersom man tydligen inte har total kontroll på utmatningsordningen: -g kod> fält kommer före fälten -c .

Vad vill du göra med poäng- och strängfält om de skiljer sig mellan linjerna, eller händer det aldrig?
Egentligen bryr jag mig inte om poängfältet och skulle helst sätta det till "." om det inte redan är fallet. Jag kan inte garantera att strandfältet alltid kommer att vara detsamma, men eftersom dessa sänglinjer kommer från transkriptionsanteckningar vars gen_id jag har lagt i namnfältet antar jag att det i allmänhet kommer att vara sant att för samma namn kommer det samma. Jag borde dock kontrollera detta.
Fem svar:
OrdiNeu
2017-08-10 22:40:41 UTC
view on stackexchange narkive permalink

Även om du inte nämner det, antar jag att du använder sängverktyg v2.26.0. Version 2.26.0 av groupBy innehåller en bugg som du har stött på (den åtgärdades strax efter utgivningen, så du måste antingen använda en version innan felet introducerades eller kompilera den aktuella källkoden själv från https://github.com/arq5x/bedtools2)

v2.26.0:

  local10: ~ / Documents / tmp $ cat asdf. säng I 3746 3909 WBGene00023193. -I 3746 3909 WBGene00023193. -I 4118 4220 WBGene00022277. -I 4118 4358 WBGene00022277. -I 4118 10230 WBGene00022277. -I 4220 4223 WBGene00022277. -local10: ~ / Documents / tmp $ groupBy -i asdf.bed -g 4 -c 2,3 -o min, max 3746 10230 

v2.26.0-125-g52db654 (IE sammanställa källkoden från github):

  local10: ~ / Documents / tmp $ bedtools2 / bin / groupBy -i asdf.bed -g 4 -c 2,3 -o min, maxWBGene00023193 3746 3909WBGene00022277 4118 10230  

För att svara på dina frågor:

1) Du kanske märker att min utdata ovan ger de grupperade kolumnerna först; du måste omorganisera utdata via awk för att få tillbaka den i ordning. När det gäller varför de valde att gruppera i båda kolumnerna 1 och 4: om du har samma namn på flera kromosomer kanske du vill behandla dem som separata funktioner.

2) Versionsskillnader, som anges i första delen av mitt svar.


För att faktiskt slå samman filen:

Se till att köra den med en annan version än v2.26.0 (som Devon Ryan skriver i kommentarerna, kanske du vill lägga till kolumn 6 till -g för att göra den strängspecifik):

  ./bedtools2/bin/groupBy -i asdf.bed -g 1,4 -c 2 , 3,5,6 -o min, max, första, första \ | awk -v OFS = '\ t' '{skriv ut $ 1, $ 3, $ 4, $ 2, $ 5, $ 6}' I 3746 3909 WBGene00023193. -I 4118 10230 WBGene00022277. -  
Om du inkluderar 6 i `-g 1,4` så har du nytta av att inte slå samman gener på olika strängar. UCSC har ibland dessa och de är verkligen inte samma gen och bör inte slås ihop. Du behöver inte 1 i `-c` eller 6 om du lägger till den i` -g`.
Ian Sudbery
2017-08-10 18:45:38 UTC
view on stackexchange narkive permalink

Du kan göra det med verktyget CGAT :

cgat bed2bed --method = merge --merge-by-name -Jag bed_with_gene_ids.bed

Att installera ett sådant massivt paket kan dock vara överdrivet för den här uppgiften.

Det händer att cgat redan är installerat på min dator (även om jag glömde i vilket syfte). Jag försökte kommandot du föreslår och jag slutar med en duplikat av `I 3746 3909" WBGene00023193 ". -`. Beviljas att det fanns dubbla rader i originalsängen. Men förväntas detta beteende?
Dessutom, om jag kör detta på hela filen och inte bara de första 6 raderna, efter ett tag, misslyckas programmet på 'TypeError:' <'stöds inte mellan instanser av' Bed 'och' Bed ''. Jag uppgraderar cgat för att se om felet kvarstår.
Jag rapporterade problemen här: https://github.com/CGATOxford/cgat/issues/347
Ditt första problem är inte så långt jag känner till det avsedda beteendet. Och jag är ganska säker på att den andra inte är avsedd. Jag föreslår att du skickar en felrapport.
Vi korsade inlägg!
Cotton Seed
2017-08-14 03:27:07 UTC
view on stackexchange narkive permalink

Du kan göra det enkelt med Hail. Hail använder främst BED-filer för att kommentera genetiska datamängder (se det senaste annotate_variants_table -exemplet), men du kan manipulera BED-filer med hjälp av Hails allmänna möjligheter för att manipulera avgränsade textfiler. Till exempel:

  $ cat genes.bedI 3746 3909 "WBGene00023193". -I 3746 3909 "WBGene00023193". -I 4118 4220 "WBGene00022277". -I 4118 4358 "WBGene00022277". -I 4118 10230 "WBGene00022277". -I 4220 4223 "WBGene00022277". -  

Hail-skriptet (pythonkod):

  från hagelimport * hc = HailContext () (hc .import_table ('genes.bed', impute = True, no_header = True) .aggregate_by_key ('f0 = f0, f3 = f3', 'f1 = f1.min (), f2 = f2.max (), f4 = ".", f5 = "-"' ) .select (['f0', 'f1', 'f2', 'f3', 'f4', 'f5']) .export ('genes_merged.bed', header = False))  

Resultatet:

  $ cat genes_merged.bed I 3746 3909 WBGene00023193. -I 4118 10230 WBGene00022277. -  

Jag aggregerar över krom och namn så att den här lösningen inte slår samman poster på olika kromosomer. välj är nödvändigt för att ordna om fälten eftersom aggregat_by_key placerar nycklarna som aggregeras först.

Upplysning: Jag jobbar med Hail.

Alex Reynolds
2017-08-10 23:48:21 UTC
view on stackexchange narkive permalink
  $ cut -f4-6 in.bed | sed's / \ t / _ / g '| sortera | uniq | awk -F'_ '' {system ("grep" $ 1 "in.bed | bedops --merge -"); skriva ut $ 0; } '| klistra in -d "\ t" - - | sed's / _ / \ t / g '| sort-bed - > answer.bed  

Givet din provingång:

  $ mer in.bedI 3746 3909 "WBGene00023193". -I 3746 3909 "WBGene00023193". -I 4118 4220 "WBGene00022277". -I 4118 4358 "WBGene00022277". -I 4118 10230 "WBGene00022277". -I 4220 4223 "WBGene00022277". -  

answer.bed -filen:

  $ more answer.bedI 3746 3909 "WBGene00023193". -I 4118 10230 "WBGene00022277". -  

Sortering med sort-säng är användbart i slutet, så att du kan pipa det eller arbeta med det med andra BEDOPS-verktyg eller andra verktyg som nu acceptera sorterad BED-ingång.

Streaming är i allmänhet ett ganska effektivt sätt att göra saker.


Så här fungerar

Här är rörledningen igen:

  $ cut -f4-6 in.bed | sed's / \ t / _ / g '| sortera | uniq | awk -F'_ '' {system ("grep" $ 1 "in.bed | bedops --merge -"); skriva ut $ 0; } '| klistra in -d "\ t" - - | sed's / _ / \ t / g '| sort-bed - > answer.bed  

Vi börjar med att klippa kolumnerna 4 till 6 (id, poäng och sträng), ersätta flikar med understrykningar, sortera och ta bort dubbletter:

  klipp -f4-6 in.bädd | sed's / \ t / _ / g '| sortera | uniq  

Vad vi får ut av detta är en sorterad lista med "nålar" - en för varje kombination av ID-poäng-sträng: en ID-nål - som vi kan använda för att grep eller filtrera den ursprungliga BED-filen.

Den här listan skickas till awk som för varje ID-nål kör grep mot den ursprungliga BED-filen och rör undermängden till bedops --merge - , som sammanfogar överlappande intervall.

Observera att sammanslagning endast fungerar för överlappande intervall. Sammanfogning är inte nödvändigtvis detsamma som att returnera ett min-max-par, och denna pipeline kommer att brytas om det finns intervall som inte överlappar varandra. Men du kan ändra uttalandet awk till bearbeta inmatningsintervallen och returnera minsta och maximala intervallkoordinater, om det verkligen är vad du vill, genom att spåra min- och maxvärdena över alla intervall som kommer in i awk och skriva ut ett slutintervall med END -block.

Kommandot system skriver ut det sammanslagna intervallet på en rad. Följande utskrift $ 0 uttalande skriver ut nålen på nästa rad:

  awk -F'_ '' {system ("grep" $ 1 "in.bed | bedops --sammanfoga - "); skriva ut $ 0; } ' 

Vi tar varje par alternerande linjer och linjäriserar dem igen med klistra in . Resultatet innehåller nu fyra kolumner: de tre kolumnerna för varje sammanslaget intervall och ID-nålen.

Vi använder sedan sed för att ersätta understrykningar med flikar, så att vi förvandlar ID-nålen tillbaka till tre, flikavgränsade ID-poängsträngkolumner:

  klistra in -d "\ t" - - | sed's / _ / \ t / g ' 

Utgången är nu en BED-fil med sex kolumner, men den ordnas efter den sorteringsordning vi använde på ID-nålar längre upp i pipeline, som vi inte vill ha. Vad vi verkligen vill ha är BED som sorteras per BEDOPS sorteringsbädd , så att vi kan göra fler inställda operationer och få ett korrekt resultat. Så vi rör detta till sort-bed - för att skriva en sorterad fil till answer.bed:

  sort-bed - > svar. säng  
Tack för svaret, det fungerar, och jag tror att jag förstod hur. Kanske kan några förklaringar om de olika stegen vara användbara.
terdon
2017-08-10 18:59:49 UTC
view on stackexchange narkive permalink

Om du är 100% säker på att allt utom start- och slutpositionerna kommer att vara desamma för alla rader som delar ett namn, kan du bara göra det själv. Till exempel, i Perl:

  $ perl -fält '$ start {$ F [3]} || = $ F [1]; if ($ F [1] < $ start {$ F [3]}) {$ start {$ F [3]} = $ F [1]} if ($ F [2] > $ end {$ F [3 ]}) {$ end {$ F [3]} = $ F [2]} $ chr {$ F [3]} = $ F [0]; $ rest {$ F [3]} = gå med i "\ t", @F [4, $ # F]; SLUT {foreach $ n (key% chr) {print "$ chr {$ n} \ t $ start {$ n} \ t $ end {$ n} \ t $ n \ t $ rest {$ n}"}} 'file.bed I 3746 3909 "WBGene00023193". -I 4118 10230 "WBGene00022277". -  
Jag hoppades att det redan fanns ett effektivt verktyg och skulle undvika att jag skulle uppfinna hjulet på ett långsamt skriptspråk.
@bli absolut, det är mycket mer meningsfullt. Jag tänkte bara att detta är tillräckligt enkelt, så jag kan lika gärna ge en skriptlösning. Men ja, det här kommer att vara långsamt och är också mycket naivt så det kommer att gå sönder om dina filer är lite annorlunda.


Denna fråga och svar översattes automatiskt från det engelska språket.Det ursprungliga innehållet finns tillgängligt på stackexchange, vilket vi tackar för cc by-sa 3.0-licensen som det distribueras under.
Loading...