[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號出口



42會員
25內容數
歡迎來到彼得的沙龍,在這裡,我將與你分享理財增值的秘訣、書籍精華的智慧、人際溝通的技巧,以及情緒管理的策略。不僅幫助你打好財務基礎,還能引領你在人生的每個環節中游刃有餘。如果你渴望成長,並追求更充實的生活,這裡就是你值得關注的空間。立即加入,與我一起探索成長的無限可能!
留言0
查看全部
發表第一個留言支持創作者!
欸! 是彼得的沙龍 的其他內容
在進行SQL查詢邏輯更改時,需要適當地使用SubQuery和join來達到新的排序需求。本文將介紹原本的撈取邏輯、需求以及如何使用SubQuery來解決新的排序需求。
在進行SQL查詢邏輯更改時,需要適當地使用SubQuery和join來達到新的排序需求。本文將介紹原本的撈取邏輯、需求以及如何使用SubQuery來解決新的排序需求。
你可能也想看
Thumbnail
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
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
1.加權指數與櫃買指數 週五的加權指數在非農就業數據開出來後,雖稍微低於預期,但指數仍向上噴出,在美股開盤後於21500形成一個爆量假突破後急轉直下,就一路收至最低。 台股方面走勢需觀察週一在斷頭潮出現後,週二或週三開始有無買單進場支撐,在沒有明確的反轉訊號形成前,小夥伴盡量不要貿然抄底,或是追空
Thumbnail
近期的「貼文發佈流程 & 版型大更新」功能大家使用了嗎? 新版式整體視覺上「更加凸顯圖片」,為了搭配這次的更新,我們推出首次貼文策展 ❤️ 使用貼文功能並完成這次的指定任務,還有機會獲得富士即可拍,讓你的美好回憶都可以用即可拍珍藏!
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
自行車產業的景氣回春,對供應鏈和市場都產生了影響。該產業前景樂觀,但需要從品牌、車種和市場三個面向來進行分析。自行車產業的回溫與全球市場趨勢密不可分。此篇文章從多個角度對自行車產業進行了深入分析,提供了寶貴的前景洞察。