読者です 読者をやめる 読者になる 読者になる

Google Spreadsheetからデータを取得してPandasのDataframeに変換する例

最近はPythonを書く機会が多いのでPythonネタをメモ程度に書き留めておきます。

事前準備

データの準備

動作確認用のスプレッドシートを作成し、サービスアカウントで編集できるように権限を設定します。

(GoogleAPIを使用するためにサービスアカウントを使用しますが、設定手順は割愛します)

そのスプレッドシートに「iris」という名前のシートを作成し、シートの内容を以下のようにします。

f:id:ariarijp:20170528204805p:plain

Irisのデータは以下のリンクなどから入手できます。

UCI Machine Learning Repository: Iris Data Set

環境の準備

venv などを使用して、以下の requirements.txt を使用できるようにしてください。

google-api-python-client==1.6.2
httplib2==0.10.3
numpy==1.12.1
oauth2client==4.1.0
pandas==0.20.1
pyasn1==0.2.3
pyasn1-modules==0.0.8
python-dateutil==2.6.0
pytz==2017.2
rsa==3.4.2
six==1.10.0
uritemplate==3.0.0

コード例

処理についてはコメントを参照してください。

import httplib2
import os

import sys
from apiclient import discovery
from oauth2client.service_account import ServiceAccountCredentials

import pandas as pd

CLIENT_SECRET_FILE = os.environ.get('CLIENT_SECRET_FILE', 'client_secret.json')
SCOPES = 'https://www.googleapis.com/auth/spreadsheets.readonly'
DISCOVERY_URL = 'https://sheets.googleapis.com/$discovery/rest?version=v4'

credentials = ServiceAccountCredentials.from_json_keyfile_name(
    filename=CLIENT_SECRET_FILE,
    scopes=SCOPES)
http = credentials.authorize(httplib2.Http())
service = discovery.build(serviceName='sheets',
                          version='v4',
                          http=http,
                          discoveryServiceUrl=DISCOVERY_URL)

# スプレッドシートのIDをコマンドライン引数から取得する
spreadsheet_id = sys.argv[1]

# スプレッドシートからデータを取得する
values = service.spreadsheets().values() \
    .get(spreadsheetId=spreadsheet_id,
         range='iris!A:E') \
    .execute() \
    .get('values', [])

# 取得したデータをDataframeにする
df = pd.DataFrame \
    .from_records(data=values[1:],
                  columns=values[0])

# 全ての列がobject型になってしまうので、数値の列の型をfloatに変換する
df = df.astype({
    'sepal_length': float,
    'sepal_width': float,
    'petal_length': float,
    'petal_width': float,
})

# 動作確認
print('[df.describe]')
print(df.describe())
print()
print('[df.head]')
print(df.head(5))

実行

$ python example.py スプレッドシートID
[df.describe]
       sepal_length  sepal_width  petal_length  petal_width
count    150.000000   150.000000    150.000000   150.000000
mean       5.843333     3.054000      3.758667     1.198667
std        0.828066     0.433594      1.764420     0.763161
min        4.300000     2.000000      1.000000     0.100000
25%        5.100000     2.800000      1.600000     0.300000
50%        5.800000     3.000000      4.350000     1.300000
75%        6.400000     3.300000      5.100000     1.800000
max        7.900000     4.400000      6.900000     2.500000

[df.head]
   sepal_length  sepal_width  petal_length  petal_width      species
0           5.1          3.5           1.4          0.2  Iris-setosa
1           4.9          3.0           1.4          0.2  Iris-setosa
2           4.7          3.2           1.3          0.2  Iris-setosa
3           4.6          3.1           1.5          0.2  Iris-setosa
4           5.0          3.6           1.4          0.2  Iris-setosa

まとめ

とにかくなんでもPandasのデータフレームに持ち込めれば、Pandasの強力な機能の数々を使うことができるので、 様々なデータソースを使った処理を書いたり、分析したりする人にとって、Pandasはうれしいツールですね。もうちょっと勉強しつつ、実践投入していく予定です。

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

この本は図書館で借りたことがあったけど、手元に置いておきたいかも。

React NativeでCrashlyticsを使う手順

簡単だけど記録として残しておくための記事です。

前提

  • Macを使っている
    • この記事ではiOSアプリについての手順のみ紹介します
  • React Nativeがインストール済みで使ってiOSアプリを作ったことがある
    • HelloWorld程度の知識で十分です
    • 使用したバージョン
      • react-native-cli: 2.0.1
      • react-native: 0.43.3
  • Xcodeを少しだけ触ったことがある
    • ビルド、実行ぐらいができれば十分です
  • FabricのMacアプリがインストールされている
  • Crashlyticsがなにをしてくれるかをざっくり知っている

手順

プロジェクトを作成する

まずはReact Nativeのプロジェクトを作成します。

$ react-native init Hello

しばらくするとプロジェクトのディレクトリが作成されます。

Fabricアプリを使ってCrashlyticsを導入する

アプリを追加する

FabricのMacアプリで「New App」を選ぶと、Mac内にある.xcodeprojを探してくれるようです。

f:id:ariarijp:20170412135814p:plain

先程作成したプロジェクト内の.xcodeprojファイルがあると思うので、それを選択します。

使用するツールを選択する

次に使用したいツールを選択します。

f:id:ariarijp:20170412135830p:plain

今回はCrashlyticsのみをInstallして次に進みます。

ビルドスクリプトを編集する

続いて、Xcodeでビルドスクリプトを編集します。Fabricアプリで以下の画面が表示されるとともに、Xcodeが起動します。

f:id:ariarijp:20170412135846p:plain

プロジェクトの設定から「Build Phases」を選択し、左上の「+」ボタンから「New Run Script Phase」を選択します

「Run Script」のブロックが追加されるので、そこにFabricアプリに表示されているコマンドを貼り付けます。

f:id:ariarijp:20170412142658p:plain

コマンドを貼り付けたら、Cmd-Bなどでアプリをビルドします。

ライブラリをインストールする

ビルドが完了すると、Fabricアプリの画面が以下のように切り替わります。

f:id:ariarijp:20170412140625p:plain

この画面に切り替わったら、Crashlyticsを使用するために必要なライブラリをXcodeプロジェクトにインストールします。

FabricアプリのバッグのようなアイコンをXcodeプロジェクトにドラッグアンドドロップすると、以下のような画面が表示されます。

f:id:ariarijp:20170412141203p:plain

「Finish」ボタンをクリックして先に進みます。

コードを編集する

ライブラリをインストールすると、以下のような画面が表示されます。

f:id:ariarijp:20170412141403p:plain

画面でハイライト表示されているコードをコピーして、プロジェクト内のAppDelegate.mファイルに貼り付けます。

f:id:ariarijp:20170412141659p:plain

せっかくReact Nativeを使っているのにObj-Cだなんて辛い!と思うかもしれませんが我慢してください。

コードを追加し終わったら、Fabricアプリの画面の「Next」をクリックして先に進みます。

アプリを起動する

Fabricアプリが以下のような画面になるので、Xcodeを使用し、Cmd-Rなどでアプリを実行します。

f:id:ariarijp:20170412141942p:plain

無事にアプリが起動すれば、iOSシミュレータで以下のような画面が表示されます。

f:id:ariarijp:20170412142233p:plain

あわせて、Fabricアプリも以下のような画面に切り替わります。

f:id:ariarijp:20170412142310p:plain

これでCrashlyticが導入できました。Fabricの画面を見てみるとHelloアプリが追加されています。

PHPExcelの後継っぽいPhpSpreadsheetでExcelファイルを読み書きするサンプルコード

PHPExcel

PHPExcelを操作する。というと「やめておけ」という言葉の次に上がってくる有名なライブラリは、PHPExcelではないかと思います。

github.com

溜まりに溜まったIssuesとPull Requestsの数を見ると不安な気持ちになってしまいますが、後継のライブラリーが開発中のようです。

github.com

PHPExcel vs PhpSpreadsheet ? に書いてある通り、PHPExcelと互換性のない変更が含まれるため別プロジェクトになっているようで、開発もPhpSpreadsheetに注力しており、PHPExcelはもうメンテナンスされていないということについても明言されています。

サンプルコード

まだ安定版がリリースされていませんが、PhpSpreadsheetを使った簡単なサンプルコードを書いてみました。

動作環境

HomebrewでインストールしたPHP7.0で動作確認しました。

$ php -v
PHP 7.0.17 (cli) (built: Mar 18 2017 20:13:50) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies

composer.json

composer.json は以下のようになっています。

{
    "require": {
        "phpoffice/phpspreadsheet": "dev-develop"
    }
}

安定版がなので dev-develop を指定しています。

読み込みに使用するExcelファイル

以下のようなファイルを使用します、手元にExcelがないので、ファイルはNumbersで作りました。

f:id:ariarijp:20170326200437p:plain

サンプルコード本体

Excelファイルから特定の範囲を読み出し、各値を2乗したものを別ファイルに書き出すものです。

書き出し先はExcelファイルとCSVファイルの2パターン用意しました。

<?php

require 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Settings;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheet\Writer\CSV as CSVWriter;

/*
 * 読み込みサンプル
 */
$reader = new XlsxReader();
$spreadsheet = $reader->load('sample1.xlsx');
$sheet = $spreadsheet->getActiveSheet();

// B2からD4までの領域を2次元配列として取得する
$dataArray = $sheet->rangeToArray('B2:D4');

/*
 * 書き出しサンプル
 */
// 上記のサンプルコードで読み出した各値を2乗する
array_walk_recursive($dataArray, function (&$x) {
    $x = $x ** 2;
});

// B1を起点として2次元配列をシートに書き込む
$sheet->fromArray($dataArray, null, 'B2');

// Excel(.xlsx)として書き出す
$writer = new XlsxWriter($spreadsheet);
$writer->save('sample2.xlsx');

// CSVとして書き出す
$writer = new CSVWriter($spreadsheet);
$writer->save('sample2.csv');

実行結果

実行結果として書き出された sample2.xlsx は以下のようになります。

f:id:ariarijp:20170326200831p:plain

また、 sample2.csv はこのようになります。

"","列1","列2","列3","列4"
"行1","1","4","9","4"
"行2","25","36","49","8"
"行3","81","100","121","12"
"行4","13","14","15","16"

まとめ

まだ開発中ではありますが、どうしてもPHPExcelを操作しなければならない時はPHPExcelとあわせてPhpSpreadsheetも検討してみるといいかもしれません。

PHPCompatibilityを実行するためのDockerイメージを作った

PHP5からPHP7への移行を検討するとき、この記事を思い出してPHPCompatibilityを使ってみたところ、結構便利そうだった。

kakakakakku.hatenablog.com

で、ちょっと導入が面倒な気がしたので、Dockerイメージに無理やり押し込んでみたのがこちら。

https://hub.docker.com/r/ariarijp/php-compatibility/

PHP_CodeSnifferとPHPCompatibility導入済みのイメージなので、Dockerホスト上のPHPアプリが置いてあるディレクトリをマウントすれば phpcs が実行できる。

設定ファイルは元記事を参考に、PHP7で非推奨になったものをチェックする。

<?xml version="1.0"?>
<ruleset name="wordpress">
  <rule ref="PHPCompatibility">
    <arg name="testVersion" value="7.0" />
    <exclude name="PHPCompatibility.PHP.DefaultTimezoneRequired" />
  </rule>
</ruleset>

試しにWordPressを対象に実行してみる例がこちら

$ docker run --rm -v `pwd`:/mnt/host ariarijp/php-compatibility phpcs --extensions=php --standard=/mnt/host/ruleset.xml /mnt/host/wordpress

FILE: /mnt/host/wordpress/wp-admin/includes/class-ftp.php
----------------------------------------------------------------------
FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE
----------------------------------------------------------------------
 902 | WARNING | Function dl() is deprecated since PHP 5.3
----------------------------------------------------------------------


FILE: /mnt/host/wordpress/wp-admin/includes/class-pclzip.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 2 LINES
----------------------------------------------------------------------
 5345 | ERROR | Function set_magic_quotes_runtime() is deprecated
      |       | since PHP 5.3 and removed since PHP 7.0
 5376 | ERROR | Function set_magic_quotes_runtime() is deprecated
      |       | since PHP 5.3 and removed since PHP 7.0
----------------------------------------------------------------------

...略...

PHP5.6のEOLは2018/12/31。まだ余裕があるようで、時間はあっという間に過ぎてしまうので、こういったツールも活用しつつ計画的にアップグレードしていきたいところ。

PHP BLT #6 でPHPのパフォーマンスモニタリングについてLTした

ちょっと前の話になってしまいますが、2/22にメルカリさんで開催されたPHP BLT #6に参加しました。

phpblt.connpass.com

発表内容

php-profiler-extensionとElasticsearch/Kibanaを使用したパフォーマンスモニタリングの試行について発表しました。

speakerdeck.com

5分に収まるように資料を無理やりまとめてしまったのと、発表時は緊張してたのもあって、駆け足なLTになってしまったのですが、後からハッシュタグを追ってみるとphp-profiler-extensionはXHProfの代替として利用でき、PHP7に対応しているというところは興味を持っていただけたようでした。

LTで軽くデモをしたElasticsearch/Kibanaでの可視化については、別途記事を書くかもしれません。

感想

PHP BLT初参加だったのですが、話題が多岐にわたりながらLTサイズ(5分)で聞けるので、普段気にしていなかったり触れていなかったことを発見できる場として、素直にいいなと思いました。

個人的にはPHP BLT #5での @sotarok さんの発表スライドを見て、次に開催されるときは必ず参加しようと思っていたこともあり、そういった意味でも充実した時間を過ごすことができました。

speakerdeck.com

遅くなってしまいましたが、メルカリさん(と、司会の @koemu さん)ありがとうございました!