[GAS] 利用 YouBike 開放數據進行共享單車使用率分析

閱讀時間約 16 分鐘
自製 - Ubike2.0數據分析

自製 - Ubike2.0數據分析


最近,我偶然發現了一個有趣的分享,有人利用政府提供的 YouBike 開放數據來解決自己在使用 YouBike 時遇到找不到車可以借的麻煩。這讓我靈光一閃:為什麼不利用這些數據做一點有趣的數據分析,來看看不同時間點的 YouBike 使用率呢?

接下來,我決定展開一個小小的實驗,使用 Google Apps Script 來分析這些公開的資料,從而深入了解城市中的共享單車系統。或許,我們可以發現一些出乎意料的使用趨勢,甚至預測何時能輕鬆找到一輛空閒的 YouBike。讓我們一起挖掘這些數據背後的秘密吧!


使用的技術

1. Google Sheet

2. Google Apps Script

3. Javascript

  1. YouBike2.0臺北市公共自行車即時資訊


Google Apps Script實作流程

1. 每10分鐘從 YouBike json檔擷取數據,將原始數據存儲在 "Raw Data" 表

// 抓取 YouBike 數據並存儲
function fetchAndStoreYouBikeData() {
    try {
    var response = UrlFetchApp.fetch(YOUBIKE_API_URL);
    var data = JSON.parse(response.getContentText());
    var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Raw Data');

    if (!sheet) {
      sheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet('Raw Data');
      sheet.appendRow(['Timestamp', 'Station ID', 'Station Name', 'Total Bikes', 'Available Bikes', 'Available Spaces']);
    }

    var timestamp = new Date();
    var rowsAdded = 0;
    data.forEach(function(station) {
      var stationId = String(station.sno); // 將站點 ID 轉換為字串
      if (STATION_IDS.includes(stationId)) {
        sheet.appendRow([
          timestamp,
          stationId,
          station.sna,
          station.total,
          station.available_rent_bikes,
          station.available_return_bikes
        ]);

        rowsAdded++;
      } else {
        Logger.log('站點 ID 不匹配: ' + stationId);
      }
    });

    Logger.log('成功添加了 ' + rowsAdded + ' 行數據');

    // 如果沒有添加任何數據,記錄所有接收到的站點 ID

    if (rowsAdded === 0) {
      Logger.log('警告:沒有匹配的站點。接收到的站點 ID:' + data.map(station => station.sno).join(', '));
    }
  } catch (error) {
    Logger.log('錯誤:獲取或存儲 YouBike 數據時出錯 - ' + error.toString());
  }
}


2. 分析數據並在 "Analysis" 表中提供簡單的需求預測和供給建議

使用簡單的「線性回歸」來預測未來供需量
function analyzeDemandAndSupply() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Raw Data');
  var data = sheet.getDataRange().getValues(); 
  var analysisSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Analysis');

  if (!analysisSheet) {
    analysisSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet('Analysis');
    analysisSheet.appendRow(['Station ID', 'Station Name', 'Avg Available Bikes', 'Demand Prediction', 'Supply Recommendation']);
  }

  // 清空分析表格(保留表頭)
  analysisSheet.getRange(2, 1, analysisSheet.getLastRow(), 5).clear();
  var stationData = {};

  // 處理原始數據
  for (var i = 1; i < data.length; i++) {
    var stationId = String(data[i][1]); // 將站點 ID 轉換為字串
    if (STATION_IDS.includes(stationId)) {
      if (!stationData[stationId]) {
        stationData[stationId] = {
          name: data[i][2],
          availableBikes: [],
          totalBikes: data[i][3]
        };
      }
      stationData[stationId].availableBikes.push(data[i][4]);
    }
  }

  // 檢查是否有數據
  if (Object.keys(stationData).length === 0) {
    Logger.log('警告:沒有找到匹配的站點數據');
    return;
  }
 
  // 分析每個站點
  STATION_IDS.forEach(function(stationId) {
    var station = stationData[stationId];
    if (station && station.availableBikes.length > 0) {
      var avgAvailableBikes = average(station.availableBikes);
      var demandPrediction = predictDemand(station.availableBikes);
      var supplyRecommendation = recommendSupply(avgAvailableBikes, station.totalBikes)
      analysisSheet.appendRow([
        stationId,
        station.name,
        avgAvailableBikes,
        demandPrediction,
        supplyRecommendation
      ]);
    } else {
      Logger.log('警告:站點 ' + stationId + ' 沒有數據或可用自行車數據為空');
    }
  });
}


3. 針對每個出口站點建立分析圖表

// 需要一個函數來獲取站點名稱
function getStationNames() {
  var rawDataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Raw Data');
  var rawData = rawDataSheet.getDataRange().getValues();
  var stationNames = {};
 
  rawData.forEach(function(row) {
    if (row[1] && row[2]) {  // 確保站點 ID 和名稱都存在
      stationNames[String(row[1])] = row[2];
    }
  });
  return stationNames;
}



// 準備圖表資料
function prepareChartData() {
  var rawDataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Raw Data');
  var rawData = rawDataSheet.getDataRange().getValues();
  var stationNames = getStationNames();

  STATION_IDS.forEach(function(stationId) {
    var stationName = stationNames[stationId] || stationId;  // 如果找不到名稱,就使用 ID
    var chartDataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Chart Data ' + stationName);
    if (!chartDataSheet) {
      chartDataSheet = SpreadsheetApp.getActiveSpreadsheet().insertSheet('Chart Data ' + stationName);
    }

    // 清空圖表數據表格
    chartDataSheet.clear();

    // 添加表頭
    chartDataSheet.appendRow(['Timestamp', '使用率', '可租借的數量', '可還車的數量']);
   
    // 處理原始數據
    var stationData = rawData.filter(function(row) {
      return String(row[1]) === stationId;
    });

    // 將數據轉換為圖表格式
    stationData.forEach(function(row) {
      var timestamp = row[0];
      var availableBikes = row[4];
      var usingBike = row[5]; // 空車柱數量
      var usePercent = Math.round(usingBike / row[3] * 100)  // 可用車數 / 總車數 = 使用率
      chartDataSheet.appendRow([new Date(timestamp), usePercent, availableBikes, usingBike]);
    }); 

    // 創建圖表
    createChart(chartDataSheet, stationId, stationName);
  });
}



// createChart 函數

function createChart(sheet, stationId, stationName) {
  var charts = sheet.getCharts();

  // 如果已存在圖表,則刪除
  charts.forEach(function(chart) {
    sheet.removeChart(chart);
  });
 
  // 創建新圖表
  var chartBuilder = sheet.newChart();

  // 設置圖表類型為線圖
  chartBuilder.setChartType(Charts.ChartType.LINE);

  // 設置圖表標題,使用站點名稱
  chartBuilder.setOption('title', 'YouBike 站點 ' + stationName + ' 使用率分析');

  // 設置 X 軸
  chartBuilder.setOption('hAxis', {title: '時間'});
 
  // 設置 Y 軸
  chartBuilder.setOption('vAxis', {title: '使用率'});

  // 添加數據範圍
  chartBuilder.addRange(sheet.getRange("A2:B"));
  // 所有範圍:
  // chartBuilder.addRange(sheet.getDataRange());
 
  // 設置圖表位置
  chartBuilder.setPosition(1, 6, 0, 0);

  // 設置圖例
  chartBuilder.setOption('legend', {position: 'bottom'});
 
  // 設置線條顏色
  chartBuilder.setOption('series', {
    // 0: {color: 'blue', labelInLegend: '可租數量'},   // 可用車輛線條顏色
    // 1: {color: 'red', labelInLegend: '可還數量'},     // 空車率線條顏色
    0: {color: 'green', labelInLegend: '使用率'}     // 使用率線條顏色
  });

  // 添加圖表到工作表
  sheet.insertChart(chartBuilder.build());
}
此次針對公館捷運站4個不同出口的youbike站點來觀察不同時段的使用率

數據分析展示


可以得到幾個總結

  1. 公館站1號跟4號出口的使用率比較容易滿載,其原因與該站可租借的數量較少有直接的影響
  2. 公館站2號跟3號出口的可租借數量較高,因此即使使用量有時會升高,也蠻快就會恢復可租借的平衡
  3. 2號出口的使用率比3號出口的低,因此優選首選去租借ubike的站為2號出口



45會員
27內容數
歡迎來到彼得的沙龍,在這裡,我將與你分享理財增值的秘訣、書籍精華的智慧、人際溝通的技巧,以及情緒管理的策略。不僅幫助你打好財務基礎,還能引領你在人生的每個環節中游刃有餘。如果你渴望成長,並追求更充實的生活,這裡就是你值得關注的空間。立即加入,與我一起探索成長的無限可能!
留言0
查看全部
發表第一個留言支持創作者!
欸! 是彼得的沙龍 的其他內容
在進行SQL查詢邏輯更改時,需要適當地使用SubQuery和join來達到新的排序需求。本文將介紹原本的撈取邏輯、需求以及如何使用SubQuery來解決新的排序需求。
在進行SQL查詢邏輯更改時,需要適當地使用SubQuery和join來達到新的排序需求。本文將介紹原本的撈取邏輯、需求以及如何使用SubQuery來解決新的排序需求。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
本篇提供騎單車的穿搭建議,幫助正在嘗試單車通勤的你解決夏季騎車溼熱的困擾。
Thumbnail
從第一次環騎是4/28,到第二次環騎5/12,讓自己間隔14天。 中間我做了什麼預備?讓我可以順利完成第二次有備而來的環騎呢?
Thumbnail
然而,朝向綠色城市發展的同時,現階段不少民眾的體感是「無車可借」。《報導者》以地圖及影像,帶你瞭解目前YouBike使用輪廓,我們也自2月19日開始收集每日實時數據,觀察政策的可能影響。
Thumbnail
這篇文章是有關歐洲自行車展場的觀察,內容包括電動輔助自行車系統、變速套件與其他零件、IoT、攤位設計概念、人身部分與趣味產品。文章內容充滿豐富圖片和詳細說明。
基於節省資源與運動的好習慣 上下班或外出,能騎腳踏車就騎腳踏車 很遠的話,則盡量搭乘大眾運輸工具 上面的觀念,只是提醒大家隨時放在心上喔! 盡力做喔! 我會盡力想看看上班日能否騎腳踏車出門,如果當日還有其他地方要去,那就不騎腳踏車上班。或需趕時間回家的日子,就不要騎腳踏車上班。 自己衡量
Thumbnail
本篇觀察並分享關於Gravel/e-Gravel & e-bike整車產品的試騎後心得,探討了e-Bike, e-SUV, e-Gravel, Gravel車,e-Bike系統等相關議題,以及電池在e-MTB產品中的重要性。
Thumbnail
本篇述及2024歐展場下的市場情況,提及銷售情況、Bicycle Leasing program局勢、消費趨勢以及車店現況。深入探討了市場的現況。
Thumbnail
自行車產業的景氣回春,對供應鏈和市場都產生了影響。該產業前景樂觀,但需要從品牌、車種和市場三個面向來進行分析。自行車產業的回溫與全球市場趨勢密不可分。此篇文章從多個角度對自行車產業進行了深入分析,提供了寶貴的前景洞察。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
本篇提供騎單車的穿搭建議,幫助正在嘗試單車通勤的你解決夏季騎車溼熱的困擾。
Thumbnail
從第一次環騎是4/28,到第二次環騎5/12,讓自己間隔14天。 中間我做了什麼預備?讓我可以順利完成第二次有備而來的環騎呢?
Thumbnail
然而,朝向綠色城市發展的同時,現階段不少民眾的體感是「無車可借」。《報導者》以地圖及影像,帶你瞭解目前YouBike使用輪廓,我們也自2月19日開始收集每日實時數據,觀察政策的可能影響。
Thumbnail
這篇文章是有關歐洲自行車展場的觀察,內容包括電動輔助自行車系統、變速套件與其他零件、IoT、攤位設計概念、人身部分與趣味產品。文章內容充滿豐富圖片和詳細說明。
基於節省資源與運動的好習慣 上下班或外出,能騎腳踏車就騎腳踏車 很遠的話,則盡量搭乘大眾運輸工具 上面的觀念,只是提醒大家隨時放在心上喔! 盡力做喔! 我會盡力想看看上班日能否騎腳踏車出門,如果當日還有其他地方要去,那就不騎腳踏車上班。或需趕時間回家的日子,就不要騎腳踏車上班。 自己衡量
Thumbnail
本篇觀察並分享關於Gravel/e-Gravel & e-bike整車產品的試騎後心得,探討了e-Bike, e-SUV, e-Gravel, Gravel車,e-Bike系統等相關議題,以及電池在e-MTB產品中的重要性。
Thumbnail
本篇述及2024歐展場下的市場情況,提及銷售情況、Bicycle Leasing program局勢、消費趨勢以及車店現況。深入探討了市場的現況。
Thumbnail
自行車產業的景氣回春,對供應鏈和市場都產生了影響。該產業前景樂觀,但需要從品牌、車種和市場三個面向來進行分析。自行車產業的回溫與全球市場趨勢密不可分。此篇文章從多個角度對自行車產業進行了深入分析,提供了寶貴的前景洞察。