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

30代無職のプログラミング入門

暇つぶしにプログラミングを独学してみる

モンテカルロ法で円周率を求める

コードはRです。解説はできないので端折りますが、『高校数学+α』のpp.518-9の説明が分かりやすかったです。著者のサイトで読めます→ http://tad311.xsrv.jp/hsmath/

library(tidyverse)

N = 10000

df <- tibble(
  x = runif(N, -1, 1),
  y = runif(N, -1, 1),
  inside =  (x**2 + y**2) <= 1
)

pi_monte = sum(inside) * 4/N
error = abs((pi_monte - pi)/pi) * 100

結果:

> print(pi_monte)
[1] 3.1296
> print(error)
[1] 0.381738

3.1296なので、円周率っぽい数字にはなってる。誤差は0.381738%。

ggplot2で作画。

ggplot(data = df, mapping = aes(x = x, y = y)) +
  geom_point(mapping = aes(color=inside)) +
  coord_fixed() # 散布図のサイズを正方形に

f:id:unEmployed:20170418212314p:plain

Python、Selenium Web Driver を使ってブログ村の「ping代理送信」ボタンを押す

from selenium import webdriver

# Chromeを立ち上げる。
browser = webdriver.Chrome('Chromedriverへのpath')

# ブログ村のログインページに移動する
browser.get('https://mypage.blogmura.com/login')

# IDとパスワードのクラス属性は 'field' なので、それを取得する。
textboxes = browser.find_elements_by_class_name('field')
textbox_id = textboxes[0] # [0]は、取得した要素の最初のものがIDのテキストボックスだから。
textbox_pass = textboxes[1] # [1]は、取得した要素の2番目のものがパスワードのテキストボックスだから。

# ID・パスワードのテキストボックスに、ID・パスワードを入力する。
textbox_id.send_keys('ID')
textbox_pass.send_keys('Pass')

# ログインボタンを押す
botton = browser.find_elements_by_class_name('botton')
botton = botton[0]
botton.click()

# ログイン後の画面の「記事反映/Ping送信」ページに移動する
ping = browser.find_elements_by_class_name('nb')
ping = ping[1] 
ping.click()

# 「ping代理送信」ボタンを押す
submit = browser.find_elements_by_class_name('submit')
submit = submit[1] 
submit.click()

上記を実行すると、

f:id:unEmployed:20170417200458p:plain

となる。

しかし「ブログ村」とか、なんて私はロートルなのだろう。

RStudioから利用するPythonを変更する

RStudio(の「R Notebook」)ってPythonのコードも実行できるんだ、と興奮したのもつかの間、それが参照するPythonが2系だった。

> system("python --version")
Python 2.7.10

これを、AnacondaのPython(3系)に変更する。

support.rstudio.com

上記のリンク先を参考に、以下をRStudioのコンソールで実行する。

Sys.setenv(PATH = paste("/home/username/anaconda/bin", Sys.getenv("PATH"),sep=":"))

(「”/home/username/anaconda/bin"」の部分は適宜書き換えてください。)

すると、

> system("python --version")
Python 3.5.2 :: Anaconda custom (x86_64)

名字ランキングの1〜1000までをプロット

この前は200までだったのを、1000までデータをスクレイピングし、プロットしてみた。コードは代わり映えがしないので省略。

f:id:unEmployed:20170214200700p:plain

対数軸にすると:

f:id:unEmployed:20170214200704p:plain

名字ランキングのスクレイピング、プロット等

名字のランキングと、Googleのヒット数に相関とかあるのだろうか、と思って調べてみた。

まず、名字のランキングをスクレイピングで取得する。

サイトはここ。

myoji-yurai.net

上位200位の名字のデータを取得する(上位200なのは、最初のページが200までというだけの理由)。

import requests, bs4

res = requests.get('https://myoji-yurai.net/prefectureRanking.htm')
soup = bs4.BeautifulSoup(res.text, 'lxml')

a = soup.find_all("tr", class_="odd")

# ランキング部だけを選択(かなりアド・ホックな仕方)
b = [i for i in a][16:216]

ranking = []
myouji = []
num = []

count = 0
while count < 200:
    x = [i.string for i in b[count]]
    ranking.append(x[1])
    myouji.append(x[3])
    num.append(x[5])
    count += 1

# ランキングの数字の後に付いている「位」を除去
ranking_2 = []
for i in ranking:
    ranking_2.append(i[:-1])

# 人口の数字の前の「およそ」を除去。コンマを除去。数値に変換
num_2 = []
for i in num:
    num_2.append(int(i[3:-1].replace(',','')))

上記で作成したリストを、pandas のDataFrameにする。

import pandas as pd
df = pd.DataFrame({'ranking':ranking_2, 'myouji':myouji, 'population':num_2})
df = df.set_index('ranking')

こんな感じになる。

df[:5]

f:id:unEmployed:20170210201022p:plain

次は、名字ごとのGoogleのヒット件数を取得する。これは、前回の記事のコードとだいたい同じ。

def google_results(word_list):
    import requests, bs4
    
    url = 'https://www.google.co.jp/search?q='
    results = []
    
    for i in word_list:
        res = requests.get(url + i)
        soup = bs4.BeautifulSoup(res.text, 'lxml')
        
        # ソースの中の、id="resultStats"の部分がヒット件数なのでそこを抜き出す
        text = soup.find(id="resultStats").getText()
        
        # 数字部分だけ抜き出して、コンマを除去
        results.append(int(text[2:-2].replace(',','')))
        print(i)
    return results
results = google_results(myouji)

データフレームに追加。

df['google_results'] = results

df[:5]

f:id:unEmployed:20170210201402p:plain

取得したデータをプロットしてみる。まずは名字の人口。

import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns

df.population.plot()

f:id:unEmployed:20170210201530p:plain

次は、Googleのヒット件数。

df.google_results.plot()

f:id:unEmployed:20170210201623p:plain

相関なんて全然なかった。Googleのヒット件数がスパイクしているもの(4億件以上)を拾ってみると、こんな感じ。

df[df.google_results > 400000000]

f:id:unEmployed:20170210201918p:plain

林、森、原、東、南。一文字の方が、検索の限定が弱い分、ヒット件数は増えるわなあ…。こんな結果になるとは、調べてみるまで思いもしなかった。ぼんやりと相関するんじゃないかとだけ思ってたので。(ちなみに、上位200の名字のうち他に漢字1文字なのは「関」「辻」「堀」)。

Googleで1〜1000の数字を検索し、そのヒット数をグラフ化する

def google_results(num):
    
    import requests, bs4
    
    url = 'https://www.google.co.jp/search?q='
    results = []
    
    while num > 0:
        res = requests.get(url + str(num))
        soup = bs4.BeautifulSoup(res.text, 'lxml')
        
        # ソースの中の、id="resultStats"の部分がヒット件数なのでそこを抜き出す
        text = soup.find(id="resultStats").getText()
        
        # 数字部分だけ抜き出して、コンマを除去
        results.append(int(text[2:-2].replace(',','')))
        
        num -= 1
        
    # 昇順に
    results.reverse()
    
    return results
results = google_results(1000)

グラフ化する。

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

plt.plot(results,".",markersize=5)

f:id:unEmployed:20170206212333p:plain

対数軸にすると

plt.plot(results,".",markersize=5)
plt.yscale('log')

f:id:unEmployed:20170206212354p:plain

感想

  • 結果の取得に時間がかかりすぎ。threading?とかをすると早いようだけれど、解説を読んでも意味がわからなかった。

  • あと、検索結果の取得は、1〜3秒くらいの間隔でランダムに取得すべきだったんだろう…とあとで気づいた。

参考

https://automatetheboringstuff.com/chapter11/

CheckiOを始めた

checkio.org

簡単な問題を解かないと、そもそもアカウントも作れない、とか書いてあるのがあったけど、普通に何もせずアカウントは作れた。以前、paizaで1問目から解けずに挫折したので、戦々恐々としてたのだけど。

1問だけ、解いた。リストのうちで、ユニークな(重複のない)要素を除く、という問題。

最初、こんなふうに書いた。

def checkio(data):
    for i in data:
        if data.count(i) == 1:
            data.remove(i)
    return data

で、その後それを、リスト内包表記に書きなおして、提出した。

def checkio(data):
    return [i for i in data if not data.count(i) == 1]

問題に正解すると、他の人の書いたコードが読める。それがとても勉強になるっぽい。

広告を非表示にする