चरित्र स्तंभों को विभाजित करें और स्ट्रिंग में फ़ील्ड के नाम प्राप्त करें


11

मुझे एक स्तंभ को विभाजित करने की आवश्यकता है जिसमें कई स्तंभों की जानकारी है।
मैं उपयोग करूंगा tstrsplitलेकिन उसी तरह की जानकारी पंक्तियों के बीच एक ही क्रम में नहीं है और मुझे चर के भीतर नए कॉलम का नाम निकालने की आवश्यकता है। यह जानना महत्वपूर्ण है: जानकारी के कई टुकड़े हो सकते हैं (नए चर बनने के लिए क्षेत्र) और मैं उन सभी को नहीं जानता, इसलिए मुझे "फ़ील्ड बाय फ़ील्ड" समाधान नहीं चाहिए।

नीचे मेरे पास एक उदाहरण है:

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

और मैं प्राप्त करना चाहूंगा:

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

एक सबसे सरल तरीका है कि बहुत सराहना की जाएगी पाने के लिए! ( नोट: मैं दुस्साहसी / तीखे तरीके से जाने को तैयार नहीं हूं )

जवाबों:


5

उपयोग regexऔर stringiपैकेज:

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

संपादित करें: सही प्रकार यह प्राप्त करने के लिए लगता है (?) type.convert()के लिए इस्तेमाल किया जा सकता है:

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

मुझे एक बहुत लंबी चेतावनी मिलती है "अवैध .intern.selfref का पता लगाया और डेटा की एक (उथली) प्रति लेकर तय की गई। स्थिर ..."
मूडी_मॉडस्किपर

यहां भी टाइप और एंड कैरेक्टर हैं, यकीन नहीं तो उम्मीद है कि
Moody_Mudskipper

1
@Moody_Mudskipper टिप्पणी करने के लिए धन्यवाद। (1) (यह चेतावनी है (मुझे लगता है) data.table की वजह से है। structure()मैंने इस मुद्दे से बचने के लिए उत्तर अपडेट किया है (2) वे उद्देश्य पर चरित्र हैं ... मुझे लगा कि उन्हें सही ढंग से पार्स करना मुश्किल होगा और एक अलग प्रश्न। ऐसा लगता है कि आपने इसे अपने उत्तर में हल कर लिया है और मैं देखूंगा और देखूंगा कि क्या मैं कुछ नया सीख सकता हूं।
sindri_baldur

4

मुझे लग रहा है कि आपका डेटा VCF फ़ाइल से आ रहा है , अगर ऐसा है तो ऐसी समस्याओं के लिए एक समर्पित उपकरण है - bcftools

आइए परीक्षण के लिए उदाहरण VCF फ़ाइल बनाएँ :

# 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

अब हम bcftools का उपयोग कर सकते हैं । यहाँ एक उदाहरण के रूप में हम जानकारी कॉलम से AF और DP को कम कर रहे हैं :

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

अधिक क्वेरी विकल्पों के लिए मैनुअल देखें ।


3

हम ";"फिर से लंबे-चौड़े आकार में विभाजित कर सकते हैं, फिर से फिर से विभाजित हो सकते हैं, फिर "="लंबे-से-चौड़े तक वापस आ सकते हैं:

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

एक बेहतर / अधिक पठनीय संस्करण:

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")]

@ जाप धन्यवाद, मुझे पता था कि चीजों को चट करने का एक बेहतर डीटी तरीका था।
zx8754

3

अभी के लिए, मैं निम्नलिखित कोड के साथ जो चाहता हूं उसे पाने में कामयाब रहा:

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 (जिन्होंने उन्हें टिप्पणियों में दिया) के लिए धन्यवाद:

cSplitपहले एक डबल के साथ dcast:

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

। के बजाय cSplit/ trstrplitऔर :dcastreshape

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

1
मैं cSplitइस तरह एक डबल करूँगा cSplit(cSplit(myDT, "info", ";", "long"), "info", "=")[, dcast(.SD, chr + pos ~ info_1, value.var = "info_2")]:।
a5C1D2H2I1M1N2O1R2T1

1
या, इसी अवधारणा: cSplitद्वारा पीछा किया tstrsplit, जिसके बाद dcast: cSplit(myDT, "info", ";", "long")[, c("t1", "t2") := tstrsplit(info, "=", fixed = TRUE)][, dcast(.SD, chr + pos ~ t1, value.var = "t2")]
a5C1D2H2I1M1N2O1R2T1

@ A5C1D2H2I1M1N2O1R2T1 बहुत बहुत धन्यवाद! दोनों महान हैं, दोहरे cSplitविकल्प के लिए एक विशेष के साथ :-)
कैथ

2

यहाँ है कि मैं यह कैसे करूँगा:

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 को रेप्रेक्स पैकेज (v0.3.0) द्वारा बनाया गया


मुझे बदलने की आवश्यकता नहीं है ";" में "," और शौकीन नहीं eval(parse(text=...))... लेकिन फिर भी आपके उत्तर के लिए धन्यवाद
कैथ

1
मैं व्यक्तिगत स्वाद के साथ बहस नहीं कर सकता, लेकिन parseएक बुरा प्रतिनिधि है क्योंकि यह अक्सर गलत कारण के लिए उपयोग किया जाता है, यहां ठीक इसका उपयुक्त उपयोग मामला है, स्ट्रिंग से कोड तक जा रहा है। आपने पाठ प्रारूपित किया है, लेकिन R के लिए प्रारूपित नहीं किया है, और आपने सूचियों का नाम दिया है, इसलिए मेरी पहली पंक्ति R सूची के लिए "a; b" को "सूची (a, b)" में बदलकर कोड बनाती है। फिर हम इसका मूल्यांकन करते हैं और इसमें से एक तालिका बनाते हैं।
मूडी_मडस्किपर 12

1

आप subप्रत्येक इच्छित निकाले गए फ़ील्ड के लिए अलग-अलग कॉल का उपयोग कर सकते हैं , उदाहरण के लिए type:

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

मुझे पता नहीं है कि सभी दायरें होंगी और वे बहुत कुछ हो सकते हैं इसलिए यह एक विकल्प नहीं है
कैथ

1
काफी उचित; मुझे यह पता नहीं था जब मैंने यह उत्तर पोस्ट किया था।
टिम बैजलेसेन

मैं इसे जोड़ूंगा (btw आप वांछित आउटपुट नहीं देते हैं, आपका उत्तर कुछ पंक्तियों को याद करता है ...)
कैथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.