2017-09-05 54 views
0

我有一個CSV文件,其中包含4列的哈希值,雖然只有兩個相關的。紅寶石 - 打開一個CSV到包含一個比率值

列A包含一大羣有時重複串的例如(Apple,Banana,Apple,Apple,Cherry),B列包含兩個字符串中的一個(「W」或「L」)。

我試圖把這個數據到一個哈希與A列中每個唯一的字符串鍵,取值爲每那個密鑰是「W」總行的%。

例如如果CSV有以下幾條:

ColA ColB 
"Apple" "W" 
"Apple" "W" 
"Apple" "L" 
"Banana" "W" 

哈希將是:

{"Apple" => 66%, "Banana" => 100%}. 

我已經成功地創建一個散列那組我行一起通過執行以下操作:

fullset = CSV.read('file.csv') 
groupedhash = fullset.group_by {|x| x[1]} 

,我已經成功地找到各個計數第二列像這樣:

groupedhash.map{|k,v| [k, v.select.count {|x| x[2] == "W"}]} 
groupedhash.map{|k,v| [k, v.select.count {|x| x[2] == "L"}]} 

但我一直無法弄清楚如何把它放在一起,並得到實際的「W」比率。

感謝您的幫助!

回答

0
fullset = CSV.read('file.csv') 
groupedhash = fullset.group_by { |x| x[0] } 
result = groupedhash.each_with_object({}) do |(key, values), hash| 
    w_count = values.select { |x| x[1] == "W" }.length 
    hash[key] = (w_count/values.length.to_f).round(2) 
end 
+0

這工作 - 謝謝你! – Sartake

+1

要確定'w_count',你不需要選擇包含'「W」'的元組,然後確定結果數組的大小。只需使用'values.count {| x | x [1] ==「W」}'。 –

2

我知道你已經將數據讀入一個數組,

arr = [["Apple", "W"], ["Apple", "W"], ["Apple", "L"], ["Banana", "W"]] 

,然後分組通過水果的元素,

h = arr.group_by(&:first) 
    # => {"Apple"=>[["Apple", "W"], ["Apple", "W"], ["Apple", "L"]], 
    #  "Banana"=>[["Banana", "W"]]} 

您可以通過簡單地重新計算獲得期望的結果這個散列的值。

h.keys.each { |k| h[k] = 100.0 * h[k].count { |_,t| t =="W" }/h[k].size } 
    #=> ["Apple", "Banana"] 
h #=> {"Apple"=>66.66666666666667, "Banana"=>100.0} 

另一種方法是使用一個計數散列。請參閱文檔Hash::new,特別是有關使用默認值的文檔,這裏是數組[0, 0]

arr.each_with_object(Hash.new([0,0])) { |(fruit, type), h| 
     h[fruit] = [h[fruit].first + (type == "W" ? 1 : 0), h[fruit].last + 1] }. 
    tap { |g| g.keys.each { |k| g[k] = (100.0 * g[k].first/g[k].last).round(2) } } 
    #=> {"Apple"=>66.67, "Banana"=>100.0} 

中間結果如下。

arr.each_with_object(Hash.new([0,0])) { |(fruit, type), h| 
     h[fruit] = [h[fruit].first + (type == "W" ? 1 : 0), h[fruit].last + 1] } 
    #=> {"Apple"=>[2, 3], "Banana"=>[1, 1]} 

如果Hash.new([0,0]仍然錯綜複雜,我們可以寫出如下上述行。

arr.each_with_object({}) do |(fruit, type), h| 
    h[fruit] = [0, 0] unless h.key?(fruit) 
    h[fruit] = [h[fruit].first + (type == "W" ? 1 : 0), h[fruit].last + 1] 
end 

注意,我使用Object#tap使用group_by時,然後通過加入線h在端返回該變量的值,以避免需要創建變量h。此外,我將結果四捨五入到小數點後兩位。這兩種技術當然可以與採用group_by的方法一起使用。

+0

謝謝Cary,詳細解釋這一點非常有幫助。 – Sartake

3

這裏還有一個計數散列的變體:

arr = [["Apple", "W"], ["Apple", "W"], ["Apple", "L"], ["Banana", "W"]] 

h = Hash.new { |hash, key| hash[key] = { 'W' => 0, 'L' => 0 } } 

arr.each { |a, b| h[a][b] += 1 } 

h #=> {"Apple"=>{"W"=>2, "L"=>1}, "Banana"=>{"W"=>1, "L"=>0}} 

現在,我們可以得到由(精確)比:

h.transform_values { |v| v['W'].quo(v['L'] + v['W']) } 
#=> {"Apple"=>(2/3), "Banana"=>(1/1)} 

或通過(四捨五入)百分比:

h.transform_values { |v| v['W'].fdiv(v['L'] + v['W']) * 100 } 
#=> {"Apple"=>66.66666666666666, "Banana"=>100.0} 

或可能是一個字符串表示形式:

h.transform_values { |v| sprintf('%d%%', v['W'].quo(v['L'] + v['W']) * 100) } 
#=> {"Apple"=>"66%", "Banana"=>"100%"} 
+0

謝謝 - 我認爲transform_values方法是我試圖找到但不能做到的。 – Sartake

+0

優秀的答案! Sartake注意到,在Ruby v2.4中,[Hash#transform_values](http://ruby-doc.org/core-2.4.0/Hash.html#method-i-transform_values)最近剛剛首次亮相。 –