粒沢らぼ。

当ブログでは現役生命科学系の研究者が、気になった論文を紹介したり、考えていることを共有したりしています。可能な限り意識を”低く”がモットー。たまに経済ネタとかも。
書いてる人:粒沢ツナ彦。本業は某バイオベンチャーで研究者をやっています。本名ではないです。
博士号(生命科学系)。時々演劇の脚本家、コント作家、YouTube動画編集者。アンチ竹中エバンジェリスト、ニワカ竹中ヘイゾロジスト。
Twitterアカウント:@TsubusawaBio←お仕事などの依頼もお気軽にこちらへ。

タグ:プログラミング

055537
研究開発。(研究要素強め)

バイオ系の研究の進みってどうしても遅く感じちゃうよな。
ソフトウェアとかプログラミングだと人間が頑張れば早くなるからもっと早いんだろうかなあ。


経験上、研究的な部分のことはがんばってもそれほどはやくならないんだよな。

人によるかもしれないけど、こと自分の場合はそうでしたね。

土日潰して朝から晩までやっても、進まないときは本当に進まないもんな。


もう少し具体的にいうと、何かトラブルが起きたときに、「こうすれば解決するはず」と思って改善するんだけど、その改善を一回まわすのに1,2ヶ月かそれ以上かかったりするし、その結果特に改善しないことも多い。

そんな感じだから、数ヶ月単位は平気で飛んでいくんだよな。


状況的に、確実に段階踏んでやっていけば終わるのなら、早くなることもある。

論文の投稿直前とかで、やることがはっきり決まってるとかなら、頑張れば早くなることもあるんだけどね。


がんばってもそれほどは早くならないということが、特に普段プログラミングとかを触っている人には理解されにくい印象がある。

なぜそんなにかかるのかという顔をされてしまうけど。なかなかね。
こっちだってプログラミングの難しさの深いところはわからんし、お互い様っすな。 


人手も足りないし人手を増やすだけのお金もないしな。

まあ解決策は特になくて、やれることをヤッテイキするしかないんですね。



character_program_smart


データ解析に使うちょっとしたプログラムは自力でpythonのコードとかを適当に書くことが多いのだが。

コード書いてると、for文とか使って泥臭く書こうと思えば書けるけど、できればカッコいい一行で書けるコードがないか探したりしてしまうよね。

 

特に、配列データの中身に繰り返し同じ処理をしたい場合などによくありがちだけど。

なんか、list comprehensionの構文使ったり、pandasapply lambdaの構文を使って、なるべく一行で繰り返し処理を終わらせられないか無駄に頑張ってしまう。

for文だと2行以上になるからなんかダサいなと思ってしまう。

 

無駄というのは、どうせ人に見せるわけでもないしプログラマ目指しているわけでもないんだから、そこまでプログラムの見た目をキレイに整えて何の意味があるのか、時々わからなくなるのだ。

別にfor文使って数行になってしまっても、実質的には特に問題はない

また、それほど大量のデータを扱っているわけでもないので、計算時間の最適化が多少ぬるくても実質的に大した影響がないことが多い。

 

だから、本来は「コードなんて動けばいいんだよー

と思うものの、Google検索でなにやらやりたいことがワンライナー(一行)でサラッと書かれていたりすると、「かっけえなこれ!」となったりする、

 

かっけえはかっけえんだけど、そういうコードってなにやってるかよくわからないことも多い

[なんとか for かんとか in うんたら for かんたら]

みたいになっていて、確かに望み通りの動きはするんだろうけど、解読することすら容易ではなく、粒沢の知識量だと平気で20-30分かかってしまったりする。

場合によってはそれだけ時間かけても結局よくわからなかったりね。

確かに一行でサラッとかけると美しいけど、やりすぎると書く方も読む方も(この場合両方とも自分だが)よほど慣れてないかぎり面倒くさいし全体的な効率は下がっている気がするよね。

 

昨日も無駄に色々調べてたけど、どこかのフォーラム

pythonでは、コードを短くすることや計算時間をコンマ何秒短くすることよりも、あとで読みやすくわかりやすいコードを書く方が圧倒的に大事

みたいなこと言うてる人がいて、「せやな、ほんまそれ」ってなったね。


スクリーンショット 2020-11-06 12.56.04 

今原文確認したら、

“To anyone who is writing Python code, you really should think twice before sacrificing readability and commonly-agreed Python conventions just to squeeze out a few more nanoseconds per loop.” (sleblanc)

「コードを短くする必要がない」とは言ってなかったけどまあいいや。

 

 

だいたいコード書いてて無駄に残業する羽目になるの、そう言う無駄なコダワリが原因なのよね。

マニアックな構文の学習をしても大して俺の人生に影響なさそうだし、それならその時間を他のことに使った方が有意義な可能性絶対高いよな。

 

と、夜中までpythonのフォーラム眺めてて思ったのであった。

初心者氏にプログラミングを教えて、[“sample1”, “sample2”, “sample3”, …, “sample99”]という連番のリストを作れるようにしようという目論見だったが、前回なんとかそれらしいプログラムの原型ができるところまできた。

(現実では、ここまでで2週間くらいかかっている) 

 

「昨日教えたところまでで、以下のようなコードになっていたよね。

 

list_nums = ["1", "2", "3", "4"]

list_result = ["] * 4

for i in range(4):

           list_result[i] = "sample" + list_nums[i]

 

これで、1-4までの連番のリストを作ることが一応可能だけど、これを100くらいまで拡張したい。


1-99まで連番を手で打つのは現実的ではないよね。
1から99までの数列を作るには、range(1,100)のように書くのが便利1から始まって、100の一つ下の数字までの整数を作ることができる。

そのままだとrange型という独特の型なんだけど、これをlist() で処理することで、リストに変換することもできる」

リストの長さ(要素の数)はlen()関数で取得することができる、自分で数を数えたり覚えておく必要がなくなる」

”+”を使った文字列と数字の連結には、まず数字から文字列への型変換が必要なことを思い出して欲しい」

ここまでヒントを言ったら、次のようなコードが提出された。

 

list_result[i] = "sample" + str(list_nums[i])

list_nums = list(range(1,100))

list_result = [""] * len(list_nums)

for i in range(len(list_nums)):

           list_result[i] =  "sample" + str(list_nums[i])

 

今度こそ正解と言っていいだろう。

ここまで長かったが、ようやくシンプルなプログラムを一応の完成形にまで持っていくことができた。

初心者氏もだいぶ慣れてきたようだ。少なくとも当初の五里霧中の状態からはかなり進歩した。

一方で、やっぱりプログラミングって向き不向きがかなりあるなあということを感じたのも事実だ。

普通にプログラミングをガシガシ進められる人は、それだけでもかなりすごいと思わされる。

人によっては当たり前にこなしているだろうけど、たまには誇ってもいいんじゃないかな。

 

なお、作成した連番リストの利用方法であるが、実際には例えばテキストやexcelファイルなどに結果のリストを書き出してもらうことなどを検討している。

そこら辺は現実的には続きがあるけど、このブログとしては一旦ここまでということにしよう。

昨日説明した内容で、そろそろ[sample1, sample2, sample3, …, sample99]のように連番を作るリストが書けるようになったんじゃないかと思ったのだが、意外と難しいようだ。

どうやら繰り返し処理でリストを次々更新していくというのが難しいらしい。

 

「例えばリストlist_ex = [“a”, “b”, “c”, “d”] とあったとします。

リストの2番目の値”b”を取り出すにはどうしたら良いか?」

と聞くと、多少考える時間はあるが、

list_ex[1]

という答えが一応返ってくる。

2番目の値を参照するためにはリスト名の後に[1]をくっつける(0始まりだから)、というのは一応理解してもらえたようだ。

まぁ答えが返ってくるまでの反応速度に課題はあるけれども、そこは仕方ない。

 

「じゃあ、

list_nums = ["1", "2", "3", "4"]

list_result = [""] * 4

があったときに、"sample"という文字列をくっつけて"sample1", "sample2", … としたものをlist_resultに入れていくコードをfor文を使って書いてください」

と指示してみる。
だがここが難しいらしい。

 

for i in list_nums:

           print("sample" + i)

と書いて行き詰まっていたりする。まあ惜しいっちゃ惜しい。
この書き方だと、繰り返し1回目の i は1、2回目の i は 2、と i がリストの要素そのものになる形で、やりたいことに近いことは間違いない。 

だが、これだとlist_resultsに値を入れるときに順位を指定できないから、惜しいんだけどあまり実用性がない

 

こちらの用意した正解は、

for i in range(4):

           list_result[i] = "sample" + list_nums[i]

みたいな感じを期待しているのだが、もしかすると初心者には盲点なのかもしれない。

 

for i in list_numsの場合は、繰り返し回数の増加で、ilist_numsの中の1番目、2番目、と動いていくから、ある意味わかりやすい。

一方、繰り返し回数ごとに1ずつ増加していく i を使って、リストの中の順位を指定できる、という発想は、なかなか難しい場合があるようだ。

確かに、後者のやり方は抽象度が一段上がっており、慣れてないと発想できないものかもしれない。

 

本当は、この繰り返し最中に i で順位指定を行うやり方に自力で気づいて欲しかったのだが、仕方ない。

そういう形ということで無理やり覚えて慣れてもらうしかないか。

 

「ということで、こちらの期待した答えは list_nums[i] や list_result[i] のように、[]のなかにiを入れることによってリスト内の参照位置をどんどん動かすことができるということですね。

非常に頻出する形なので、是非覚えてください」

非常に頻出する形なので覚えてくださいっていうのは、麻雀の初心者向け解説本で良くみるフレーズなので、そこからパクったのは秘密だ。

 

というわけで、なんとか、文字列+連番を作るプログラムの原型を作ることができるようになったと言える。

 

あとはちょっとした改善をすることで、99までの連番を一気に作ることが可能だ。

ゴールはもうすぐだ。

 

もうちょっとだけ、続く。

昨日のつづきで、ガチのプログラミングをやったことない人にプログラミングを仕込もうとしている。


「さて、じゃあ昨日言いかけた、固定文字列に連番を振るプログラムを書いて欲しいんだけど。

[sample1sample2, ..., sample99]

みたいなリストが作れるようになってほしい。

for文を使った繰り返しを利用することでできる、というのは察しがつくと思う。」

察しがつかないかもしれないが、とりあえずそういうことにしないと話が進まない。

 

「それで、今から”sample”という文字列と”99”みたいな文字列を連結してもらいたいと思っている。

文字列の連結は"+"を使えばよくて、

newstring = “sample” + “99

みたいな感じで+で書いてもらえれば、連結した文字列がnewstringという変数に入るっていうわけ。」

これは、簡単かな?すぐ通じたような気がする。

 

「じゃあ、これを繰り返し処理することで、連番を振るプログラムはできそうかな?」

ちょっと考えてみてくれ。何?できた?早いな、どれどれ。

 

print(“sample” + “1”)

print(“sample” + “2”)

print(“sample” + “3”)

 

オーケー、やりたいことはわかった。

とりあえず、for文の使い方以前に、まずprint厨状態を脱する必要がある。

printで出力してもそのあとでその値を使うことができないから、まずは何か空のリストを作ってそこに値を格納していくことを教えないと。

それと、よく考えたら数字から文字列への型の変換を教えないと、こちらがやりたい動作にならないな。

といっても、とりあえずは一番簡単なstr()を教えればいいか。

 

「えーと、まずヒントを出すと、print()で書き出したものってそのあとで使えないんですよね。

このあとで作った連番の文字列を使って何かに使ったり印刷したりしたいと考えているので、まずは処理をしたあとの値を入れておく“置き場”を用意してあげないといけないんだよね。

ここ重要なので、常に置き場を用意するって思っておいてね。

で、今仮に99個の連番を作りたいとすると、用意したい置き場の長さは99と言うわけだ。

なので、まぁ初期値は何でもいいんだけど、099個連続したリストをとりあえず作っておくことにする。

これは、"*"を使って以下のようにすることで可能。

newlist = [0] * 99

こんな感じね。」

 

ん、何か意見がある?なになに。

自分でググったところによると、リストに要素を追加するのには、リスト.append(要素を使うやり方もあるって?

そっちの方がわかりやすいからそっち使いたいと。

 

んー、まあ確かに、それでもいいんだけど。

経験上、append()を使ってリストの長さをどんどん伸ばしていくと処理が遅くなるんだよね。

まぁ今やろうとしている簡単なプログラムぐらいだったらどっちでもいいんだけど。

そこは俺のこだわりで、appendはあまり使いたくないなあ。

 

append使ってもいいんだけど、そっちだと遅いから、先にリストの長さだけ作っちゃう方式の方がおすすめです。慣れてくれると嬉しいです。」

 

すまんけどよろしこ。

 

「あと、さっき言うのを忘れたんだけど、プログラミングでは基本的に変数にと言うものがあって、それによって処理を実行できるかできないかが決まっているのです。

例えばさっきの”+”の連結は、文字列と文字列には使えるけど、文字列と言う型と数値という型には使えない。

だから、”sample”という文字列と、99みたいな数字を連結しようと思ったら、99という数字を”99”という文字列に変換してあげないといけないわけ。

これにはいくつかやり方があるけど、とりあえず1番わかりやすいのがstr()を使う方法かな。

str(数値)で、数値が文字列に変換される。

 

どうだろう、これで文字列に連番をつけるプログラムが書けそうかな?」

 

そろそろこれでいけるんじゃないか?これはかなり丁寧に説明した感があるぞ?
 

と思ったんだけど、初心者氏、長考の末ギブアップしてしまわれた! 

うーん、まだダメか。何が足りないんだろう。

 

続く→「繰り返し中のリスト内の順位の指定方法について教えた

このページのトップヘ