[mysql] 히스토그램 플롯에 대한 데이터 얻기

MySQL에서 bin 크기를 지정하는 방법이 있습니까? 지금 다음 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 |
------------------------------

나는 이것이 직접적인 방식으로 달성 될 수 없다고 생각하지만 관련 저장 프로 시저에 대한 참조도 괜찮을 것입니다.



답변

이것은 MySQL에서 숫자 값에 대한 히스토그램을 만드는 매우 빠르고 더러운 방법에 대한 게시물입니다.

CASE 문과 다른 유형의 복잡한 논리를 사용하여 더 우수하고 유연한 히스토그램을 만드는 다른 여러 방법이 있습니다. 이 방법은 각 사용 사례에 대해 수정하기가 쉽고 짧고 간결하기 때문에 시간이 지남에 따라 저를 매료시킵니다. 방법은 다음과 같습니다.

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

numeric_value를 열이 무엇이든 변경하고 반올림 증분을 변경하면됩니다. 막대를 로그 스케일로 만들었으므로 큰 값을 가질 때 너무 커지지 않습니다.

첫 번째 버킷에 다음 버킷만큼 많은 요소가 포함되도록하려면 numeric_value가 반올림 증분을 기준으로 ROUNDing 작업에서 오프셋되어야합니다.

예를 들어 ROUND (numeric_value, -1)을 사용하면 [0,4] (5 개 요소) 범위의 numeric_value가 첫 번째 버킷에 배치되고 [5,14] (10 개 요소)는 두 번째에, [15,24]는 세 번째에 배치됩니다. numeric_value가 ROUND (numeric_value-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 | *               |
+--------+----------+-----------------+

참고 : 일치하지 않는 범위는 개수에 표시되지 않습니다. 개수 열에 0이 표시되지 않습니다. 또한 여기에서는 ROUND 기능을 사용하고 있습니다. 더 이해하기 쉽다고 느끼면 TRUNCATE로 쉽게 교체 할 수 있습니다.

여기에서 찾았습니다 http://blog.shlomoid.com/2011/08/how-to-quickly-create-histogram-in.html


답변

Mike DelGaudio의 대답은 제가하는 방식이지만 약간 변경되었습니다.

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.

베르나르도.


답변

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

테이블 bin에는 bin을 정의하는 min_value 및 max_value 열이 포함됩니다. 연산자 “join … on x BETWEEN y and z”가 포함되어 있습니다.

table1은 데이터 테이블의 이름입니다.


답변

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;


답변

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 ....

간격이 너무 많지 않은 한 이것은 꽤 좋은 솔루션입니다.


답변

나중에 Ofri Raviv의 솔루션과 함께 사용하기 위해 지정된 수 또는 크기에 따라 저장소에 대한 임시 테이블을 자동으로 생성하는 데 사용할 수있는 절차를 만들었습니다.

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

이렇게하면 채워진 빈에 대해서만 히스토그램 개수가 생성됩니다. David West가 그의 수정에 맞아야하지만 어떤 이유로 인해 결과에 채워지지 않은 빈이 나에게 나타나지 않습니다 (LEFT JOIN을 사용 했음에도 불구하고 – 나는 이유를 이해할 수 없습니다).


답변

작동합니다. 그렇게 우아하지는 않지만 여전히 :

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

Mike DelGaudio 를 통해