2016-11-28 13 views
20

हम पंक्तियों और स्तंभों पर एक टेक्स्ट फ़ाइल को सब्सक्राइब करना चाहते हैं, जहां फ़ाइल से पंक्तियां और स्तंभ संख्याएं पढ़ी जाती हैं। हेडर को छोड़कर (पंक्ति 1) और राउनम्स (कॉल 1)।पंक्ति और कॉलम संख्याओं द्वारा फ़ाइल को सब्सक्राइब करें

inputFile.txt टैब सीमांकित पाठ फ़ाइल

header 62 9 3 54 6 1 
25 1 2 3 4 5 6 
96 1 1 1 1 0 1 
72 3 3 3 3 3 3 
18 0 1 0 1 1 0 
82 1 0 0 0 0 1 
77 1 0 1 0 1 1 
15 7 7 7 7 7 7 
82 0 0 1 1 1 0 
37 0 1 0 0 1 0 
18 0 1 0 0 1 0 
53 0 0 1 0 0 0 
57 1 1 1 1 1 1 

subsetCols.txt कॉमा कोई रिक्त स्थान, एक पंक्ति, संख्या का आदेश दिया साथ अलग कर दिया। वास्तविक डेटा में हमारे पास 500 के कॉलम हैं, और ~ 10K को सब्सक्राइब करने की आवश्यकता है।

1,4,6 

subsetRows.txt कॉमा कोई रिक्त स्थान, एक पंक्ति, संख्या का आदेश दिया साथ अलग कर दिया। वास्तविक डेटा में हमारे पास 20K पंक्तियां हैं, और लगभग 300 के लिए सब्सक्राइब करने की आवश्यकता है।

1,3,7 

वर्तमान समाधान कटौती और awk लूप (Related post: Select rows using awk) का उपयोग:

# define vars 
fileInput=inputFile.txt 
fileRows=subsetRows.txt 
fileCols=subsetCols.txt 
fileOutput=result.txt 

# cut columns and awk rows 
cut -f2- $fileInput | cut -f`cat $fileCols` | sed '1d' | awk -v s=`cat $fileRows` 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' > $fileOutput 

आउटपुट फ़ाइल: result.txt

1 4 6 
3 3 3 
7 7 7 

प्रश्न:
यह समाधान छोटी फ़ाइलों के लिए ठीक काम करता है, बड़ी फ़ाइलों 50K पंक्तियों और 200 के कॉलम के लिए, यह बहुत लंबा लग रहा है, 15 मिनट प्लस, अभी भी चल रहा है। मुझे लगता है कि कट कॉलम कॉलिंग ठीक काम करता है, पंक्तियों का चयन धीमा बिट है।

कोई बेहतर तरीका?

# $fileInput: 
#  Rows = 20127 
#  Cols = 533633 
#  Size = 31 GB 
# $fileCols: 12000 comma separated col numbers 
# $fileRows: 300 comma separated row numbers 

अधिक फ़ाइल के बारे में जानकारी: फ़ाइल GWAS जीनोटाइप डेटा शामिल

रियल इनपुट जानकारी फ़ाइलें। प्रत्येक पंक्ति नमूना (व्यक्तिगत) का प्रतिनिधित्व करती है और प्रत्येक कॉलम SNP का प्रतिनिधित्व करता है। आगे के क्षेत्र आधारित विश्लेषण के लिए हमें जैसे अन्य सांख्यिकीय सॉफ़्टवेयर के लिए इनपुट के रूप में डेटा को अधिक प्रबंधनीय (छोटा) बनाने के लिए नमूनों (पंक्तियों) और एसएनपी (कॉलम) को सब्सक्राइब करने की आवश्यकता है।

सिस्टम:

$ uname -a 
Linux nYYY-XXXX ZZZ Tue Dec 18 17:22:54 CST 2012 x86_64 x86_64 x86_64 GNU/Linux 

अद्यतन: समाधान @JamesBrown से नीचे प्रदान की अपने सिस्टम में स्तंभों की आदेश मिश्रण किया गया था, के रूप में मैं awk के विभिन्न संस्करण का उपयोग कर रहा है, मेरे संस्करण है: GNU Awk 3.1.7

+1

जैसा कि मैंने आपकी समस्या को काफी रोचक पाया है, मैं अभी भी आपके संपादन पढ़ने के आसपास हूं। मैं प्रसंस्करण को तेज करने के लिए दोनों बहुत अच्छे उत्तरों पर कुछ सुधारों के साथ आया था और यह गैर-gnu awk के साथ भी काम करता है। – anubhava

उत्तर

20

If programming languages were countries, which country would each language represent? में वे कहते हैं कि भले ही ...

012,351,

Awk: उत्तर कोरिया। जिद्दी रूप से विरोध का विरोध करता है, और इसके उपयोगकर्ता इसके कारण अनजाने में शौकीन हैं क्योंकि हम केवल अनुमान लगा सकते हैं।

... जब भी आप देख अपने आप को एसईडी पाइप, कट, ग्रेप, awk, आदि, बंद करो और अपने आप से कहते हैं: awk इसे अकेले कर सकते हैं!

इसलिए इस मामले में यह पंक्तियों और स्तंभों को निकालने का विषय है (हेडर और पहले कॉलम को बाहर करने के लिए उन्हें ट्वीक करना) और फिर आउटपुट को अंततः प्रिंट करने के लिए बफर करना।

awk -v cols="1 4 6" -v rows="1 3 7" ' 
    BEGIN{ 
     split(cols,c); for (i in c) col[c[i]] # extract cols to print 
     split(rows,r); for (i in r) row[r[i]] # extract rows to print 
    } 
    (NR-1 in row){ 
     for (i=2;i<=NF;i++) 
       (i-1) in col && line=(line ? line OFS $i : $i); # pick columns 
       print line; line=""        # print them 
    }' file 
अपने नमूना फ़ाइल के साथ

:

$ awk -v cols="1 4 6" -v rows="1 3 7" 'BEGIN{split(cols,c); for (i in c) col[c[i]]; split(rows,r); for (i in r) row[r[i]]} (NR-1 in row){for (i=2;i<=NF;i++) (i-1) in col && line=(line ? line OFS $i : $i); print line; line=""}' file 
1 4 6 
3 3 3 
7 7 7 
अपने नमूना फ़ाइल के साथ

, और इनपुट के रूप में चर, अल्पविराम पर विभाजित:

awk -v cols="$(<$fileCols)" -v rows="$(<$fileRows)" 'BEGIN{split(cols,c, /,/); for (i in c) col[c[i]]; split(rows,r, /,/); for (i in r) row[r[i]]} (NR-1 in row){for (i=2;i<=NF;i++) (i-1) in col && line=(line ? line OFS $i : $i); print line; line=""}' $fileInput 

मैं काफी यकीन है कि इस तरह से तेजी से होगी। उदाहरण के लिए आप awk के प्रदर्शन की तुलना grep और अन्य के प्रदर्शन की तुलना में कुछ बेंचमार्क के लिए Remove duplicates from text file based on second text file देख सकते हैं।

बेस्ट,
किम जोंग-उन

6

एक ग्नू awk संस्करण 4.0 या बाद में के रूप में स्तंभ आदेश for और PROCINFO["sorted_in"] पर निर्भर करता है। पंक्ति और स्तंभ संख्या फ़ाइलों से पढ़ने जाते हैं:

$ awk ' 
BEGIN { 
    PROCINFO["sorted_in"]="@ind_num_asc"; 
} 
FILENAME==ARGV[1] {      # process rows file 
    n=split($0,t,","); 
    for(i=1;i<=n;i++) r[t[i]] 
} 
FILENAME==ARGV[2] {      # process cols file 
    m=split($0,t,","); 
    for(i=1;i<=m;i++) c[t[i]] 
} 
FILENAME==ARGV[3] && ((FNR-1) in r) {  # process data file 
    for(i in c) 
     printf "%s%s", $(i+1), (++j%m?OFS:ORS) 
}' subsetRows.txt subsetCols.txt inputFile.txt 
1 4 6 
3 3 3 
7 7 7 

कुछ प्रदर्शन लाभ शायद शीर्ष berore 1 और 2 के लिए ARGV[3] प्रसंस्करण ब्लॉक चलती है और यह अंत है करने के लिए एक next जोड़ने से आ सकता है।

+0

वास्तव में नहीं। यदि आप इसका परीक्षण करने जा रहे हैं, तो प्रदर्शन सुनने में रुचि रखने की तरह। इसके अलावा, मैंने कुछ बैठकों में कुछ टुकड़ों में लिखा था, इसलिए मुझे यह सुनकर खुशी हो रही है कि यह काम करता है ... क्यूसी और सामान। : डी –

+1

हालांकि, ध्यान दें कि का उपयोग करते हुए '(मैं ग में)' सही क्रम प्रदान नहीं कर सकते के लिए: [क्यों awk सरणी randomize करने के लिए प्रतीत होता है?] (Http://stackoverflow.com/a/22504503/1983854) – fedorqui

+0

आप सही थे, पंक्तियों और कोलों को मिश्रित किया गया था, इसके बारे में खेद है। इसके अलावा, 'ओएफएस' अब जगह है। –

2

दोनों उत्कृष्ट जवाब से दूर कुछ भी लेने के लिए नहीं। सिर्फ इसलिए कि इस समस्या में डेटा का बड़ा सेट शामिल है, मैं प्रसंस्करण को तेज करने के लिए 2 उत्तरों का संयोजन पोस्ट कर रहा हूं।

awk -v cols="$(<subsetCols.txt)" -v rows="$(<subsetRows.txt)" ' 
BEGIN { 
    n = split(cols, c, /,/) 
    split(rows, r, /,/) 
    for (i in r) 
     row[r[i]] 
} 
(NR-1) in row { 
    for (i=1; i<=n; i++) 
     printf "%s%s", $(c[i]+1), (i<n?OFS:ORS) 
}' inputFile.txt 

पुनश्च: यह रूप में अच्छी तरह से पुराने awk संस्करण या गैर gnu awk साथ काम करना चाहिए।

+2

ओह, कूल, आप कॉलम की मात्रा को जानने के लिए स्प्लिट की वापसी संख्या का उपयोग करते हैं और इसलिए उचित स्तंभ संख्या निकालने के दौरान इसका उपयोग करते हैं। यह बहुत स्मार्ट है, अच्छी तरह से किया। – fedorqui

0

@anubhava समाधान हम प्रत्येक पंक्ति के लिए 10k से अधिक मूल्यों खोज तथ्य का लाभ takeing से अगर हम सही पंक्ति पर देखने के लिए से छुटकारा मिल सकता है परिष्कृत करने के लिए इनपुट पहले से ही

awk -v cols="$(<subsetCols.txt)" -v rows="$(<subsetRows.txt)" ' 
BEGIN { 
    n = split(cols, c, /,/) 
    split(rows, r, /,/) 
    j=1; 
} 
(NR-1) == r[j] { 
    j++ 
    for (i=1; i<=n; i++) 
     printf "%s%s", $(c[i]+1), (i<n?OFS:ORS) 
}' inputFile.txt 
+2

मुझे यह जानने के लिए बहुत कुछ पता नहीं है कि क्या यह पोस्ट एक अलग उत्तर होने का हकदार है, मेरे लिए ऐसा लगता है कि परिवर्तन बहुत मामूली हैं और @anubhava की पोस्ट पर टिप्पणी हो सकती थी? – zx8754

+0

शायद आपको इसे पैमाने पर समय देना चाहिए – tomc

-1

क्रमबद्ध हो जाता है पायथन में एक सीएसवी मॉड्यूल है। आप एक सूची में एक पंक्ति पढ़ते हैं, वांछित कॉलम को stdout, कुल्ला, धोने, दोहराने के लिए मुद्रित करें।

यह कॉलम 30,000 से 20,000 काट चाहिए।

import csv 
with open('foo.txt') as f: 
    gwas = csv.reader(f, delimiter=',', quoting=csv.QUOTE_NONE) 
    for row in gwas: 
     print(row[20001:30001] 
संबंधित मुद्दे