हिस्टोग्राम प्लॉट के लिए डेटा प्राप्त करना


82

क्या MySQL में बिन साइज़ निर्दिष्ट करने का कोई तरीका है? अभी, मैं निम्नलिखित SQL क्वेरी की कोशिश कर रहा हूँ:

select total, count(total) from faults GROUP BY total;

जो डेटा जनरेट किया जा रहा है, वह काफी अच्छा है, लेकिन अभी बहुत सारी पंक्तियाँ हैं। मुझे जो चाहिए वह डेटा को पूर्वनिर्धारित डिब्बे में समूहित करने का एक तरीका है। मैं यह एक स्क्रिप्टिंग भाषा से कर सकता हूं, लेकिन क्या इसे सीधे SQL में करने का कोई तरीका है?

उदाहरण:

+-------+--------------+
| total | count(total) |
+-------+--------------+
|    30 |            1 | 
|    31 |            2 | 
|    33 |            1 | 
|    34 |            3 | 
|    35 |            2 | 
|    36 |            6 | 
|    37 |            3 | 
|    38 |            2 | 
|    41 |            1 | 
|    42 |            5 | 
|    43 |            1 | 
|    44 |            7 | 
|    45 |            4 | 
|    46 |            3 | 
|    47 |            2 | 
|    49 |            3 | 
|    50 |            2 | 
|    51 |            3 | 
|    52 |            4 | 
|    53 |            2 | 
|    54 |            1 | 
|    55 |            3 | 
|    56 |            4 | 
|    57 |            4 | 
|    58 |            2 | 
|    59 |            2 | 
|    60 |            4 | 
|    61 |            1 | 
|    63 |            2 | 
|    64 |            5 | 
|    65 |            2 | 
|    66 |            3 | 
|    67 |            5 | 
|    68 |            5 | 
------------------------

मैं क्या देख रहा हूँ:

+------------+---------------+
| total      | count(total)  |
+------------+---------------+
|    30 - 40 |            23 | 
|    40 - 50 |            15 | 
|    50 - 60 |            51 | 
|    60 - 70 |            45 | 
------------------------------

मुझे लगता है कि यह सीधे आगे के तरीके से हासिल नहीं किया जा सकता है, लेकिन किसी भी संबंधित संग्रहीत प्रक्रिया के लिए एक संदर्भ भी ठीक होगा।


मुझे बिल्कुल यकीन नहीं है कि आप क्या पूछ रहे हैं। उदाहरण आउटपुट मदद कर सकता है।
बेरेक ब्रायन

माफ़ करना! बस एक उदाहरण के साथ मेरी पोस्ट को अपडेट किया।
लीजेंड

जवाबों:


162

यह संख्यात्मक मानों के लिए MySQL में हिस्टोग्राम बनाने के लिए एक सुपर क्विक-एंड-डर्टी तरीका के बारे में एक पोस्ट है।

हिस्टोग्राम बनाने के लिए कई अन्य तरीके हैं जो बेहतर और अधिक लचीले हैं, जो कि CASE स्टेटमेंट और अन्य प्रकार के जटिल तर्क का उपयोग करते हैं। यह विधि मुझे समय और समय के साथ फिर से जीतती है क्योंकि यह प्रत्येक उपयोग के मामले के लिए संशोधित करना इतना आसान है, और इतना छोटा और संक्षिप्त है। इसे आपको इसी तरह करना होगा:

SELECT ROUND(numeric_value, -2)    AS bucket,
       COUNT(*)                    AS COUNT,
       RPAD('', LN(COUNT(*)), '*') AS bar
FROM   my_table
GROUP  BY bucket;

बस जो कुछ भी आपका कॉलम है, उसे num_value बदलें, गोलाई वृद्धि को बदलें, और यही वह है। मैंने बारों को लघुगणकीय पैमाने पर बनाने के लिए बनाया है, ताकि बड़े मूल्य होने पर वे बहुत अधिक न बढ़ें।

संख्यात्मक_वायु को राउडिंग ऑपरेशन में ऑफसेट किया जाना चाहिए, गोलाई की वृद्धि के आधार पर, यह सुनिश्चित करने के लिए कि पहली बाल्टी में निम्नलिखित बाल्टी के रूप में कई तत्व शामिल हैं।

जैसे ROUND (संख्यात्मक_वायु, -1), संख्यात्मक_वायु के साथ श्रेणी में [0,4] (5 तत्व) को पहले बाल्टी में रखा जाएगा, जबकि [5,14] (दूसरे में 10 तत्व), [15,24] तीसरे में, जब तक सांख्यिक_वायु को ROUND के माध्यम से उचित रूप से ऑफसेट नहीं किया जाता है (संख्यात्मक_वायु - 5, -1)।

यह कुछ यादृच्छिक डेटा पर ऐसी क्वेरी का एक उदाहरण है जो बहुत प्यारी लगती है। डेटा के त्वरित मूल्यांकन के लिए पर्याप्त है।

+--------+----------+-----------------+
| bucket | count    | bar             |
+--------+----------+-----------------+
|   -500 |        1 |                 |
|   -400 |        2 | *               |
|   -300 |        2 | *               |
|   -200 |        9 | **              |
|   -100 |       52 | ****            |
|      0 |  5310766 | *************** |
|    100 |    20779 | **********      |
|    200 |     1865 | ********        |
|    300 |      527 | ******          |
|    400 |      170 | *****           |
|    500 |       79 | ****            |
|    600 |       63 | ****            |
|    700 |       35 | ****            |
|    800 |       14 | ***             |
|    900 |       15 | ***             |
|   1000 |        6 | **              |
|   1100 |        7 | **              |
|   1200 |        8 | **              |
|   1300 |        5 | **              |
|   1400 |        2 | *               |
|   1500 |        4 | *               |
+--------+----------+-----------------+

कुछ नोट: जिन रंगों का कोई मिलान नहीं है, वे गिनती में दिखाई नहीं देंगे - आपके पास गिनती कॉलम में शून्य नहीं होगा। इसके अलावा, मैं यहाँ ROUND फ़ंक्शन का उपयोग कर रहा हूं। आप बस इसे आसानी से TRUNCATE से बदल सकते हैं यदि आपको लगता है कि यह आपके लिए अधिक समझ में आता है।

मैंने इसे यहाँ पाया http://blog.shlomoid.com/2011/08/how-to-quickly-create-histogram-in.html


1
MySQL 8.0.3 के अनुसार, अब आपके पास आशावादी को अधिक आँकड़े प्रदान करने के लिए हिस्टोग्राम आँकड़े बनाने की क्षमता है - mysqlserverteam.com/histogram-statistics-in-mysql
Jaro

आपको क्वेरी के "बार" भाग की भी आवश्यकता नहीं है; संख्याएँ पहले से ही एक लघुगणकीय बार चार्ट / हिस्टोग्राम बनाती हैं।
enharmonic

31

माइक डेलगायो का जवाब है कि मैं इसे करता हूं, लेकिन थोड़े बदलाव के साथ:

select floor(mycol/10)*10 as bin_floor, count(*)
from mytable
group by 1
order by 1

लाभ? आप जितने चाहे उतने बड़े या जितने चाहे उतने छोटे डिब्बे बना सकते हैं। आकार 100 के डिब्बे? floor(mycol/100)*100। आकार 5 के डिब्बे? floor(mycol/5)*5

बर्नार्डो।


जैसा कि कार्सिलिनेटर ने कहा कि आपके समूह द्वारा & ऑर्डर बेहतर तरीके से बिन_फ्लोर या 1 होना चाहिए - यदि आप इसे ठीक करते हैं, तो इसे ठीक करें, यह मेरे लिए सबसे अच्छा जवाब है
बीएम

मेला काफी, @ बी.एम. के रूप में बदल दिया है, जो कि कार्लोनाइटर द्वारा सुझाई गई है।
बर्नार्डो सियु

और यदि आप एक अच्छा कॉलम नाम चाहते हैं तो आप कर सकते हैंconcat(floor(mycol/5)*5," to ",floor(mycol/5)*5+5)
alex9311

यह वास्तव round(mycol, -2)में स्वीकृत उत्तर से सरल से बेहतर है क्योंकि यह उपयोगकर्ता को किसी भी गैर-दशमलव "रेंज" को परिभाषित करने देता है। मैं roundइसके बजाय सिर्फ इसका उपयोग करता हूं floorक्योंकि यह ठीक से संख्याओं को गोल करता है।
मेरिडियस

16
SELECT b.*,count(*) as total FROM bins b 
left outer join table1 a on a.value between b.min_value and b.max_value 
group by b.min_value

टेबल के डिब्बे में कॉलम min_value और max_value होते हैं जो डिब्बे को परिभाषित करते हैं। ध्यान दें कि ऑपरेटर "x BETWEEN y और z पर" सम्मिलित है।

तालिका 1 डेटा तालिका का नाम है


2
SQL के लिए सिंटैक्स रंग इतना खराब क्यों है? मैं इसे कैसे सुधार सकता हूं? हो सकता है कि मैं इसे मेटा पर पोस्ट
करूँ

2
इस मामले में न्यूनतम अधिकतम परिभाषित करने के लिए एक टेम्पलेट तालिका आवश्यक है। केवल SQL के साथ संभव नहीं है।
सेसर

SQL गुरु! बिल्कुल वही जो मैं चाहता था। मुझे लगता है कि डिब्बे की मेज बनाते समय देखभाल की जानी चाहिए। अन्यथा सब कुछ पूरी तरह से काम करता है। :) धन्यवाद। मैंने अभी एक अजगर की पटकथा लिखनी पूरी की लेकिन यह सिर्फ मेरी जरूरत है ...
लीजेंड

@Legend: वास्तव में, मैं काफी n00b हूँ जब यह SQL की बात आती है। लेकिन यह एक अच्छा और उपयोगी सवाल था, इसलिए मुझे यह अभ्यास पसंद आया ...
18:00

1
@David West का उत्तर (जो एक टिप्पणी, यहां होना चाहिए था) को देखना महत्वपूर्ण है कि जब शून्य का उत्पादन करना चाहिए तो COUNT (*) 1 का उत्पादन कैसे करता है। हो सकता है कि यह आपके लिए एक बड़ी समस्या न हो, लेकिन यह सांख्यिकीय डेटा को तिरछा कर सकता है और यदि आप किसी को नोटिस करते हैं तो आप थोड़ा मूर्ख दिखेंगे :)
क्रिस्टोफर शुल्त्स

11

Ofri Raviv का जवाब बहुत ही करीब है लेकिन गलत है। count(*)हो जाएगा 1, भले ही देखते हैं शून्य परिणाम एक हिस्टोग्राम अंतराल में। सशर्त का उपयोग करने के लिए क्वेरी को संशोधित करने की आवश्यकता है sum:

SELECT b.*, SUM(a.value IS NOT NULL) AS total FROM bins b
  LEFT JOIN a ON a.value BETWEEN b.min_value AND b.max_value
GROUP BY b.min_value;

10
select "30-34" as TotalRange,count(total) as Count from table_name
   where total between 30 and 34
union (
select "35-39" as TotalRange,count(total) as Count from table_name 
   where total between 35 and 39)
union (
select "40-44" as TotalRange,count(total) as Count from table_name
   where total between 40 and 44)
union (
select "45-49" as TotalRange,count(total) as Count from table_name
   where total between 45 and 49)
etc ....

जब तक बहुत अधिक अंतराल नहीं होते हैं, यह एक बहुत अच्छा समाधान है।


1
+1 यह एकमात्र समाधान है जो डिब्बे को अलग-अलग आकार का होने की अनुमति देता है
गेबे मुथर्ट

महान - अतिरिक्त तालिकाओं की कोई आवश्यकता नहीं
NiRR

+1 यह सबसे लचीला समाधान imo है, और SQL के भीतर से बिन को चाहने के उपयोग के मामले में सबसे उपयुक्त लगता है। किसी भी मामले में जहां बिन श्रेणियों को प्रोग्रामेटिक रूप से प्राप्त करने की आवश्यकता होती है, इसकी संभावना SQL के बाहर ऐसा करने के लिए बेहतर है। फिर से imo
रयान मैककॉय 2

4

मैंने एक प्रक्रिया बनाई, जिसका उपयोग स्वचालित रूप से एक निर्दिष्ट संख्या या आकार के अनुसार डिब्बे के लिए एक अस्थायी तालिका उत्पन्न करने के लिए किया जा सकता है, बाद में एग्री रविव के समाधान के साथ उपयोग के लिए।

CREATE PROCEDURE makebins(numbins INT, binsize FLOAT) # binsize may be NULL for auto-size
BEGIN
 SELECT FLOOR(MIN(colval)) INTO @binmin FROM yourtable;
 SELECT CEIL(MAX(colval)) INTO @binmax FROM yourtable;
 IF binsize IS NULL 
  THEN SET binsize = CEIL((@binmax-@binmin)/numbins); # CEIL here may prevent the potential creation a very small extra bin due to rounding errors, but no good where floats are needed.
 END IF;
 SET @currlim = @binmin;
 WHILE @currlim + binsize < @binmax DO
  INSERT INTO bins VALUES (@currlim, @currlim+binsize);
  SET @currlim = @currlim + binsize;
 END WHILE;
 INSERT INTO bins VALUES (@currlim, @maxbin);
END;

DROP TABLE IF EXISTS bins; # be careful if you have a bins table of your own.
CREATE TEMPORARY TABLE bins (
minval INT, maxval INT, # or FLOAT, if needed
KEY (minval), KEY (maxval) );# keys could perhaps help if using a lot of bins; normally negligible

CALL makebins(20, NULL);  # Using 20 bins of automatic size here. 

SELECT bins.*, count(*) AS total FROM bins
LEFT JOIN yourtable ON yourtable.value BETWEEN bins.minval AND bins.maxval
GROUP BY bins.minval

यह हिस्टोग्राम गिनती केवल उन डिब्बे के लिए उत्पन्न करेगा जो आबादी वाले हैं। डेविड वेस्ट को अपने सुधार में सही होना चाहिए, लेकिन किसी कारण के लिए, अनपॉप किए गए डिब्बे मेरे लिए परिणाम में नहीं दिखाई देते हैं (एक LEFT JOIN के उपयोग के बावजूद - मुझे समझ नहीं आता कि क्यों)।


3

वह काम करना चाहिए। इतना सुंदर नहीं है लेकिन फिर भी:

select count(mycol - (mycol mod 10)) as freq, mycol - (mycol mod 10) as label
from mytable
group by mycol - (mycol mod 10)
order by mycol - (mycol mod 10) ASC

माइक डेलगाडियो के माध्यम से


3
SELECT
    CASE
        WHEN total <= 30 THEN "0-30"
        WHEN total <= 40 THEN "31-40"       
        WHEN total <= 50 THEN "41-50"
        ELSE "50-"
    END as Total,
    count(*) as count
GROUP BY Total 
ORDER BY Total;

2

डिब्बे की दी गई गिनती में बराबर चौड़ाई वाली बाइनिंग:

WITH bins AS(
   SELECT min(col) AS min_value
        , ((max(col)-min(col)) / 10.0) + 0.0000001 AS bin_width
   FROM cars
)
SELECT tab.*,
   floor((col-bins.min_value) / bins.bin_width ) AS bin
FROM tab, bins;

ध्यान दें कि 0.0000001 यह सुनिश्चित करने के लिए है कि अधिकतम (कॉल) के बराबर मूल्य वाले रिकॉर्ड केवल अपने आप से ही बिन नहीं बनाते हैं। इसके अलावा, यह सुनिश्चित करने के लिए योजक स्थिर है कि यह सुनिश्चित करने के लिए कि क्वेरी शून्य से विभाजन पर विफल न हो जब कॉलम के सभी मान समान हों।

यह भी ध्यान दें कि पूर्णांक विभाजन से बचने के लिए डिब्बे की गिनती (उदाहरण में 10) एक दशमलव चिह्न के साथ लिखी जानी चाहिए (अनैच्छिक बिन_विविधता दशमलव हो सकती है)।


WITH something ASआप मूल्य है कि डिब्बे में चला जाता है की गणना करने के लिए है, तो बहुत उपयोगी है।
रौनर बर्ग

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