0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

身長が165cm~170cmである日本人男性の数を調べた

Posted at

概要

身長が165cm~170cmである日本人男性の数、割合をいい加減な精度で算出した。

方法

chatGPT君にコードを生成してもらい、筆者が適宜コードを書き換えた。

使用した技術

筆者がReactの勉強をしたいと思っているので、chatGPTでコードを生成した。グラフ部分はchart.jsを利用した。

その他追記事項

筆者は統計学に関して全くの無知です。ですので、明らかに間違えている場合があります。
計算部分もJavaScriptで実装されているので、精度に関しては責任を一切負いません。
5分程ですべて実装(生成)したため、正しく動作していないような気がしています。

前提

平均値(中央値) 172cm
標準偏差 6cm
日本人男性総数 6175万人

結果

2024-11-23_qiita.png

総数 15597709人
日本人男性に占める割合 0.252594478

使用したコード

PopulationInRangeWithLines.jsx
import React, { useState } from "react";
import {
  Chart as ChartJS,
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
  Title,
  Tooltip,
  Legend,
} from "chart.js";
import { Line } from "react-chartjs-2";
import annotationPlugin from "chartjs-plugin-annotation"; // Annotation プラグイン

// 必要な要素を登録
ChartJS.register(
  CategoryScale,
  LinearScale,
  PointElement,
  LineElement,
  Title,
  Tooltip,
  Legend,
  annotationPlugin // Annotation プラグインを登録
);

const PopulationInRangeWithLines = () => {
  const [mean, setMean] = useState(170); // 平均身長
  const [stdDev, setStdDev] = useState(6); // 標準偏差
  const [totalPopulation, setTotalPopulation] = useState(61750000); // 総人口
  const [rangeMin, setRangeMin] = useState(160); // 区間の下限値
  const [rangeMax, setRangeMax] = useState(180); // 区間の上限値

  const calculateGaussian = (mean, stdDev) => {
    const dataPoints = 100; // X軸の点数
    const min = mean - 4 * stdDev; // 表示範囲の最小値
    const max = mean + 4 * stdDev; // 表示範囲の最大値
    const step = (max - min) / dataPoints; // 1ステップの幅

    const xValues = [];
    const yValues = [];

    for (let i = 0; i <= dataPoints; i++) {
      const x = min + i * step;
      const pdf =
        (1 / (Math.sqrt(2 * Math.PI) * stdDev)) *
        Math.exp(-0.5 * Math.pow((x - mean) / stdDev, 2));
      xValues.push(x.toFixed(1)); // 小数点1桁まで表示
      yValues.push(pdf * totalPopulation * step); // 人口を計算
    }

    return { xValues, yValues };
  };

  const calculatePopulationInRange = (mean, stdDev, rangeMin, rangeMax, totalPopulation) => {
    const step = 0.1; // 積分のステップ幅
    let population = 0;

    for (let x = rangeMin; x <= rangeMax; x += step) {
      const pdf =
        (1 / (Math.sqrt(2 * Math.PI) * stdDev)) *
        Math.exp(-0.5 * Math.pow((x - mean) / stdDev, 2));
      population += pdf * step * totalPopulation; // 人口を合計
    }

    return Math.round(population); // 四捨五入して整数に
  };

  const { xValues, yValues } = calculateGaussian(mean, stdDev);

  const populationInRange = calculatePopulationInRange(mean, stdDev, rangeMin, rangeMax, totalPopulation);

  const data = {
    labels: xValues,
    datasets: [
      {
        label: "Height Distribution (Population)",
        data: yValues,
        borderColor: "blue",
        borderWidth: 2,
        fill: false,
      },
    ],
  };

  const options = {
    responsive: true,
    plugins: {
      legend: {
        display: true,
      },
      annotation: {
        annotations: {
          rangeMinLine: {
            type: "line",
            xMin: rangeMin,
            xMax: rangeMin,
            borderColor: "red",
            borderWidth: 2,
            label: {
              content: `Min: ${rangeMin} cm`,
              enabled: true,
              position: "end",
            },
          },
          rangeMaxLine: {
            type: "line",
            xMin: rangeMax,
            xMax: rangeMax,
            borderColor: "green",
            borderWidth: 2,
            label: {
              content: `Max: ${rangeMax} cm`,
              enabled: true,
              position: "end",
            },
          },
        },
      },
    },
    scales: {
      x: {
        title: {
          display: true,
          text: "Height (cm)",
        },
      },
      y: {
        title: {
          display: true,
          text: "Population",
        },
      },
    },
  };

  return (
    <div style={{ width: "80%", margin: "0 auto", textAlign: "center" }}>
      <h1>Population in Height Range</h1>
      <div style={{ marginBottom: "20px" }}>
        <label>
          Mean (cm):{" "}
          <input
            type="number"
            value={mean}
            onChange={(e) => setMean(Number(e.target.value))}
          />
        </label>
        <label style={{ marginLeft: "10px" }}>
          Standard Deviation (cm):{" "}
          <input
            type="number"
            value={stdDev}
            onChange={(e) => setStdDev(Number(e.target.value))}
          />
        </label>
        <label style={{ marginLeft: "10px" }}>
          Total Population:{" "}
          <input
            type="number"
            value={totalPopulation}
            onChange={(e) => setTotalPopulation(Number(e.target.value))}
          />
        </label>
        <label style={{ marginLeft: "10px" }}>
          Min Height (cm):{" "}
          <input
            type="number"
            value={rangeMin}
            onChange={(e) => setRangeMin(Number(e.target.value))}
          />
        </label>
        <label style={{ marginLeft: "10px" }}>
          Max Height (cm):{" "}
          <input
            type="number"
            value={rangeMax}
            onChange={(e) => setRangeMax(Number(e.target.value))}
          />
        </label>
      </div>
      <h2>
        Population in Range ({rangeMin} cm - {rangeMax} cm): {populationInRange.toLocaleString()} people
      </h2>
      <Line data={data} options={options} />
    </div>
  );
};

export default PopulationInRangeWithLines;

おわりに

ReactはVueより実装しやすいような気がした。
特に

sample.js
const [val, setVal] = useState(12345);

この部分が、後から読み返したときに理解しやすいような気がします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?