我一直在閱讀其他類似的問題。我有這個作業,但由于我正在使用的 CSV 的大小,它非常慢。有沒有辦法提高效率?
我的目標:我有一個非常大的 CSV(>100 GB)。我想獲取列中的所有唯一值,提取其中的 10%,然后使用這 10% 對原始 CSV 進行二次抽樣。
我在做什么:
1 - 我從第 11 列中提取所有唯一值并將其寫入文本檔案:
cat File1.csv | cut -f11 -d , | sort | uniq > uniqueValues.txt
2 - 接下來,我隨機抽取 10% 的值uniqueValues.txt:
cat uniqueValues.txt | awk 'BEGIN {srand()} !/^$/ { if (rand() <= .10) print $0'} > uniqueValues.10pct.txt
3 - 接下來,我從以下位置提取File1.csv具有第 11 列匹配值的行uniqueValues.10pct.txt:
awk -F, 'NR==FNR{a[$1]=$0;next}($11 in a){print}' uniqueValues.10pct.txt File1.csv > File1_subsample.csv
據我所知,這似乎有效。這看起來合理嗎?關于如何提高效率的任何建議?
uj5u.com熱心網友回復:
關于如何提高效率的任何建議?
避免sort在第一步中,因為第二步和第三步不關心順序,您可以使用單個 awk 命令執行整個第一步,如下所示:
awk 'BEGIN{FS=","}!arr[$11] {print $11}' File1.csv > uniqueValues.txt
說明:我通知 GNUAWK欄位分隔符 ( FS) 是逗號,然后對于我所做的每一行arr[$11] 來獲取第 11 列中值的出現次數并使用!它來否定它,因此0變為真,而1更大則變為假。如果這成立,我print第 11 欄。
請針對您的資料的第一步進行上述測驗,然后選擇一個更快的。
至于第三步,AWK如果您被允許在您的機器上安裝工具,您可能會嘗試使用非 GNU。例如文章的作者1 Don't MAWK AWK – 最快、最優雅的大資料處理語言!發現nawk比 GNU快AWK,mawk比nawk. 安裝后準備測驗資料和測量時間
gawk -F, 'NR==FNR{a[$1]=$0;next}($11 in a){print}' uniqueValues.10pct.txt File1.csv > File1_subsample.csv
nawk -F, 'NR==FNR{a[$1]=$0;next}($11 in a){print}' uniqueValues.10pct.txt File1.csv > File1_subsample.csv
mawk -F, 'NR==FNR{a[$1]=$0;next}($11 in a){print}' uniqueValues.10pct.txt File1.csv > File1_subsample.csv
然后使用一個最快證明的。
1請注意,顯示的值與 2009 年 9 月可用的版本有關,您可能會得到與 2022 年 6 月可用版本不同的時間。
uj5u.com熱心網友回復:
您可能會發現這更快(未經測驗,因為沒有提供示例輸入/輸出):
cut -f11 -d',' File1.csv |
sort -u > uniqueValues.txt
numUnq=$(wc -l < uniqueValues.txt)
shuf -n "$(( numUnq / 10 ))" uniqueValues.txt |
awk -F',' 'NR==FNR{a[$1]; next} $11 in vals' - File1.csv
您可以嘗試先將其替換cut | sort; numUnq=$(wc...)為
numUnq=$(awk -F',' '!seen[$11] {print $11 > "uniqueValues.txt"; cnt } END{print cnt 0}' File1.csv)
看看這是否更快,但我懷疑它,因為cut,sort和wc都非常快,同時awk必須進行基于正則運算式的欄位拆分并將所有$11值存盤在記憶體中(由于動態陣列分配的作業方式,隨著陣列大小的增加,這可能會變慢)。
uj5u.com熱心網友回復:
你似乎有很多記憶體,所以你可以試試這個:
awk -F, '
BEGIN { srand() }
!($11 in seen) {
seen[$11]
if (rand() <= .1)
selected[$11]
}
$11 in selected
' File1.csv
備注:我試圖將操作次數保持在最低限度
uj5u.com熱心網友回復:
創建示例 *.csv 檔案:
for ((i=1;i<=100;i ))
do
for ((j=1;j<=100;j ))
do
echo "a,b,c,d,e,f,g,h,i,j,${j},k,l,m"
done
done > large.csv
筆記:
- 1,000 條線
- 第 11 個欄位中的 100 個唯一值
- 每個唯一值在檔案中顯示 10 次
我們將看看幾個awk想法:
- 跟蹤我們發現的獨特價值
- 當我們遇到一個新的(唯一的)值時應用隨機百分比檢查
- 只需要一次通過源檔案
- 注意:這兩個
awk腳本(如下)替換了所有 OP 的當前代碼(cat/cut/sort/uniq/cat/awk/awk)
第一個想法是在每次找到新的唯一值時應用我們的隨機百分比檢查:
awk -F',' '
BEGIN { srand() }
!seen[$11] { if (rand() <= 0.10) # if this is the 1st time we have seen this value and rand() is <= 10% then ...
keep[$11] # add the value to our keep[] array
}
$11 in keep # print current line if $11 is an index in the keep[] array
' large.csv > small.csv
筆記:
- 這種方法的一個缺點是唯一值的總數不能保證總是正好是 10%,因為我們受
rand()函式的支配,例如...... - 半打樣本運行在
small.csv
一種不同的方法,我們預先生成一組隨機modulo 100值(即0to 99);當我們找到一個新的 uniq 值時,我們檢查(uniq 值的)計數modulo 100,如果我們找到與我們預先生成的集合匹配,那么我們列印該行:
awk -F',' -v pct=10 '
BEGIN { srand()
delete mods # force awk to treat all "mods" references as an array and not a scalar
while (length(mods) < pct) # repeat loop until we have "pct" unique indices in the mods[] array
mods[int(rand() * 100)] # generate random integers betwen 0 and 99
}
!seen[$11] { if (( uniqcnt % 100) in mods) # if this is the 1st time we have seen this value then increment our unique value counter and if "modulo 100" is an index in the mods[] array then ...
keep[$11] # add the value to our keep[] array
}
$11 in keep # print current line if $11 is an index in the keep[] array
' large.csv > small.csv
筆記:
- 對于一個大的,
pct這假設rand()結果均勻分布在 0 和 1 之間,以便mods[]及時填充陣列 - 這樣做的好處是列印的行正好代表可能唯一值的 10%(取決于唯一值的數量,百分比實際上是 10% /- 1%)
- 六個樣本運行都在
small.csv
如果 OP 仍然需要生成兩個中間(排序)檔案(uniqueValues.txt和uniqueValues.10pct.txt),那么這可以awk通過一個塊在同一個腳本中完成END {...},例如:
END { PROCINFO["sorted_in"]="@ind_num_asc" # this line of code requires GNU awk otherwise OP can sort the files at the OS/bash level
for (i in seen)
print i > "uniqueValues.txt"
for (i in keep)
print i > "uniqueValues.10pct.txt" # use with 1st awk script
# print i > "uniqueValues." pct "pct.txt" # use with 2nd awk script
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/486687.html
