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

からあげ定食

僻地の大学生の進捗発表。R,Python,yacht,twitteR,自然言語処理,将棋,機械学習,ヨット

Mac Finderのタブにファイルのパスを表示する方法

普段Rをよく使うので、例えばcsvのデータを読み込むときなど、ファイルのパスを知りたい場面がたくさんあります。Macの標準のRエディタならば、ファイルをエディタにドラッグアンドドロップでパスを表示してくれるのですが、sublime text3に変えてからできなくなってしまいました。

いろいろ調べた結果、どうやらFinderの上部にファイルパスを表示してくれる設定ができるみたい!

参考:Mac Finderのタイトルバーにフォルダのフルパスを表示する裏技 / Inforati

こうゆうこと、
f:id:fujit33:20150410192400p:plain

まず、ターミナルを起動。ターミナルはアプリケーションフォルダのユーティリティの中にある。
そしてこれを打ち込んでreturn

defaults write com.apple.finder _FXShowPosixPathInTitle -boolean true

そしてFinderを再起動させるだけ。

元に戻すには

defaults delete com.apple.finder _FXShowPosixPathInTitle

して再起動。
簡単だね。

【R】質的データから円グラフを作る

 [565] "autotweety.net"                           "twittbot.net"                            
 [567] "Janetter Pro for iPhone"                  "Osfoora for iOS"                         
 [569] "twittbot.net"                             "Twitter for Android"                     
 [571] "Twitter for iPhone"                       "Twitter for iPhone"                      
 [573] "Twitter for iPhone"                       "Twitter for iPhone"                      
 [575] "Facebook"                                 "Twitter for Android" 

このような、同じものが何回も出てくるデータの割合を円グラフにして表したいということはよくあると思います。
今回は、Twitterのデータから、ツイートをつぶやいたアカウントの割合を円グラフで表します。

# ツイートを取得
tweet <- searchTwitter("スターバックス",1000)
# ツイートをデータフレームに		
tw <- twListToDF(tweet)
# つぶやいたクライアントをURL表示からクライアント名に変換	
tw[,"statusSource"] <- substr(tw[,"statusSource"],
    regexpr(">",tw[,"statusSource"])+1,
    nchar(tw[,"statusSource"])-4)

# ツイートのクライアントの頻度表を作成
source <- data.frame(table(tw$statusSource)) 
# 度数分布表を度数の多い順に並べる
source.order <- source[order(source$Freq,decreasing=T),]
# 度数分布表を相対度数分布表に
source.pie <- source.order[,2]/sum(source.order[,2])
# 名前をつける
names(source.pie) <- source.order[,1]
# 円グラフを表示
pie(source.pie)

f:id:fujit33:20150406173250p:plain]
頻度が1しか無いものが多くてごっちゃごちゃになっていますので、頻度の少ないものをその他にまとめたいですが……すみませんまた今度やります。
こう見ると、iPhoneAndroidなどでつぶやいている人は以外に少ないように思います。残りは非公式クライアントもありますが、ほとんどがBotです。

ちなみに、同じことをキーワード「大相撲」に変えてやってみました。(スタバの対極を考えて浮かんだものが大相撲だった)
f:id:fujit33:20150406175827p:plain
こちらは、iPhoneAndroidからのつぶやきの割合が大きいことが分かります。おそらく、スタバ関連のBotは多く、大相撲関連のBotは少ないからでしょう。

twitteRでツイートをキーワード検索

twitteRを使い、キーワードでツイートを取得するにはsearchTwitter()関数を使う。
twitterの認証等は済でtwitteRの関数がそのまま使える状態とする。

library(twitteR) 
tweet <- searchTwitter("江ノ島",10) # 「江ノ島」が含まれるツイート最新10個取得
tw.df <- twListToDF(tweet) # Rで扱いやすいデータフレームに変換
tw.df[,"text"]
# ---
 [1] "RT @kitbox_anepochi: 【江ノ島コスプレ祭】にご参加いただきましたみなさま 本日はありがとうございました!\n物販では不慣れな対応ですみませんでした~(&gt;&lt;)\n普段ツイッターでお話ししている方々とお会いできて楽しかったです(^-^)/凸\nお帰り途中の皆さまどうぞ…"   
 [2] "RT @T25_owner: #江ノ島コスプレ祭 で撮影した江ノ島さんぽちゃん @enoshimasanpo \n#キャラサミ http://t.co/01uww5DRMZ"                                                                                                                                                
 [3] "@sheher_maydy こんばんは!本日ADVにてダンガンロンパの江ノ島盾子をやっておりました彼方(かなた)です♪ 本日はとても可愛いリンちゃんを撮影させていただきありがとうございました♡本当の双子のようでした♡ もしよろしければ、フォロー失礼してもよろしいでしょうか?><"
 [4] "RT @horinchi: これから咲く花、今咲く花、すでに散った花。儚くも美しい桜とさんぽちゃん。 #江ノ島さんぽちゃん #江ノ島 http://t.co/7A2pYpXhRz"                                                                                                                        
 [5] "ヴィジュアル系は釣り針と共に水中へ江ノ島ドーンされる…"                                                                                                                                                                                                           
 [6] "【片瀬江ノ島方面】\n22:53 の電車は 当駅始発 各駅停車 片瀬江ノ島 ゆきです\n\n次の電車は 23:00 急行 藤沢 ゆきです\n#小田急相模大野駅 [22:42:03]"                                                                                                                    
 [7] "誰か江ノ島いこーぜー!ただし平日なーw"                                                                                                                                                                                                                            
 [8] "@Aug_1st_skyblue 江ノ島行くと、甘味屋かホットケーキかで悩む人ですw←間違ってるw"                                                                                                                                                                                  
 [9] "@meguri28 えっ 江ノ島なのww"                                                                                                                                                                                                                                   
[10] "明日Uni-Share Vol.9が発行ということで懐かしさに浸る。\nみんなお疲れさまでした。\n\n#unishare #vol #7 #coordinate #江ノ島 #Tさん @… https://t.co/pAlSVXJUGg"
# ---

このような形で簡単にツイートを取得できる。

searchTwitter()関数の引数には次のようなものが指定できる。

searchTwitter(
"searchString", n=25, lang=NULL,since=NULL, until=NULL,locale=NULL, 
geocode=NULL, sinceID=NULL,retryOnRateLimit=120
) # 何も指定していなかった場合

# searchString 検索する言葉
# n 取得するツイートの数(その数存在するとは限らない)
# lang	つぶやかれている言語で制限 (ex: 'ja','en') 
# sinse  ツイートを取得する期間の初めの日付(ex: '2014-06-06')
# until	ツイートを取得する期間の終わりの日付(ex: '2014-06-08')
# locale クエリの言語を設定。ja(JSON)しか選択できない(ex:'ja')
# geocode  指定地点の周辺のツイートを取得する。第3引数はその地点の周囲nキロ。
	   # (ex: '35.388184,139.247367,10km)
# sinceID 指定したツイートのID以降につぶやかれたものを取得する
# retryOnRateLimit すみません。分かりません。だれか教えてー

geocodeで位置からツイートを収集しようとしても、ほとんど位置情報をつけてつぶやく人が少ないため、大量に集めるのはなかなか難しい。また、過去に遡れるツイートは1週間前までである。


twListToDF()関数を使ってデータフレームにした後、str()関数で中身を見てみるとこんな感じ。

> str(tw.df)
'data.frame':	10 obs. of  16 variables:
 $ text         : chr  "RT @kitbox_anepochi: 【江ノ島コスプレ祭】にご参加いただきましたみなさま 本日はありがとうございました!\n物販では不慣れな対応で"| __truncated__ "RT @T25_owner: #江ノ島コスプレ祭 で撮影した江ノ島さんぽちゃん @enoshimasanpo \n#キャラサミ http://t.co/01uww5DRMZ" "@sheher_maydy こんばんは!本日ADVにてダンガンロンパの江ノ島盾子をやっておりました彼方(かなた)です♪ 本日はとても可愛いリンち"| __truncated__ "RT @horinchi: これから咲く花、今咲く花、すでに散った花。儚くも美しい桜とさんぽちゃん。 #江ノ島さんぽちゃん #江ノ島 http://t.co/"| __truncated__ ...
 $ favorited    : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ favoriteCount: num  0 0 0 0 0 0 1 0 0 0
 $ replyToSN    : chr  NA NA "sheher_maydy" NA ...
 $ created      : POSIXct, format: "2015-03-29 13:42:48" ...
 $ truncated    : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ replyToSID   : chr  NA NA NA NA ...
 $ id           : chr  "582176082025000960" "582176063481987073" "582176055504465921" "582176038156775424" ...
 $ replyToUID   : chr  NA NA "2478333073" NA ...
 $ statusSource : chr  "<a href=\"http://twitter.com/download/android\" rel=\"nofollow\">Twitter for Android</a>" "<a href=\"http://twitter.com/download/android\" rel=\"nofollow\">Twitter for Android</a>" "<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>" "<a href=\"http://twitter.com/download/android\" rel=\"nofollow\">Twitter for Android</a>" ...
 $ screenName   : chr  "85izumitan" "85izumitan" "stars_mnmm" "85izumitan" ...
 $ retweetCount : num  3 6 0 11 0 0 0 0 0 0
 $ isRetweet    : logi  TRUE TRUE FALSE TRUE FALSE FALSE ...
 $ retweeted    : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ longitude    : chr  NA NA NA NA ...
 $ latitude     : chr  NA NA NA NA ...

# text ツイート本文
# favorited ファボられているか否か (TRUE or FALSE)
# favoriteCount ファボられた回数
# replyToSN リプライ先のscreen name(@~)
# created つぶやかれた日時
# id ツイート固有のID
# repyToUID リプライ先のユーザーID(@~とは別に存在する数字のID)
# statusSource つぶやかれたクライアント
# screenName つぶやいたアカウントのscreen name(@~)
# retweetCount リツイートされている回数
# isRetweet そのつぶやきがリツイートか否か (TRUE or FALSE)
# retweeted そのツイートがリツイートされているか否か (TRUE or FALSE)
# longitude 経度
# latitude 緯度

これらの情報がひとつのツイートに含まれている。
isRetweetとretweetedの違いは、検索して取得したそのツイートが別のユーザによってRTされたものであるのかを判定するものと、単純にそのツイートはRTされているのかを判定するもの、という違い。
また、先述の通り位置情報をつけてつぶやく人はあまりいないので、緯度経度の情報はほとんど含まれていない。

(参考)
cran.r-project.org/web/packages/twitteR/twitteR.pdf

FireFoxでTwitterなどにログインできなくなったときの対処法

突然FireFoxTwitterやPocketにログインできなくなってしまった。何度正しいIDとパスワードを打っても同じページのまま進まない。
しかしググったらFireFox公式のヘルプですぐ直ったのでメモ。


Web サイトにログインできない | Firefox ヘルプ


対処法がいくつか書かれているが、私はcookieとキャッシュを消去してログインできるようになった。

f:id:fujit33:20150306220931p:plain

GAEとPythonでギリシャの時間を知らせるTwitter Botをつくる

前回ようやくBotを作ることに成功したので、他にも作ってみよう!
(前回記事)

PythonでTwitter Botを作るまでの長い長い物語(完結編) - からあげ定食
知り合いがギリシャに旅行中なので、ギリシャの現地時刻を知らせる単純なBotを作ってみることにする。

現在時刻を取得するモジュールはdatetime

from date time import datetime
d = datetime.today()
print "今は%s年%s月%s日%s時%s分%s秒" %(d.year, d.month, d.day, d.hour, d.minute, d.second)

# 今は2015年3月6日21時9分25秒

タイムゾーンを扱うモジュールはpytz

使い方はここを参考にしました。
pytz – Pythonでタイムゾーンを扱うライブラリ | 情シスハック
[python]pytzモジュールでのタイムゾーン一覧 | KentaKomai Blog

from datetime import datetime
import pytz

jst = pytz.timezone('Asia/Tokyo') #日本のタイムゾーン
eet = pytz.timezone('Europe/Athens') #ギリシャのタイムゾーン

j = datetime.today()
g = j.replace(tzinfo=jst).astimezone(eet) #タイムゾーンを自分で設定してから変換する(直接やるとエラー)

print '日本の現在時刻は%s時%s分です' % (j.hour,j.minute)
print 'ギリシャの現在時刻は%s時%s分です' % (g.hour,g.minute)
# 日本の現在時刻は21時18分です
# ギリシャの現在時刻は14時18分です

そしてBotのコードがこれ!

tweet.py
#!/usr/bin/env python
#coding: utf-8

from google.appengine.ext import webapp

import keys
import GAE_Oauth.oauth

CONSUMER_KEY = keys.twi_key['consumer_key']
CONSUMER_SECRET = keys.twi_key['consumer_secret']
ACCESS_TOKEN = keys.twi_key['access_token_key']
ACCESS_SECRET = keys.twi_key['access_token_secret']

def getGreeceTime():
    from datetime import datetime
    import pytz
    jst = pytz.timezone('UTC')
    eet = pytz.timezone("Europe/Athens")
    j = datetime.today()
    g = j.replace(tzinfo=jst).astimezone(eet)
    text = u'現在のギリシャ時間は%s時%s分!' % (g.hour,g.minute)
    return text


class TweetHandler(webapp.RequestHandler):

    def get(self):
        import GAE_Oauth.oauth
        from datetime import datetime 
        client = GAE_Oauth.oauth.TwitterClient(CONSUMER_KEY, CONSUMER_SECRET, None)

        tweet = getGreeceTime()
        param = {'status': tweet}

        # Twitter API 1.1 に対応
        client.make_request('https://api.twitter.com/1.1/statuses/update.json',
    	token=ACCESS_TOKEN,
      	secret=ACCESS_SECRET,
	    additional_params=param,
	    protected=True,
	    method='POST')
        self.response.out.write(tweet)
app.py
#!/usr/bin/env python

import webapp2
from google.appengine.ext.webapp.util import run_wsgi_app

from tweet import *

app = webapp2.WSGIApplication([
    ('/greece', TweetHandler)
], debug=True)

def main():
	run_wsgi_app(app)

if __name__ == "__main__":
	main()
app.yaml

application: greesayo
version: 1
runtime: python27
api_version: 1
threadsafe: false

handlers:
- url: .*
  script: app.app

libraries:
- name: webapp2
  version: "2.5.2"
- name: ssl
  version: "latest"

できた!

GAE上でdatetimeを使うと国際標準時で取得されるようなので、タイムゾーンの変換を"UTC"→"Europe/Athens"に変えています。
pytzは標準モジュールでは無いのでダウンロードしてディレクトリに置いておく。
コンシューマーキーなどはkeys.pyとして保存し、tweet.pyから読み込む。
cron.yamlは省略。
GitHub使いたいけど使ったこと無いからそのうち。

Google App Engineでcronの設定をする

Google App Engine で自動実行をさせたいときはcron.yamlを編集します。
アプリケーションを作るとき、デフォルトではこのファイルは無いので自分で作ることになる。

例えばこんな感じ

cron:
- description: tweet_post
  url: /tweet
  schedule: every 2 hours from 8:00 to 24:00
  timezone: Asia/Tokyo

description 説明書き。
url cronがアクセスするurl。ここにアクセスするとコードが実行される。
schedule 実行する間隔を指定する。書式が決まっている。
timezone これを指定しておくと、scheduleを日本時間で記述できる。

scheduleの記述の書式の例

(引用:GAE公式Scheduled Tasks With Cron for Python - Python — Google Cloud Platform

every 12 hours
every 5 minutes from 10:00 to 14:00
2nd,third mon,wed,thu of march 17:00
every monday 09:00
1st monday of sep,oct,nov 17:00
every day 00:00

普通のサーバーでcrontabを編集する際はvimemacsなどで書くことになり、慣れていない人にとってはつらいものがある。しかし、これならば簡単かつぱっと見でもも分かりやすい。さすがGoogle

PythonでTwitter Botを作るまでの長い長い物語(完結編)

前編の失敗編に引き続き、後編の完結編です。

PythonでTwitter Botを作るまでの長い長い物語(失敗編) - からあげ定食

最初に予告しておきますが、後編も半分が失敗です。

"Python Twitter Bot"と検索すると、Google App Engineなるものが目につきます。
Google App Engine(以下GAE)とは、
Google社の提供するクラウドサービス。同社の運用するサーバ環境に自分の開発したWebアプリケーションを置き、実行・公開することができる。利用できるプログラミング言語PythonJava
(引用:Google App Engineとは 【 GAE 】 - 意味/解説/説明/定義 : IT用語辞典)

Google先生につきまとっていたところ、どうやら前回の自分と同じところでつまづいてGAEに移っている人が多かったようで、自分もその流れにのることに。

GAEでPythonを使う方法はこちらのサイトが素晴らしくわかりやすくまとめてあり、とても勉強になりました。
Google AppEngine/Python入門 - サーバを作ってみよう | adamrocker
ですので、細かい使い方は省略します。
このサイトを参考に、既に作っているtweepyを使ったpythonでツイートを投稿するコードを実行できるようにする。

もちろん、tweepyライブラリも作業ディレクトリにアップロードするのですが、他にも大量のライブラリを入れさせられます。
実行しては、ImportError: No module named ~
また実行しては ImportError: No module named ~
の繰り返しです。気力との戦いでした……

最終的にディレクトリはこんな感じに

 app.yaml
 crom.yaml
 main.py
 ----ここから下が追加したライブラリ----
 tweepy
 outhlib
 requests
 requests_outhlib
 six.py

やっと動くかとおもいきや、

The Socket API will be enabled for this application once billing has been enabled in the admin console

課金の設定をしろといわれました。え、無料じゃなかったの!?と思いましたが、ここまでやったし課金して動くなら……と思い、クレジットカードを登録。結果……


動きませんでした!!!!涙!!!


もうやだ!
心が折れそうになりました。必至で調べましたが、Socket APIはGAEでは対応していないとのこと。そしてどうやらtweepyやpython-twitterはSocket APIを使わなければいけないということが分かりました。じゃあなんでできてる人がいるんですか!!!分かりません。分かったら誰か教えてください。

第二章 Google App Engine + tweepy編 〜完〜


第三章 tweepy無しでGoogle App Engine

折れかけた心をなんとかつなぎとめてくれたのがこのサイトでした。

Google App Engine for Python でTwitter bot (twitter API 1.1) - homma.py

自分と同じように、GAEでtweepyを使うことを諦めて、ライブラリを使わずにtweetを投稿しています。最後のお願いということで、このサイトをほぼパクるような形でbotを作らせていただきました。すると、

うごきました!!!!!涙!!!


コードはこんな感じ。

tweet.py #ツイートの機能を実装
#!/usr/bin/env python

from google.appengine.ext import webapp

import keys
import GAE_Oauth.oauth

CONSUMER_KEY = keys.twi_key['consumer_key']
CONSUMER_SECRET = keys.twi_key['consumer_secret']
ACCESS_TOKEN = keys.twi_key['access_token_key']
ACCESS_SECRET = keys.twi_key['access_token_secret']

class TweetHandler(webapp.RequestHandler):
    def get(self):
        import GAE_Oauth.oauth
        from random import choice
        client = GAE_Oauth.oauth.TwitterClient(CONSUMER_KEY, CONSUMER_SECRET, None)
   
        tweet = choice(list(open("meigen.txt"))).replace("\\n","\n")
        param = {'status': tweet}

        # Twitter API 1.1 に対応
        client.make_request('https://api.twitter.com/1.1/statuses/update.json',
    	token=ACCESS_TOKEN,
      	secret=ACCESS_SECRET,
	    additional_params=param,
	    protected=True,
	    method='POST')
        self.response.out.write(tweet)
app.py #機能を実行する
#!/usr/bin/env python

import webapp2
from google.appengine.ext.webapp.util import run_wsgi_app

from tweet import *

app = webapp2.WSGIApplication([
    ('/tweet', TweetHandler)
], debug=True)

def main():
	run_wsgi_app(app)

if __name__ == "__main__":
	main()
app.yaml 
application: shogi-bot
version: 1
runtime: python27
api_version: 1
threadsafe: false

handlers:
- url: /.*
  script: app.app

libraries:
- name: webapp2
  version: "2.5.2"
- name: ssl
  version: "latest"
cron.yaml
cron:
- description: tweet_post
  url: /tweet
  schedule: every 1 hours
  timezone: Asia/Tokyo

tweepy無しでtwitterAPIを使う方法は、このサイトが参考になります。
Twitter - Google App Engine for PythonでTweet(API1.1) - Qiita
meigen.txtに改行区切りでつぶやく言葉を書いておき、その中からランダムにつぶやきます。
open()でテキストを読み込んでいますが、\nを\\nと読み込んでしまうので、replace()で置き換えています。

画像付きでつぶやけるようにしたいので、いろいろ自分流にアップグレードできたら報告します。
でもとりあえず今はつかれた……