karakter sütunlarını böl ve dizede alan adlarını al


11

Birkaç sütun içine bilgi içeren bir sütun bölmek gerekiyor.
Kullanırdım tstrsplitama aynı tür bilgiler satırlar arasında aynı sırada değil ve değişken içindeki yeni sütunun adını çıkarmam gerekiyor. Bilmek önemli: birçok bilgi parçası olabilir (alanlar yeni değişkenler haline gelebilir) ve hepsini bilmiyorum, bu yüzden bir "tarla" çözümü istemiyorum.

Aşağıda sahip olduğum şeyin bir örneği var:

library(data.table)

myDT <- structure(list(chr = c("chr1", "chr2", "chr4"), pos = c(123L,
                  435L, 120L), info = c("type=3;end=4", "end=6", "end=5;pos=TRUE;type=2"
                  )), class = c("data.table", "data.frame"), row.names = c(NA,-3L))

#    chr pos                  info
#1: chr1 123          type=3;end=4
#2: chr2 435                 end=6
#3: chr4 120 end=5;pos=TRUE;type=2

Ve almak istiyorum:

#    chr pos end  pos type
#1: chr1 123   4 <NA>    3
#2: chr2 435   6 <NA> <NA>
#3: chr4 120   5 TRUE    2

Bunu almanın en kolay yolu çok takdir edilecektir! ( Not: Ben bir dplyr / tidyr yolu ile gitmek istemiyorum )

Yanıtlar:


5

Kullanma regexve stringipaketleri:

setDT(myDT) # After creating data.table from structure()

library(stringi)

fields <- unique(unlist(stri_extract_all(regex = "[a-z]+(?==)", myDT$info)))
patterns <- sprintf("(?<=%s=)[^;]+", fields)
myDT[, (fields) := lapply(patterns, function(x) stri_extract(regex = x, info))]
myDT[, !"info"]

    chr  pos type end
1: chr1 <NA>    3   4
2: chr2 <NA> <NA>   6
3: chr4 TRUE    2   5

Düzenleme: Doğru tip almak için görünüyor (?) type.convert()Kullanılabilir:

myDT[, (fields) := lapply(patterns, function(x) type.convert(stri_extract(regex = x, info), as.is = TRUE))]

Çok uzun bir uyarı alıyorum "Geçersiz .internal.selfref tespit edildi ve data.table (sığ) bir kopyasını alarak düzeltildi ..."
Moody_Mudskipper

Ayrıca türü ve sonu burada karakter, beklenen olup olmadığından emin değilim
Moody_Mudskipper

1
@Moody_Mudskipper Yorum yaptığınız için teşekkür ederiz. (1) (Bu uyarı (sanırım) data.table tarafından oluşturulan neden structure()bu sorunu önlemek için cevabı güncelledim (2) Amaç amaçlı karakterler ... Onları doğru ayrıştırmak zor olacağını hissettim ve ayrı bir soru gibi görünüyor. Cevabınızda olsa çözdünüz ve yeni bir şey öğrenip öğrenemeyeceğime bir göz
atacağım

4

Verilerinizin bir VCF dosyasından geldiğini tahmin ediyorum , eğer öyleyse bcftools - bu tür sorunlar için özel bir araç var .

Test için örnek VCF dosyası oluşturalım :

# subset some data from 1000genomes data
tabix -h ftp://ftp-trace.ncbi.nih.gov/1000genomes/ftp/release/20100804/ALL.2of4intersection.20100804.genotypes.vcf.gz 17:1471000-1472000 > myFile.vcf
# zip it and index:
bgzip -c myFile.vcf > myFile.vcf.gz
tabix -p vcf myFile.vcf.gz

Şimdi bcftools'u kullanabiliriz . Burada bir örnek olarak INFO sütunundan AF ve DP'yi ayarlıyoruz :

bcftools query -f '%CHROM %POS %INFO/AF %INFO/DP \n' myFile.vcf.gz 
17  1471199  1916 0.088
17  1471538  2445 0.016
17  1471611  2733 0.239
17  1471623  2815 0.003
17  1471946  1608 0.007
17  1471959  1612 0.014
17  1471975  1610 0.179

Daha fazla sorgu seçeneği için kılavuza bakın .


3

Biz bölünmüş olabilir ";"uzun geniş to-sonra tekrar bölmek yeniden şekillendirmek sonra "="uzun etmek çapında, daha sonra yeniden biçimlendirme arka:

dcast(
  melt(dt[,  paste0("col", 1:3) := tstrsplit(info, split = ";") ],
       id.vars = c("chr", "pos", "info"))[, -c("info", "variable")][
         ,c("x1", "x2") := tstrsplit(value, split = "=")][
           ,value := NULL][ !is.na(x1), ],
  chr + pos ~ x1, value.var = "x2")

#     chr pos end  pos type
# 1: chr1 123   4 <NA>    3
# 2: chr2 435   6 <NA> <NA>
# 3: chr4 120   5 TRUE    2

Geliştirilmiş / daha okunabilir bir sürüm:

dt[, paste0("col", 1:3) := tstrsplit(info, split = ";")
   ][, melt(.SD, id.vars = c("chr", "pos", "info"), na.rm = TRUE)
     ][, -c("info", "variable")
       ][, c("x1", "x2") := tstrsplit(value, split = "=")
         ][, dcast(.SD, chr + pos ~ x1, value.var = "x2")]

@Jaap Teşekkürler, işleri zincirlemenin daha iyi bir DT yolu olduğunu biliyordum.
zx8754

3

Şimdilik, aşağıdaki kodla istediğimi elde etmeyi başardım:

newDT <- reshape(splitstackshape::cSplit(myDT, "info", sep=";", "long")[, 
                  c(.SD, tstrsplit(info, "="))], 
                 idvar=c("chr", "pos"), direction="wide", timevar="V4", drop="info")
setnames(newDT, sub("V5\\.", "", names(newDT)))

newDT
#    chr pos type end  pos
#1: chr1 123    3   4 <NA>
#2: chr2 435 <NA>   6 <NA>
#3: chr4 120    2   5 TRUE

@ A5C1D2H2I1M1N2O1R2T1 (bunları yorumlarda yazan) sayesinde yukarıdaki satırları iyileştirmek için iki seçenek:

. cSplitönce bir çift ile dcast:

cSplit(cSplit(myDT, "info", ";", "long"), "info", "=")[, dcast(.SD, chr + pos ~ info_1, value.var = "info_2")]

. ile cSplit/ trstrplitve dcastyerine reshape:

cSplit(myDT, "info", ";", "long")[, c("t1", "t2") := tstrsplit(info, "=", fixed = TRUE)][, dcast(.SD, chr + pos ~ t1, value.var = "t2")]

1
Bir çift yapardım cSplitböyle,: cSplit(cSplit(myDT, "info", ";", "long"), "info", "=")[, dcast(.SD, chr + pos ~ info_1, value.var = "info_2")].
A5C1D2H2I1M1N2O1R2T1

1
Ya da, aynı konsepti: cSplitizledi tstrsplit, ardından dcast: cSplit(myDT, "info", ";", "long")[, c("t1", "t2") := tstrsplit(info, "=", fixed = TRUE)][, dcast(.SD, chr + pos ~ t1, value.var = "t2")].
A5C1D2H2I1M1N2O1R2T1

@ A5C1D2H2I1M1N2O1R2T1 Çok teşekkürler! Her ikisi de harika, çift cSplitseçenek için özel bir :-)
Cath

2

İşte böyle yapardım:

library(data.table)

myDT <- structure(list(chr = c("chr1", "chr2", "chr4"), pos = c(123L,
                                                                435L, 120L), info = c("type=3;end=4", "end=6", "end=5;pos=TRUE;type=2"
                                                                )), class = c("data.table", "data.frame"), row.names = c(NA,-3L))

R_strings <- paste0("list(", chartr(";", ",", myDT$info),")")
lists <- lapply(parse(text=R_strings),eval)
myDT[,info:=NULL]
myDT <- cbind(myDT,rbindlist(lists, fill = TRUE))
myDT
#>     chr pos type end  pos
#> 1: chr1 123    3   4   NA
#> 2: chr2 435   NA   6   NA
#> 3: chr4 120    2   5 TRUE

2019-11-29 tarihinde reprex paketi tarafından oluşturuldu (v0.3.0)


";" içine düştüm ve hoşlanmadım eval(parse(text=...))... ama yine de cevabın için teşekkürler
Cath

1
Kişisel tadıyla tartışamam ama parsekötü bir temsilcisi var, çünkü genellikle yanlış bir nedenle kullanılıyor, işte tam olarak uygun kullanım durumu, dizeden koda gidiyor. Metni biçimlendirdiniz, ancak R için biçimlendirmediniz ve listelere ad verdiniz, bu nedenle ilk satırım "a; b" yi "list (a, b)" olarak değiştirerek R listesinin kodunu oluşturur. Sonra değerlendiririz ve bir tablo oluştururuz.
Moody_Mudskipper

1

subİstenen her çıkarılan alan için ayrı çağrılar kullanabilirsiniz , örneğin type:

myDT$type <- sub("^.*\\btype=([^;]+)\\b.*$", "\\1", myDT$info)

Ortaya çıkacak tüm dosyaları bilmiyorum ve çok olabilirler, bu bir seçenek değil
Cath

1
Yeterince adil; Bu cevabı gönderdiğimde bunu bilmiyordum.
Tim Biegeleisen

Onu ekleyeceğim (btw istediğiniz çıktıyı vermiyorsunuz, cevabınız bazı satırları kaçırıyor ...)
Cath
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.