裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

2次元配列の文字列を数値に置換

2020年12月16日 | ブログラミング

プログラマーの卵向け(?)か,「2次元配列の文字列を数値に置換」という記事があった

> 1行目は2行目移行の標準入力の繰り返し回数。
> で、2行目移行の数値は2次元配列に格納したい。

3
1 2
3 4
5 6

結果として [[1, 2], [3, 4], [5, 6]] を期待する。

例によって(?)二次元配列と書いてあるが,厳密にいえば,二重リストだね。

これに対して,以下のようなプログラムが示されている。

arr = []
n = int(input())
for i in range(n):
    arr.append(input().split())

for i in range(len(arr)):
    for j in range(len(arr[i])):
        arr[i][j] = int(arr[i][j])

最後の 3 行を以下の 1 行で置き換えることもできるよ

arr = [[int(x) for x in y] for y in arr]

とも書いてある。

とても,お手本とするプログラムとはいえない。しかも,そのページはなんか IT 関連の会社が作成しているようなんだけど。

========

短いプログラムは,それだけで読みやすい。わかりやすい。

ということで,以下のようなプログラムを書く。

n = int(input())
arr = [0] * n
for i in range(n):
    arr[i] = list(map(int, input().split()))

だけでよい。

print(arr) # [[1, 2], [3, 4], [5, 6]]

列数が大きくなってもプログラムには何の修正も必要ない

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

プログラミングの歴史 -- 4(R と C++)

2020年12月16日 | ブログラミング

Python と違って,R はずいぶん前から(2013年には既に)全てのソースは precompile (バイトコンパイル)されているのでコンパイラとは縁がなくなっている。(今でも,compiler パッケージについての古いブログ記事がいくつか残っているが,シーラカンス同然)。

代わって,R から C++ で書いた関数を呼び出す機能(Rcpp パッケージ)が便利である。

このブログでも,ずいぶん前(2012年)に Rcpp に関する記事を書いたが,その頃と比べてわかりやすさ,利用しやすさの点で格段の進歩があったのでちょっとまとめておく。

##### C++

戻り値のない関数     calcf.cpp

以下のような内容のファイル calcf.cpp を作る

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]

// ここまでがおまじない
// これ以降に C++ で書いた関数プログラム

void calcf() {
    double x, y;
    double dt;
    int i;
    //NumericVector ans(2);
    dt = 0.00000001;
    x = 1;
    y = 0;
    for (i = 0; i < 628318531; i++) {
        x = x - y * dt;
        y = y + x * dt;
    }
    printf("(x, y) = (%.15lg, %.15lg)\n", x, y);
}

R で calcf.cpp ファイルのコンパイルと実行

> system.time({
+     library(Rcpp) # ライブラリ
+     sourceCpp("calcf.cpp") # コンパイル 1 回
+     calcf() # 実行 いつでも,何度でも
+ })
(x, y) = (0.999999999999772, 2.8203875166645e-09)
   ユーザ   システム       経過  
     3.168      0.011      3.183 

コンパイルも含めた時間で 3 秒というのは,PyPy と同じくらいの速度ということになる(C プログラムと比べても速い)。

===================

戻り値のある関数     calcf2.cpp

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]

NumericVector calcf2() {
    double x, y, dt;
    int i;
    NumericVector ans(2);
    dt = 0.00000001;
    x = 1;
    y = 0;
    for (i = 0; i < 628318531; i++) {
        x = x - y * dt;
        y = y + x * dt;
    }
    ans[0] = x;
    ans[1] = y;
    return ans;
}

R で calcf2.cpp ファイルのコンパイルと実行

> system.time({
+     library(Rcpp)
+     sourceCpp("calcf2.cpp")
+     ans = calcf2()
+     cat(sprintf("(x, y) = (%.15g, %.15g)\n", ans[1], ans[2]))
+ })
(x, y) = (0.999999999999772, 2.8203875166645e-09)
   ユーザ   システム       経過 
     3.203      0.011      3.217 

実行時間は戻り値を返さない場合と同じである。

=====

本件は,プログラミングの歴史(私にとって)の C++ の 1 ページ でもある。

さて,残るプログラミング言語も少なくなってきたが,VB(Visual Basic) だけは,書きたくない。あんなもの,悪夢だ。地獄だ。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Python の JIT compile -- PyPy

2020年12月16日 | ブログラミング

前の記事で,Cpython については触れないと書いた。特に意味はなくて,Cpython ってはじめて読んだからに過ぎない。

プログラミングの歴史 -- 3(R と Python の速度比較)

この記事では,前から知ってはいた JIT コンパイラ(just in time compiler)の PyPy について書いてみよう。

自機にはインストールしていなかったが何回か使ったことはあった。
今回,インストールして,使ってみたと言うことだ。

インストール法は何通りもあるようだが,
pypy3とpipのインストール Ubuntu 18.04 · GitHub
に従った。問題なくインストールできた。
まあ,上手くインストールできなくても,根気よく動くようになるまで色々手を尽くすということだ。

使い方は簡単 コマンドラインで pypy3 foo.py と指定するだけ。

以下のような calcf.py ソースを

def calcf():
 dt = 0.00000001
 x = 1
 y = 0
 for i in range(628318531):
     x -= y * dt
     y += x * dt
 print('(x, y) = ({0:.15g}, {1:.15g})\n'.format(x, y))

calcf()

実行してみる。

$ time pypy3 calcf.py
(x, y) = (0.999999999999772, 2.8203875166645e-09)

2.935u 0.018s 0:02.95 99.6% 0+0k 0+0io 0pf+0w

驚きの 3 秒!!
FORTRAN, C, Java, JavaScript などのコンパイラ言語はコンパイルと実行を合わせた時間が 5 秒程度であったのに比べても,速い。

なお,前の記事で,「関数にしないと遅い」と書いたが,以下のような関数化されていない以下の calc2.py のような場合も

dt = 0.00000001
x = 1
y = 0
for i in range(628318531):
    x -= y * dt
    y += x * dt
print('(x, y) = ({0:.15g}, {1:.15g})\n'.format(x, y))

実行してみると,

$ time pypy3 calcf2.py
(x, y) = (0.999999999999772, 2.8203875166645e-09)

5.134u 0.021s 0:05.16 99.8% 0+0k 0+0io 0pf+0w

確かに,関数化しないソースファイルのコンパイル結果よりは遅いけど,他のコンパイラ言語と同じ程度の速度である。この場合も問題なく速いといってよい。

いくつか制約はあるものの,PyPy を使わないという選択はない...のかも知れない。

 

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Python 嫌いだけど,こんな Python プログラムはいやだ(その7)

2020年12月16日 | Python

きりがないので,これで止める。

R でもそうだけど,for を使ったところは,使わないように書き換えるのが吉。

単に行数が短くなると言うことではなく,その方が効率的だから。

Java や JavaScript, C, C++ 古くは FORTRAN などの経験者はどうしても自分の経験から for ループを使ったコードを,「安易に」書いてしまう。

R や Python はそれを実現する,1つの関数を持っている。それを使うべし。

for を多用している Python プログラムは,「参考にしてはならない!!」

旧人類の真似をしてるうちは,新人類にはなれませんっ!

ベテランは,自己の経験に基づくのではなく,Python ではどのように書くのが「普通か」ということを探索すべし。自分ほど経験豊富なプログラマ(エッヘン)は何でもプログラムできるからと言って,旧来の for ループでなんでもかんでも書くというのは,止めるべし。

import math
data = [66, 59, 62, 64, 63,
        68, 65, 59, 68, 64,
        65, 51, 67, 64, 83,
        59, 61, 62, 57, 72,
        65, 64, 54, 60, 53,
        65, 67, 60, 53, 79,
        74, 53, 61, 68, 75,
        50, 57, 55, 66, 56,
        55, 61, 70, 71, 49,
        69, 70, 80, 73, 72]

n = len(data)       #   The number of scores
print("n = %d" % n)

# print("Data...")
# i = 1
# for x in data:
#     print("%5d:"%i + "  %f"%x)
#     i+=1

# sum = 0.0
# for x in data:
#    sum += x
# mean = sum / n
mean = sum(data) / n
print("Mean = %g" % mean)
#ssum = 0.0
#for x in data:
#    ssum += sqr(x - mean)
# var = ssum / n
var = sum((x - mean)**2 for x in data) / n
sd = math.sqrt(var)
# print("Variance = %f"%var + "     sd = %f"%sd)
print("Variance = %g     sd = %g" % (var, sd))
# uvar = ssum / (n - 1.0)
uvar = var * n / (n - 1)
sd_uvar = math.sqrt(uvar)
# print("Unbiased Var. = %f"%uvar + "     sd(uvar) = %f"%sd_uvar)
print("Unbiased Var. = %g     sd(uvar) = %g" % (uvar, sd_uvar))

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PVアクセスランキング にほんブログ村

PVアクセスランキング にほんブログ村