雑記 - 静かなる名辞
pythonとプログラミングのこと
2020-05-07T20:42:34+09:00
hayataka2049
Hatena::Blog
hatenablog://blog/10328537792367869878
ブログで直帰率が高いことは問題ではない。満足して帰っていれば
hatenablog://entry/17680117127219175963
2019-07-18T05:22:10+09:00
2019-08-31T22:22:16+09:00 はじめに ブログをある程度真面目に運営している人は、googleアナリティクスなんかを入れて色々な指標を日々確認していると思います。指標が悪いと、なんか問題があるのではないかと思いがちです。 当ブログは直帰率が高いです。8割以上といったところです。でも、気にしていません。どうして気にしないのか? 気にする意味がないからです。 いや、真面目な話、気にしていた時期もあったといえばあったんですよ。レイアウトの改善で1%くらい下がったかな? ということをやっていた時期もありましたが、最近はきっぱり諦めました。それに伴って、他の要因*1でレイアウトをいじっているので、直帰率もきもち程度上昇気味です。振れ…
<div class="section">
<h3>はじめに</h3>
<p> ブログをある程度真面目に運営している人は、googleアナリティクスなんかを入れて色々な指標を日々確認していると思います。指標が悪いと、なんか問題があるのではないかと思いがちです。</p><p> 当ブログは直帰率が高いです。8割以上といったところです。でも、気にしていません。どうして気にしないのか? 気にする意味がないからです。</p><p> いや、真面目な話、気にしていた時期もあったといえばあったんですよ。レイアウトの改善で1%くらい下がったかな? ということをやっていた時期もありましたが、最近はきっぱり諦めました。それに伴って、他の要因<a href="#f-7e9fa367" name="fn-7e9fa367" title="ユーザビリティだったり広告最適化だったり">*1</a>でレイアウトをいじっているので、直帰率もきもち程度上昇気味です。振れ幅は数%ですけどね。</p>
</div>
<div class="section">
<h3>どうして直帰率が高いんだ!</h3>
<p> <b>A:技術ブログだからさ</b></p><p> あー、えーっと、この記事は「プログラミングの記事を書くかたわら、気晴らしで書いている運営報告系雑記記事」です。なので、検索から来た人の多くにとって、自分のブログには直接は当てはまらないと思います。ごめん。</p><p> 必要だと思うので技術ブログというブログの形態について説明しておくと、プログラミングをやる上でのお悩み解決に役立つような記事を中心に上げるブログです(勝手に定義)。「このコマンドの使い方がわからないなー」とか「書いて動かしたらこんなエラーが出た」とか、そんな動機でググった人がやってくるブログです。</p><p> 薄々感づいてきた人もいるかもしれませんが、当ブログにやってくる人のほとんどは別に当ブログを読みたい訳ではなくて、暇つぶしに読むブログを探しているとかでもなくて、単に自分の抱えている問題を解決したいだけです。私のブログが解決策を示せていれば、満足して直帰します。残念ながら解決につながらなかった場合も、直帰して他のサイトを読みに行きます。</p><p> それでも1割くらいの人は直帰しないで回遊してくれていますが、それは3パターンくらいあって、</p>
<ol>
<li>記事中に貼った内部リンク(関連する内容の記事へのリンク)を見てくれる</li>
<li>仕事中とかにあまりやる気がない状態でやってきて、仕事をしたくないので漫然と最新記事とか記事下の関連コンテツを回遊している(失礼)</li>
<li>「おぉ~このブログいろいろ書いてあるぅ~」と思ってくれてアーカイブやカテゴリページを総なめしている。ログを見ると、そんな感じで回遊している人が毎日1~2人はいそうな気がします。大変ありがたいです</li>
</ol><p> のいずれかだと思います。まあ、どれにしてもそんなに増えることは期待できない訳です。<br />
(せいぜい記事中の内部リンクを増やすくらい。でも内部リンクを貼る必要のない記事に貼ってもしょうがないのだし)</p><p> 少し話が脱線しましたが、「知りたいことについてググる」「問題の解決策を探す」といったような、いわゆる『調べごと系』の検索ニーズに応えるというのは、技術ブログに限らず多くのブロガーの方が実践している方向性だと思います。すると何が起こるか? ユーザは目的を達成してもしなくても帰っていきます。なので、直帰率は自ずと高くなる、ということです。</p>
</div>
<div class="section">
<h3>どのみち直帰する?</h3>
<p> もう少し上の現象について掘り下げて考えてみましょう。同じことを二回書きますが、整理すると以下の図式です。</p>
<ul>
<li>ユーザが満足した(検索の目的を達成した)</li>
</ul><p> それ以上の用はないので直帰する。</p>
<ul>
<li>ユーザが不満足だった(検索の目的を達成しなかった)</li>
</ul><p> このブログには見切りをつけて他に行く。</p><p> この状況のユーザに対して、直帰されないためにブログ運営者から打てる手はほとんどありません。いくらコンテンツの質を上げようが、内部リンクを工夫しようが原理的にほぼ無理です。最初から「知りたいことが載っているページを探して、読んだら直帰する」つもりで来ている訳ですから。</p><p> それでもウザいくらいに記事中に内部リンクを貼るとかすれば統計的に何%かのユーザは「釣られて」くれるかもしれませんが、そういうのは回遊の押し売りとでもいうべきもので、ブログの運営の仕方として望ましいものではないと思います。</p><p> たとえばランディングページと大して関係のない記事に回遊させたとして、「なんで俺はこんなの読まされたんだろう」と当然思われるでしょう。そういう事態は避けるべきです。ただ、このあたりの塩梅はケースバイケースで、結果的にユーザに許容されるであろうという確信が持てれば「釣って」もいいと思います。「この記事を読みに来た人なら、絶対にこっちの記事も読んだ方が良い」みたいなのは適切な説明をつけてリンクしておくと良いでしょう。でも、そういう「釣って良い」ケースは限られるので、実際問題として個別の記事でそういう処置がとれるものはあったとしても、全体の直帰率に及ぼす影響はさほど大きくないでしょう。</p><p> 結論を言うと、「調べごと」系にフォーカスしたブログでは原理的に直帰率は改善できないはずです。高いなら高いままと考えた方が良いです。</p>
</div>
<div class="section">
<h3>だから、直帰率のこととか気にしなくていいと思うよ</h3>
<p> 実際問題として、直帰率が低いとなにか問題があるのでしょうか?</p><p> まあ、直帰率の1%の低下は大雑把にはPVを1%増やすかもしれませんが、雀の涙です。そして直帰率を1%下げるというのはけっこうたいへんです。これでPVを稼ごうと考えるより、先にやるべきことがたくさんあるでしょう<a href="#f-a2518bbc" name="fn-a2518bbc" title="数千記事、100万PVクラスのブログだと事情が違う可能性はあります。でも、そんな人は読んでないだろうし">*2</a>。</p><p> 直帰率が高いとgoogleの評価が~という話もちらほら見かけますが、眉唾物だと思っています。少なくとも、公式にそれを肯定する情報はありません。</p><p> 参考:<br />
<a href="https://seopack.jp/seoblog/20160330-bnc-rate-wont-affect/">サイト直帰率が高くてもGoogle順位には「影響ない」</a><br />
<a href="https://promonista.com/session_time/">ページの滞在時間はSEO順位に影響する?コンテンツの滞在時間と直帰率を改善する方法 | プロモニスタ</a></p><p> だいいち、検索からサイトに飛んだ人をトラッキングする手段は、普通に考えたらないのではないでしょうか。googleアナリティクス(googleのアクセス解析ツール)を入れているサイトなら結果的には情報がgoogleに送信されますし、もしかしたらchromeになにか仕込まれているという可能性も皆無ではありませんが、そういったものを検索の評価に使うというのは現実的ではないように思います。</p><p> あとは、ユーザ満足度やコンバージョンに結びつける話もありますが、ユーザ満足度に関しては上述の通り「満足しようがしまいが結果的に直帰する」ユーザがほとんどである以上、直帰率では測れません。コンバージョンも普通のブロガーには関係ないですよね。</p><p> なので、直帰率は気にしなくて良いということです。</p>
</div>
<div class="section">
<h3>ユーザ満足度はgoogleアナリティクスでは測れない</h3>
<p> さて、ここまで読んできた人の中には、直帰率はユーザ満足度の指標なので改善するべき、という巷で喧伝されている説明を信じていたのに、という人もいるでしょう。もう直帰率はあてにならないと知ってしまった訳で、困りますよね。</p><p> 繰り返しになりますが、直帰率はユーザ満足度の指標ではありません。私の感覚では、満足した結果として直帰する、というユーザはかなりの割合を占めます。なので、他の方法で考えるしかありません。</p><p> 真っ先に思い浮かぶのは、平均ページ滞在時間でしょうか。でも、あれは直帰したユーザについては計測できない(というか0になる)という欠点を抱えています。駄目駄目ですね。それに、滞在時間が長ければ満足しているという発想にも無理があるでしょう。読みづらくて時間がかかっているのかもしれないし、別ウィンドウやタブで開いたまま放ったらかして他のページを見ている可能性も十分にあります。</p><p> 参考:<br />
<a href="https://webtan.impress.co.jp/e/2016/09/29/23835">まだGAの「滞在時間」を信用してるの? 計算の仕組みとその使い方を理解する[第15回] | 衣袋教授の新・Googleアナリティクス入門講座 | Web担当者Forum</a></p><p> この章のタイトル「ユーザ満足度はgoogleアナリティクスでは測れない」はちょっと過激にしてありますが、ブログに関して言うと当たらずといえども遠からずというのが私の肌感覚です。特に、ページごとに出てくる数字はPV以外「気休め」くらいに思った方が精神衛生上良いでしょう。</p><p> では何で見るのがいいかというと、Search Consoleはある程度使えます。ページごとにどんなキーワードでユーザが来ているのかがわかるので、キーワード(検索意図)とページの内容がずれていたらたぶん満足度は低いだろうな、ということがわかるからです。これは改善に使えます。</p><p> あとはやっぱり、自分で読んでみて読みやすいか、わかりやすいかといったあたりでしょう。</p>
</div>
<div class="section">
<h3>それでも直帰率を下げたい</h3>
<p> そんなに直帰率を下げることにこだわらなくていいという記事ですが、それでも下げたいのであれば。</p>
<ol>
<li>サイドバーとかに面白いものを出して(人気記事ランキングとか)、そっちに飛ばす</li>
<li>無理のない範囲で内部リンクを貼って、関連記事への回遊を促す</li>
<li>記事を読み終えたらすぐに関連記事リストが出てくるように配置する</li>
</ol><p> の3点くらいでしょうか。数%~5%くらいはいけると思います。私はもう実践していませんが、こだわる方はどうぞ。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> ということで、直帰率は下げなくても可です。直帰率は極論すれば、ブログにとっては「下げれば反比例してPVが増える以外、特に意味のない数字」と言っていいと思います。</p><p> ブロガーの方は、直帰率が高いからユーザの不満度が高いのかなぁ~とか心配する暇があったら、せいぜいサチコ<a href="#f-0f4e0e89" name="fn-0f4e0e89" title="Search Console">*3</a>を見てキーワード最適化しましょう。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-7e9fa367" name="f-7e9fa367" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">ユーザビリティだったり広告最適化だったり</span></p>
<p class="footnote"><a href="#fn-a2518bbc" name="f-a2518bbc" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">数千記事、100万PVクラスのブログだと事情が違う可能性はあります。でも、そんな人は読んでないだろうし</span></p>
<p class="footnote"><a href="#fn-0f4e0e89" name="f-0f4e0e89" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">Search Console</span></p>
</div>
hayataka2049
記事の寿命から考える、1記事で1日に得るべきPVとブログの収益性
hatenablog://entry/17680117127218357209
2019-07-15T07:30:42+09:00
2019-07-15T07:36:57+09:00 はじめに 当ブログは見ての通りたくさん広告を貼っていますが、こういうことをしていると「どれくらいPVを稼げば、記事を書く労力に対して儲けが割に合うのかなぁ」ということが気になってきます。そこで常日頃から考えていたことを軽く書いておきます。 テーマは「1記事で1日にどれくらいPVを稼げていれば、割に合う広告収益が得られるのか」です。ぶっちゃけダーティーなカネの話ですが、ふんわりした感じで計算していきますのでご安心ください。 目次 はじめに 未来永劫PVを稼げて広告を貼り続けられるなら、いつかはペイする 記事の寿命は3年程度 PVの単価を考えると1PV 0.15円くらい 記事に費やした労力をお金に…
<div class="section">
<h3 id="はじめに">はじめに</h3>
<p> 当ブログは見ての通りたくさん広告を貼っていますが、こういうことをしていると「どれくらいPVを稼げば、記事を書く労力に対して儲けが割に合うのかなぁ」ということが気になってきます。そこで常日頃から考えていたことを軽く書いておきます。</p><p> テーマは「1記事で1日にどれくらいPVを稼げていれば、割に合う広告収益が得られるのか」です。ぶっちゃけダーティーなカネの話ですが、ふんわりした感じで計算していきますのでご安心ください。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#はじめに">はじめに</a></li>
<li><a href="#未来永劫PVを稼げて広告を貼り続けられるならいつかはペイする">未来永劫PVを稼げて広告を貼り続けられるなら、いつかはペイする</a></li>
<li><a href="#記事の寿命は3年程度">記事の寿命は3年程度</a></li>
<li><a href="#PVの単価を考えると1PV-015円くらい">PVの単価を考えると1PV 0.15円くらい</a></li>
<li><a href="#記事に費やした労力をお金に換算すると平均437円くらい">記事に費やした労力をお金に換算すると平均437円くらい</a></li>
<li><a href="#437円を3年で稼ぐには一日3PV必要">437円を3年で稼ぐには一日3PV必要</a></li>
<li><a href="#ただし稼げるとは一言も言っていない">ただし稼げるとは一言も言っていない</a></li>
<li><a href="#まとめ">まとめ</a></li>
</ul>
</div>
<div class="section">
<h3 id="未来永劫PVを稼げて広告を貼り続けられるならいつかはペイする">未来永劫PVを稼げて広告を貼り続けられるなら、いつかはペイする</h3>
<p> たとえば1ヶ月に1円しか稼がない記事があったとして、1年で12円、10年で120円、100年で1200円の収益が入ります。1ヶ月に1円というのはとても低いハードルなので、たぶん(最低限の内容があれば)すごく適当に書いた記事でも達成できます。こういう方向性で努力するというのも一つの手です。100年待てるのなら。</p><p> ふざけんな、そんな非現実的な想定してなんの役に立つんだ、と思われるかもしれませんが、「どれだけの期間で記事作成に支払った労力を回収したいのか」が重要、というのがミソです。</p><p> また、「現実的にどれくらいの期間、収益を上げられるのか」も当然考慮するべきでしょう。100年の間にgoogleやはてながサービスを終了するかもしれないし、そもそも100年後の人類(人工知能の文明になってるかもしれないけど)の興味関心に沿った記事でなければ読まれないのですから。</p>
</div>
<div class="section">
<h3 id="記事の寿命は3年程度">記事の寿命は3年程度</h3>
<p> 日頃から検索エンジンを使っている人であれば、だいたい数年以内に書かれたページが上位に出てくるということは実感していると思います。それ以前に同じテーマで書いた人がいないのかというとそういう訳ではなく、古い記事は検索ランキングを落とされます。何十位もさかのぼれば、古めのページも出てきたりします。</p><p> 「どれくらいの期間で投入した労力を回収するのか」をこれから自動的に決めることができます。というか、決めないといけません。</p><p> 今回は考察を簡単にするために、3年間は一定のアクセスを集めて、それ以後はアクセスが0になる、というモデルを想定しましょう。この想定はそんなに実情からかけ離れている訳ではなく、どちらかといえばやや保守的な想定です(実際には記事を公開してから数年が過ぎ、検索ランキングが落ちてもある程度のアクセスは入ってきます。でも、0とします)。</p>
</div>
<div class="section">
<h3 id="PVの単価を考えると1PV-015円くらい">PVの単価を考えると1PV 0.15円くらい</h3>
<p> ダーティーな話題ですが、避けては通れない話題です。1PVあたりいくら稼げるのかという問題です。</p><p> たとえばgoogleアドセンスで収益化するのなら、500PVくらいに1回は広告を踏む人がいて、30円とかが懐に入ります。アフィリエイトなら、PVに対する商品の売れる数の比率は数分の1とか未満になるけど、一回で懐に入る金額は安くても30円の10倍とかのはずです。</p><p> なので、平均的に見ると1PVでいくら稼いでいる、という数字を計算できます。</p><p> このブログはアドセンスしか貼っていませんが、実測値をぼんやりと書くと0.1円/PV以上はあるけど0.2PV/円はないかな、というくらいです。今回は0.15円/PVで考えます。これもどちらかといえば保守的な数字ですが、でもそんなに実情から乖離している訳ではありません。<br />
(ただし、この数字はサイト・コンテンツの内容や、広告の貼り方などによってけっこうブレるので、あまり当てになりません。上の数字の半分の人も、倍以上の人もいます。適当に自分が使いたい数字を当てはめてください)</p>
</div>
<div class="section">
<h3 id="記事に費やした労力をお金に換算すると平均437円くらい">記事に費やした労力をお金に換算すると平均437円くらい</h3>
<p> これもまたダーティーな話題ですが、1記事を作るのに費やした労働コストを金銭換算します。</p><p> 計算は簡単な時給換算です。まず最低賃金を見ます。</p><p><a href="https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/koyou_roudou/roudoukijun/minimumichiran/">https://www.mhlw.go.jp/stf/seisakunitsuite/bunya/koyou_roudou/roudoukijun/minimumichiran/</a></p><p> 平成30年度の全国加重平均(ちゃんと書かれていませんが人口で加重平均しているのだと思います)が874円なので、この数字を採用します。最低賃金以下なら割に合わない、という単純な発想です。「俺は最低賃金じゃ働きたくない、せめてン円はほしい」という人は勝手に好きな数字を決めて計算してください。</p><p> 時給がわかったので、あとは1記事にどれくらいの時間を費やしたのかを考えます。これも記事の長さによっていくらでも変わってくる数字ですが、勝手に平均30分ということにします。ブログ記事を書くのに費やす時間の実情としては、そんなものでしょう。</p><p> 時給と労働時間が決まれば、1記事に投入されたコストがわかります。</p><p> 437円ですね。</p>
</div>
<div class="section">
<h3 id="437円を3年で稼ぐには一日3PV必要">437円を3年で稼ぐには一日3PV必要</h3>
<p> まず1日あたりに1記事が稼ぐべき金額を決めます。<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%5Cfrac%7B437%7D%7B365%5Ctimes%203%7D%20%5Csimeq%200.4" alt=" \frac{437}{365\times 3} \simeq 0.4"/>となります。</p><p> 更に0.15円/PVですから、<img src="https://chart.apis.google.com/chart?cht=tx&chl=%200.4%20%2F%200.15%20%5Csimeq%202.7" alt=" 0.4 / 0.15 \simeq 2.7"/>となり、1日に3PV稼いでればまあまあ割に合うということになります。</p><p> これはそんなに高いハードルではないので、お金目当てでやる人はクリアできるでしょう。ま、当ブログには一日3PVも稼いでいない記事いくらでもありますが。</p>
</div>
<div class="section">
<h3 id="ただし稼げるとは一言も言っていない">ただし稼げるとは一言も言っていない</h3>
<p> ブログを書いてそこそこの儲けを出せる人は、たぶん他の方法で稼げば最低賃金よりは多くもらえることの方が多いと思うので、そういう意味では割に合わないでしょう。残業して働いた方が稼ぐ手段としてはマシです。</p><p> また、「ブログ専業でも最低賃金くらいはもらえる」というのも無理があると思います。週40時間労働として、上の想定だと一週間に80記事上げることになります。どう考えても無茶です(そんなにネタがない)。まあ、3PV稼げればと割り切ってゴミ記事を量産してもいいですし、あるいはせめて1記事10PVくらいを目指して1記事に時間をかける方向性もあるかもしれませんが、それでも週30記事くらいなので普通の人には無理です。</p><p> 逆に、仕事や学業をしながら一日1記事くらい投稿するというペースだとざっくり言って専業フルタイムでやる1/10くらいの投稿頻度なので、稼ぎも月2万円未満くらいという数字になります。まあ、これもリアルな数字で、大半の「ブロガー」は月数万円くらい稼げていれば十分ペイしているのでそれで満足するべき、という結論になります。</p><p> それだと色々寂しいので、もっと派手に稼ぎたいということで、仮に時給2000円を想定すると、1記事一日6PVくらい。3000円で10PVくらいです。この辺の数字の方が肌感覚に近く、「割に合う」と言っていいのはそれ以上の水準かもしれません。</p><p> また、1PVの収益率はブレのある数字なので、倍かもしれないし半分かもしれない、という問題が現実としてはあります。「1PVで0.15円いけるやろ」と思ってやってみたら半分だった、というのは悲惨なので、気をつけてください。</p><p> あとは、「丸一日かけて書いた渾身の力作がぜんぜんPV稼げない」とか「5分で上げたのが案外伸びた」みたいなのも考慮していません。あくまでも平均的な数字です。なので、記事単位での凹凸はありえます(ポジティブな凹凸は構いませんが、ネガティブな方向に向かうのは当然できるだけ減らすべきです。そう考えると長文力作記事はリスキーですね)。</p>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> 色々と考えてみましたが、個人的にそこそこの発見だったのは「1記事あたり一日3PVあれば、時給換算で最低賃金超える」というあたりですね。思っていた水準はもっと上だったので、少し驚きました。でも、冷静に考えたらやっぱりもう少し上を狙わないと苦しい、という結論に達しました。</p><p> 1記事でどれくらいPVを稼いでいるべきなのか、という数字が出るとサイト運営の上でいい目安になるので、収益化してるブログを持っている人は考慮してもいいんじゃない? と思います。みんな当たり前にやっていて意識すらしないということなのかもしれませんが、そういう観点で語っている人は意外と少ないので書いてみました。</p><p> このブログを読んでいる人で、この情報が役に立つ人はあまりいないと思いますが、もしいたら何かの参考にしてください。役に立たなくても「ふーん、そういう世界なのね」と思って読んで頂けたなら私的には幸いです。</p>
</div>
hayataka2049
ブログのSearch Consoleでの平均CTRや平均掲載順位が下がるのはオッケー。クリック数と表示回数が大切
hatenablog://entry/17680117127216088556
2019-07-14T04:31:16+09:00
2019-07-14T04:31:16+09:00 はじめに 当サイトは見て分かる通りの零細プログラミングブログです。大したアクセスを稼いでいないので、ぶっちゃけPVのこととか気にしても仕方ありません。考える暇があったら記事書いた方が良いというやつですね。 が、実を言うと中の人は割と頻繁にアクセス解析したりSearch Consoleいじったりしています。放っときゃいいのにって? それもそうなんですが、趣味なので・・・ で、最近の傾向は、Search Consoleの平均CTR(検索に表示されたページがクリックされる確率)と平均掲載順位(検索に表示されたときに平均して何位に出てきたのかという数字)が落ち気味なことです。普通だったらサイトの集客力…
<div class="section">
<h3>はじめに</h3>
<p> 当サイトは見て分かる通りの零細プログラミングブログです。大したアクセスを稼いでいないので、ぶっちゃけPVのこととか気にしても仕方ありません。考える暇があったら記事書いた方が良いというやつですね。</p><p> が、実を言うと中の人は割と頻繁にアクセス解析したりSearch Consoleいじったりしています。放っときゃいいのにって? それもそうなんですが、趣味なので・・・</p><p> で、最近の傾向は、Search Consoleの平均CTR(検索に表示されたページがクリックされる確率)と平均掲載順位(検索に表示されたときに平均して何位に出てきたのかという数字)が落ち気味なことです。普通だったらサイトの集客力が落ちていると解釈されて大問題になるところですが、ここ一ヶ月くらいの当ブログのアクセスは絶好調でして、どれくらい絶好調かというと今年に入ってからアクセスがずっと下降傾向だったのが<a href="#f-e8f2abd4" name="fn-e8f2abd4" title="独自ドメイン化したりいろいろやっちゃったせいだと思います。やむを得ない">*1</a>、一ヶ月で半年前の水準に戻りました。</p><p> なんで平均掲載順位が落ちてCTRも下がってるのにアクセス増えるんや? と思ってデータを軽く見てみたらけっこう面白い傾向が見えたので書き残しておきます。</p><p> あ、あと、googleの規約上実データは一切出せないし、模擬データのグラフでも描こうかとも思いましたが面倒くさいので、この記事はひたすら言葉だけで説明します。予めご了承ください。</p>
</div>
<div class="section">
<h3>いろんなクエリに低い順位で引っかかるようになった</h3>
<p> ざっと見た感じだとそんな傾向です。具体的に書くと、一日500表示くらいのキーワードの8位とか9位で出てる記事がいくつもありました。この順位だといちおう1ページ目には出ますが、それでたくさんアクセスが集まる訳ではありません。上位の記事に吸い寄せられるからです。でも、一定数のユーザは順位の低い記事も見に来ます。</p><p> 正直わりと検索意図に合致していない記事が出ている感も否めないのですが、それでも(タイトルが若干煽り気味だったりするので)入ってくる人はそれなりにいます。500表示で6位以下、CTRが5%なら単純計算で一日25PVになります。このブログで一つの記事が稼ぐPVとしては十分な数字です<a href="#f-19c58501" name="fn-19c58501" title="そんな美味しいのたくさんはないけど">*2</a>。</p><p> ということで、順位とCTRは下がってPVが増えるという状況が成立します。</p>
</div>
<div class="section">
<h3>検索に現れすらしなかった記事が評価されるようになった</h3>
<p> 今年に入ってからは新しいドメインの評価が安定していなかったり、忙しくて更新頻度が落ちたりして、割とgoogleの評価が冷たかったので、新しく書いた記事はぜんぜん検索でヒットしてくれないような状況でした。それでもURL移転から半年以上がすぎ、ようやく安定してきたので、その時期に書いた記事がじわじわ検索で上がるようになってきました。</p><p> そういう記事はまだ順位が安定しておらず、割と低めの位置にいます。まあでも、このパターンだと経験的には一年くらいかけて上がるような気がするので、今後に期待です。</p>
</div>
<div class="section">
<h3>上の下というポジションの記事が増えるとこうなる</h3>
<p> 上の下というのは、検索1ページ目の下側1/3くらいの領域のことです。</p><p> 変な話、30位とかにランクインしてても検索3ページまで見る人はそんなにいない訳で、そもそも表示回数が少ないので、平均掲載順位へのインパクトはあまりない訳です。でも、1ページ目の下の方に出るようになると統計上は「表示」されるし、実際にはほとんどクリックされないのでCTRと平均掲載順位の指標は下がり気味になる可能性があります(元がある程度高ければの話。このブログは特定のキーワードで上位に出てPVを集めるという記事をいくつか抱えているので、そういう傾向になってしまいました)。</p><p> もっと変な話すると、このロジックで行くと平均CTRだけ考えるなら10位より11位の方が有利です。で、google先生はおそらくCTRからフィードバックをかけて検索順位を調整していると思うので、もしかすると彼らのアルゴリズム次第では</p>
<ol>
<li>2ページ目上位で有利に表示されていた記事の評価が上がって1ページ目下位に移動する</li>
<li>1ページ目では表示回数の割にクリックされないのでしばらくして評価が下がりまた2ページ目へ</li>
<li>以下ループ</li>
</ol><p> というパターンもあり得るかもしれません(さすがにある程度の補正はしてそうですが)。なんとなく10位くらいを基準にフラフラしてる記事とクエリの組み合わせがいくつかあるので、可能性としてはそれなりにありえる気がします。</p>
</div>
<div class="section">
<h3>クリック数と表示回数の絶対数は重要</h3>
<p> 話がそれました。けっきょく何が言いたいのかというと、まず</p>
<ul>
<li>平均CTRと平均掲載順位はあまり気にしても仕方ない</li>
</ul><p> ということです。というか、単純なこれの上下に一喜一憂する必要はないと思います。</p><p> どちらかといえば重視するべきなのは、</p>
<ul>
<li>表示回数</li>
<li>クリック数</li>
</ul><p> です。要は絶対的な検索流入(≒PV)だけ見ろってことです。位置はともかく表示されるようになればたぶんgoogle先生はサイトの評価を上げているし、それに伴って検索流入が拡大すれば悪いことはないのです。</p><p> この逆パターン(PV減、平均掲載順位と平均CTR改善)があるのかどうかはわかりませんが、もしあったら要注意な感じです。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> なんかとりとめのない感じになりましたが、考察してみました。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-e8f2abd4" name="f-e8f2abd4" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">独自ドメイン化したりいろいろやっちゃったせいだと思います。やむを得ない</span></p>
<p class="footnote"><a href="#fn-19c58501" name="f-19c58501" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">そんな美味しいのたくさんはないけど</span></p>
</div>
hayataka2049
ロジスティック回帰が線形分離不可能な分類問題を解けないことの説明
hatenablog://entry/17680117127214398918
2019-07-07T03:36:21+09:00
2019-09-01T00:11:41+09:00 はじめに ロジスティック回帰が線形分離不可能な分類問題を解けないことは有名な話です。だけど、「いや解けるだろ」「なんで解けないの???」と言われてしまうことがあるので*1、それができないことを説明しておこうと思います。 なお、この記事はこちらの記事を参考にしています。誤った図解から学ぶロジスティック回帰の性質 - ill-identified diary 書きたいことは言い尽くされている感もあるので、こういう結論に至る過程を数式で書きます*2。 y=0.5を代入すればいい さて、説明変数、目的変数、パラメータ、などを適当に定めたとします。すると、ロジスティック回帰の予測式はこんなやつになります…
<div class="section">
<h3>はじめに</h3>
<p> ロジスティック回帰が線形分離不可能な分類問題を解けないことは有名な話です。だけど、「いや解けるだろ」「なんで解けないの???」と言われてしまうことがあるので<a href="#f-004c244d" name="fn-004c244d" title="……">*1</a>、それができないことを説明しておこうと思います。</p><p> なお、この記事はこちらの記事を参考にしています。</p><p><iframe src="https://hatenablog-parts.com/embed?url=http%3A%2F%2Fill-identified.hatenablog.com%2Fentry%2F2018%2F05%2F23%2F233955" title="誤った図解から学ぶロジスティック回帰の性質 - ill-identified diary" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="http://ill-identified.hatenablog.com/entry/2018/05/23/233955">誤った図解から学ぶロジスティック回帰の性質 - ill-identified diary</a></p><p> 書きたいことは言い尽くされている感もあるので、こういう結論に至る過程を数式で書きます<a href="#f-a127b405" name="fn-a127b405" title="誰でも納得するから">*2</a>。</p>
</div>
<div class="section">
<h3>y=0.5を代入すればいい</h3>
<p> さて、説明変数<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20x_i" alt=" x_i"/>、目的変数<img src="https://chart.apis.google.com/chart?cht=tx&chl=y" alt="y"/>、パラメータ<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%5Cbeta_i" alt=" \beta_i"/>、などを適当に定めたとします。すると、ロジスティック回帰の予測式はこんなやつになります(<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%5Cbeta_i" alt=" \beta_i"/>は適当に学習できたとする)。</p><p>\begin{align}<br />
\hat{y} = \frac{1}{1 + <br />
\mathrm{e}^{-(\beta_0 + \sum_{i=1}^{n}\beta_i x_i)}<br />
}<br />
\end{align}</p><p> 書き方の流儀はいろいろあると思いますが(<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%5Calpha" alt=" \alpha"/>を使うとか)、今回は上の式で行きます。</p><p> さて、今回は分離超平面の式に興味があるのでしたね。分離超平面ってどこ? というと、<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20y%3D0.5" alt=" y=0.5"/>のところです。なので、淡々と式を書き換えます。</p><p>\begin{align}<br />
0.5 = \frac{1}{1 + <br />
\mathrm{e}^{-(\beta_0 + \sum_{i=1}^{n}\beta_i x_i)}<br />
}<br />
\end{align}<br />
<br />
両辺を逆数にします。</p><p>\begin{align}<br />
2 = 1 + \mathrm{e}^{-(\beta_0 + \sum_{i=1}^{n}\beta_i x_i)}<br />
\end{align}</p><p> とりあえず邪魔な1を反対側に移す。</p><p>\begin{align}<br />
1 = \mathrm{e}^{-(\beta_0 + \sum_{i=1}^{n}\beta_i x_i)}<br />
\end{align}</p><p> 両辺の対数を取る。</p><p>\begin{align}<br />
0 = -(\beta_0 + \sum_{i=1}^{n}\beta_i x_i)<br />
\end{align}</p><p> マイナスは必要ないので消しましょう。</p><p>\begin{align}<br />
0 = \beta_0 + \sum_{i=1}^{n}\beta_i x_i<br />
\end{align}</p><p> もうだいたい終わってる気もしますが、たとえば<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20n%3D2" alt=" n=2"/>として適当に式を変形します。</p><p>\begin{align}<br />
\beta_0 + \beta_1 x_1 + \beta_2 x_2 = 0<br />
\end{align}</p><p> ……はい、これは「直線の式」ですね。</p><p> <img src="https://chart.apis.google.com/chart?cht=tx&chl=%20n" alt=" n"/>が増えると係数と変数が増えていきますが、いずれにせよ線形の式なのは間違いありません。<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20x_i%5E2" alt=" x_i^2"/>とか<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%5Cmathrm%7Be%7D%5E%7Bx_i%7D" alt=" \mathrm{e}^{x_i}"/>みたいなのが出てくる余地はありません。</p><p> 「分離超平面」がかのような式で表わせる以上、線形分離不可能な分類問題は解けない、ということです。</p>
</div>
<div class="section">
<h3>非線形の問題も解く方法</h3>
<p> あくまでも「分離境界が線形にならないといけない」というだけなので、データを非線形変換して解けるような空間に写像すればできます。代表的な方法は多項式を使うことです(SVMの多項式カーネルなんかと同じですが、明示的に特徴量空間を計算するのが相違点です)。</p><p> ということで、こちらの記事を御覧ください。どれくらい非線形でも行けるのかが書いてあります。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F07%2F08%2F042121" title="非線形がなんだ! ロジスティック回帰+多項式でやってやる! - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/07/08/042121">非線形がなんだ! ロジスティック回帰+多項式でやってやる! - 静かなる名辞</a></p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-004c244d" name="f-004c244d" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">……</span></p>
<p class="footnote"><a href="#fn-a127b405" name="f-a127b405" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">誰でも納得するから</span></p>
</div>
hayataka2049
コサイン距離は距離じゃないんだから、勘違いしないでよねっ!
hatenablog://entry/17680117127212914938
2019-07-05T03:09:35+09:00
2019-09-03T19:01:06+09:00 自然言語処理などでお馴染みのコサイン類似度。これを1から引いたものを「コサイン距離」と称している文献も散見されますが、この「コサイン距離」は距離としての性質を満たしません。それがどういうことなのかをこの記事で説明していきます。
<div class="section">
<h3>き、記事タイトルに意味なんてないんだからねっ!</h3>
<p> 自然言語処理などでお馴染みのコサイン類似度。これを1から引いたものを「コサイン距離」と称している文献も散見されますが、この「コサイン距離」は距離としての性質を満たしません。</p><p> それがどういうことなのかをこの記事で説明していきます。</p>
</div>
<div class="section">
<h3>コサイン類似度のことくらい自分で調べなさいっ!</h3>
<p> まず前提となるコサイン類似度については、親切に解説しているサイトが他にたくさんあるので、そちらに譲ります。</p><p> たとえばここなどがいいでしょう。</p><p><a href="http://www.cse.kyoto-su.ac.jp/~g0846020/keywords/cosinSimilarity.html">コサイン類似度</a></p><p> コサイン類似度はベクトル同士の類似度であり、要するに単なる内積(をノルムで正規化したもの)です。これは-1から1の区間を取ります。1なら「最も似ている(同じベクトル)」、-1なら「最も似ていない(反対向き)」という性質を持ちます。</p><p> これを1から引くことで、0なら「最も似ている」、2なら「最も似ていない」に変換したものが「コサイン距離」です。</p>
</div>
<div class="section">
<h3>距離の定義を知らないの? しょ、しょうがないから教えてあげるわ</h3>
<p> さて、距離という言葉というか概念は実は数学的にちゃんと定義できます。かいつまんで書くと、関数<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20d" alt=" d"/>が以下の条件(距離の公理といいます)を満たすとき、その関数を距離関数あるいは距離と言えます。</p><p>\begin{align}<br />
d(x,y) &>& 0\\<br />
x&=&y\Leftrightarrow d(x, y) = 0\\<br />
d(x, y) &=& d(y, x)\\<br />
d(x, z) &\leq& d(x, y) + d(y, z)<br />
\end{align}</p><p>参考<br />
<a href="https://ja.wikipedia.org/wiki/%E8%B7%9D%E9%9B%A2%E7%A9%BA%E9%96%93">距離空間 - Wikipedia</a><br />
<a href="https://nemuneko-gensokyou.blog.so-net.ne.jp/2015-07-12-9">第6回 距離の公理:ねむねこ幻想郷:So-netブログ</a><br />
<a href="https://dic.nicovideo.jp/a/%E8%B7%9D%E9%9B%A2">距離とは (キョリとは) [単語記事] - ニコニコ大百科</a></p><p> 数式で見ると難しく見えるかもしれませんが、この式はそれぞれ</p>
<ul>
<li>距離は負にはならない(非負性)</li>
<li>同じ点同士の距離は0、距離が0の点は同じ点</li>
<li>x,yの間の距離について、距離を測る起点を逆にしても距離は変わらない(対称性)</li>
<li>x,zとまっすぐ行くときと比べて、yに寄り道すると必ずトータルの経路は長くなる(三角不等式)</li>
</ul><p> ということを言っているだけなので、概念的には簡単です。</p><p> こういうものを満たすと距離と呼べる、ということですね。</p><p> 「コサイン距離」はどれを満たさないのでしょうか?</p>
</div>
<div class="section">
<h3>わからないの? ……ばか</h3>
<p> 「コサイン距離」は2番目の<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20x%3Dy%5CLeftrightarrow%20d%28x%2C%20y%29%20%3D%200" alt=" x=y\Leftrightarrow d(x, y) = 0"/>と、4番目の三角不等式を満たしません。</p><p> 2番目を説明するのは簡単で、元のコサイン類似度はベクトル間の角度にしか興味を持たない性質があります。なので、たとえば二次元ベクトル<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%281%2C0%29" alt=" (1,0)"/>と<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%282%2C0%29" alt=" (2,0)"/>とか、<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%2842%2C1%29" alt=" (42,1)"/>と<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%2884%2C2%29" alt=" (84,2)"/>は同じ距離になります。</p><p> 4番目については、反例を挙げてみましょう。</p><p><figure class="figure-image figure-image-fotolife" title="すごく単純な例"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190705/20190705023734.png" alt="すごく単純な例" title="f:id:hayataka2049:20190705023734p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>すごく単純な例</figcaption></figure></p><p> 特に凝ったことはしていません。この図において、単純なユークリッド距離を考えると、</p>
<ul>
<li>A-B間, B-C間の距離:1</li>
<li>A-C間の距離:<img src="https://chart.apis.google.com/chart?cht=tx&chl=%20%5Csqrt%7B2%7D%5Csimeq%201.414" alt=" \sqrt{2}\simeq 1.414"/></li>
</ul><p> となり、こういうのが三角不等式を満たしている場合です。A-B-Cとたどる経路の長さは2になるので、A-Cとたどるより長い距離をたどることになります。</p><p> では、「コサイン距離」では? というと、</p>
<ul>
<li>A-B間, B-C間の「コサイン距離」:約0.293</li>
<li>A-C間の距離:1</li>
</ul><p> となり、A-B-Cとたどることで約0.586になりますからA-Cと直接たどるより短い距離で行けてしまうことになります。つまり、三角不等式を満たさないので、「コサイン距離」は距離ではないということになります。</p>
</div>
<div class="section">
<h3>距離として扱うと困るのかって? ……困るに決まってるじゃないっ、わからずや!</h3>
<p> データ分析などで、距離を使うことを前提としている手法で「コサイン距離」を使うと、不都合なことが起きる可能性があります。</p><p> みんなが大好きなirisのデータを多次元尺度構成法、MDSで可視化してみましょう。Pythonで書くとこうなります。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">import</span> matplotlib.pyplot <span class="synStatement">as</span> plt
<span class="synPreProc">from</span> scipy.spatial.distance <span class="synPreProc">import</span> pdist, squareform
<span class="synPreProc">from</span> sklearn.datasets <span class="synPreProc">import</span> load_iris
<span class="synPreProc">from</span> sklearn.manifold <span class="synPreProc">import</span> MDS
<span class="synStatement">def</span> <span class="synIdentifier">main</span>():
iris = load_iris()
A = squareform(pdist(iris.data, <span class="synConstant">"euclidean"</span>))
mds = MDS(n_components=<span class="synConstant">2</span>, dissimilarity=<span class="synConstant">"precomputed"</span>,
n_init=<span class="synConstant">10</span>, max_iter=<span class="synConstant">500</span>)
X_2d = mds.fit_transform(A)
<span class="synStatement">for</span> i, target <span class="synStatement">in</span> <span class="synIdentifier">enumerate</span>(iris.target_names):
mask = iris.target == i
plt.scatter(X_2d[mask,<span class="synConstant">0</span>], X_2d[mask,<span class="synConstant">1</span>], label=target)
plt.xlim(X_2d[:,<span class="synConstant">0</span>].min() - <span class="synConstant">1</span>, X_2d[:,<span class="synConstant">0</span>].max() + <span class="synConstant">1</span>)
plt.ylim(X_2d[:,<span class="synConstant">1</span>].min() - <span class="synConstant">1</span>, X_2d[:,<span class="synConstant">1</span>].max() + <span class="synConstant">1</span>)
plt.title(<span class="synConstant">"MDS stress:{:.4f}"</span>.format(mds.stress_))
plt.legend()
plt.savefig(<span class="synConstant">"iris_euclidean_mds.png"</span>)
<span class="synStatement">if</span> __name__ == <span class="synConstant">"__main__"</span>:
main()
</pre><p><figure class="figure-image figure-image-fotolife" title="iris_euclidean_mds.png"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190705/20190705025204.png" alt="iris_euclidean_mds.png" title="f:id:hayataka2049:20190705025204p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>iris_euclidean_mds.png</figcaption></figure></p><p> そんなに申し分はなさそうな結果ですね。</p><p> 「コサイン距離」でもやってみます。といっても、親切なことにscipyが「コサイン距離」を標準でサポートしているので、</p>
<pre class="code lang-python" data-lang="python" data-unlink> A = squareform(pdist(iris.data, <span class="synConstant">"cosine"</span>))
</pre><p> とすれば一発でできます。あとはせいぜい出力ファイル名を変えておきます。<br />
(plt.savefig("iris_cosine_mds.png")としました。)</p><p><a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.pdist.html">scipy.spatial.distance.pdist — SciPy v1.3.0 Reference Guide</a></p><p><figure class="figure-image figure-image-fotolife" title="iris_cosine_mds.png"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190705/20190705030217.png" alt="iris_cosine_mds.png" title="f:id:hayataka2049:20190705030217p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>iris_cosine_mds.png</figcaption></figure></p><p> なんかよくわからないことになりました。念のために中心付近にズームしてみます(plt.xlimとplt.ylimで調整)。</p><p><figure class="figure-image figure-image-fotolife" title="iris_cosine_mds_zoomed.png"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190705/20190705030238.png" alt="iris_cosine_mds_zoomed.png" title="f:id:hayataka2049:20190705030238p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>iris_cosine_mds_zoomed.png</figcaption></figure></p><p> 考えてみれば当然の結果で、コサイン類似度は-1から1のレンジを取ります。ということは、「コサイン距離」の最大値は2にしかならないのです。なので、遠い点が表現できなくなり、とても小さい範囲に押し込められます。</p><p> また、「コサイン距離」では向きが同じで長さの違うベクトル同士を区別できません。昔作ったirisの主成分分析のバイプロットを持ってくると、</p><p><figure class="figure-image figure-image-fotolife" title="irisのバイプロット"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20180328/20180328230804.png" alt="irisのバイプロット" title="f:id:hayataka2049:20180328230804p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>irisのバイプロット</figcaption></figure></p><p><a href="https://www.haya-programming.com/entry/2018/03/28/231305">【python】pythonで主成分分析のバイプロット - 静かなる名辞</a></p><p> グループ間の差異は概ね第一主成分に、グループ内での差異は第二主成分にあらわれています。そして、第一主成分とほぼ同じ方向を向いている2つの変数、そうでもない2つの変数があることがわかります。</p><p> 品種が違うと各変数の相対的な比率が変わる反面、同じ品種同士では各変数の相対的な比率はさほど変わらない(全体的に大きかったり小さかったりという個体差があるだけ)と想定すれば、結果が一直線上に並ぶのもなんとなく理解できる気がします。</p>
</div>
<div class="section">
<h3>「じゃあどう呼べば良いのか」って? そんなの自分で考えてよね!</h3>
<p> 「コサイン距離」に変わる呼称方法ですが……</p><p> ま、常識的に考えると、<b><span style="font-size: 150%">コサイン非類似度</span></b>でいいのではないでしょうか。</p>
</div>
<div class="section">
<h3>わかったなら感謝しなさい。……え、ありがとう? べ、べつに喜ばれても嬉しくなかんないんだからっ!</h3>
<p> 安易に「コサイン距離」という言葉を使ってはいけないこと、また、距離として扱うと問題になるというか、イマイチな結果を招く可能性があることがこの記事でわかっていただけたら、嬉しいです。</p><p> あと、ツンデレ風の章タイトルにしたことに対して今更ながら後悔の念を感じ始めているのですが(自分で見返してもかなり痛い)、下書きに放り込んで一晩寝たらたぶん投稿する勇気がなくなっていると思うので、蛮勇を奮ってこのまま<s>後悔</s>公開することにします。</p>
</div>
hayataka2049
AIでプログラマーが失業するとか、気にしなくていいと思うよ
hatenablog://entry/17680117127203283612
2019-06-29T19:20:58+09:00
2019-06-29T19:20:58+09:00 はじめに 昨今のAIブームで、AIへの過剰な期待からか「プログラマー」が失業するのでは? ということが囁かれるようになりつつあります。人工知能によってプログラマーは失業する?AIに仕事を奪われる前にAIエンジニアになる? | アトオシ プログラマーという職業は10年後にはなくなる?これからの10年をどう生きるか | フリーランスへの道しるべ 正直「人目を引くために過激なこと言ってるだけだろ」という気もしなくはないのですが、この分野の末席で研究をやっている大学院生として*1コメントしておくことにします。 AIの定義は時代とともに移り変わる ある程度ご年配の方だと、「AI搭載でおいしく炊ける炊飯器…
<div class="section">
<h3>はじめに</h3>
<p> 昨今のAIブームで、AIへの過剰な期待からか「プログラマー」が失業するのでは? ということが囁かれるようになりつつあります。</p><p><a href="https://itpropartners.com/blog/11704/">人工知能によってプログラマーは失業する?AIに仕事を奪われる前にAIエンジニアになる? | アトオシ</a><br />
<a href="https://crowdtech.jp/blog/?p=647">プログラマーという職業は10年後にはなくなる?これからの10年をどう生きるか | フリーランスへの道しるべ</a></p><p> 正直「人目を引くために過激なこと言ってるだけだろ」という気もしなくはないのですが、この分野の末席で研究をやっている大学院生として<a href="#f-b0afd61a" name="fn-b0afd61a" title="といっても、今の研究はデータサイエンス寄りで、この辺にはほとんど絡みませんが……">*1</a>コメントしておくことにします。</p>
</div>
<div class="section">
<h3>AIの定義は時代とともに移り変わる</h3>
<p> ある程度ご年配の方だと、「AI搭載でおいしく炊ける炊飯器」「AIが最適に制御するエアコン」といった製品が出てきた時代のことを覚えていると思います。今では「ただのマイコン制御じゃん」と思う訳ですが、それが当時最先端の「人工知能」でした。</p><p> 他にも、以下のような技術は少なくとも登場時点では「AI」とみなされていたはずです。もちろん、今ではそんなことを思う人は(ほとんど)いません。</p>
<ul>
<li>プログラミング言語のコンパイラ</li>
<li>かな漢字変換</li>
<li>郵便番号の自動読み取り</li>
</ul><p> その時代の技術で実現できなかったもの、実用化されなかったものが「AI」と呼称されて残る、というシニカルな見方もあるくらいです。</p><p><a href="https://ja.wikipedia.org/wiki/%E4%BA%BA%E5%B7%A5%E7%9F%A5%E8%83%BD%E3%81%AE%E6%AD%B4%E5%8F%B2">人工知能の歴史 - Wikipedia</a><br />
<a href="http://www.soumu.go.jp/johotsusintokei/whitepaper/ja/h28/pdf/n4200000.pdf">http://www.soumu.go.jp/johotsusintokei/whitepaper/ja/h28/pdf/n4200000.pdf</a></p><p> 特にプログラミングに関して言えば、簡潔に問題を解決できるよう、自動的に処理できる部分は自動的に処理させるという方向性の努力はずっと続けられてきています。だからこそ、素晴らしいオブジェクト指向プログラミングができたり、モダンな言語で型推論が使えたりする訳です。</p>
<blockquote>
<p>「自動プログラミングとは、いつの時代もその当時のプログラマが使える言語より高水準の言語でプログラミングすることを意味する婉曲表現だった」</p><p>D. L. Parnas. "Software Aspects of Strategic Defense Systems." American Scientist. November 1985.<br />
翻訳は <a href="https://ja.wikipedia.org/wiki/%E8%87%AA%E5%8B%95%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0">自動プログラミング - Wikipedia</a></p>
</blockquote>
<p> なので、一つの考え方は「今までどおりのことだから気にする必要はない」というものでしょう。</p><p> だけど、プログラマーが失業する、という予見が世間を賑わせるようになったのは、今までの状況とは少し異なりそうです<a href="#f-1210176c" name="fn-1210176c" title="前もあったよ! といえば、それはまあその通りなのですが">*2</a>。</p><p> もうひとつの考え方、つまり「ついに人間の能力に匹敵するAIができそうなので、これまで高度な知的職業とみなされてきたプログラマーが失業しかねない」という考え方が説得力を持つようになった、とみなすのが自然でしょう。そこで、これについて、もう少し色々な角度から考えてみます。</p>
</div>
<div class="section">
<h3>これつでに技術革新で消滅した職業</h3>
<p> 1950年代とか大昔には、ソースコードは手書きしたりタイプライターで打ち込んだりして、キーパンチャという職業の人に渡していました。キーパンチャの人が何をするのかというと、渡されたコードをパンチカードに打ち込むのです。打ってもらったパンチカードをIBMなんかの汎用機のカードリーダに突っ込んで、プログラムを読み込ませていました<a href="#f-7c193047" name="fn-7c193047" title="さも見てきたかのように書いていますが、実際に見たことはありません。こういうことをしていた世代の人は、古い人だともう鬼籍に入られている方も多いくらいでしょう">*3</a>。</p><p> キーパンチャの人は、パンチカードが廃れた80年代に当然失業しています。やることはデータ入力なので、パンチカードが廃れても潰しは効いたと思いますが……</p><p> もう少し一般的な例だと、昔は植字工という職業がありました。活字というのはもともと鉛で作られた字のスタンプのことで、それを並べて作った組版にインクを塗って紙に押し当てて印刷するのが活版印刷です。なので人の手で活字をケースから集めてきて並べないと印刷ができないという時代があったのですが、これもオフセット印刷などが普及したことで、職業としてはほぼ消滅しています。</p><p> 技術革新で消滅した職業というのは、他にもたくさん、いくらでもあります。そういう職業についていた人は一度は失業して、年配の方ならばそのまま現役引退されたかもしれませんし、まだ若ければ最終的には他分野に転職した人が多いと思います。</p><p> プログラマーがこういう未来をたどる、という可能性について議論したい、ということなのでしょうね。</p>
</div>
<div class="section">
<h3>AIの水準はそのレベルに達しているか:まだ無理</h3>
<p> 残念ながら、昨今の人工知能ブームで中心的な役割を果たした深層学習は、「人間のような高度な判断が行える」という域には達していません。「ある程度人間の判断を代替できる」「大量のデータに対して機械的に適用できる」といったあたりが関の山です。</p><p> 機械翻訳などがわかりやすいでしょう。最近の機械翻訳は深層学習の技術を取り入れていて、単純な文であればかなり正確に翻訳できます。左の文を現在のgoogle翻訳に入れると「<br />
Modern machine translation incorporates deep learning techniques, so simple sentences can be translated fairly accurately.」と訳されますが、かなり文意の通じる訳文になっています。</p><p> ただし、含意まで読み取るというところまでは実現できていないのが現状です。それに、専門用語やスラングなどを文脈に合わせて翻訳する、といった必要があるケースでは、かなり不満の残る結果しか得られません。</p><p> 「コンピュータはあいまいな情報を処理するのが苦手」ということは昔から言われていましたが、最近は「あいまいな情報からも適当に推論してしまう」というあたりまでは達しています。だけど、あいまいに見えても背後には案外しっかりした規則があって、人間にはそれがわかるけど機械にはわからない……というような状況では、あまり深層学習は役に立たないはずです。</p><p> このあたりは技術の発展を待つ必要がありますが、とにかく大量のデータを突っ込んで、深層学習モデルで学習させて……という方向性で人間の判断を模せるレベルのものを作るのは、個人的には不可能だと思うし、AIの分野の人達もそういう方向性は目指していないのでは?</p><p> 何らかの技術的ブレークスルーがないと「もっと幅広い応用」は出てこないと思いますが、使えそうな技術の基礎研究はある程度出尽くしていて、その応用に力が注がれているのが現状です。もちろん深層学習の次世代(になるかもしれない)技術を研究してる人はたくさんいると思うんですが、現時点ですごく優秀で使えることがわかっているというものはありません。当然ですね。</p>
</div>
<div class="section">
<h3>プログラマーっていってもけっこう難しいことをしている</h3>
<p> プログラマーという職業の人達がどんな仕事をしているのかを考えてみましょう。機械が代替できるかどうかは、このあたりにかかっています。</p><p> とりあえずどんなプログラムを書くにせよ、その前に要件定義とか仕様の決定とか設計文書の作成とかをやるというのが典型的なケースです。中には、そこまできっちりやらないでとりあえず試作してみて、お客さんの反応を見ながら正式な仕様を決定していくみたいな方針もあると思いますが、考えることが多くなりすぎるのでやめます。</p><p> たとえば、こういうのを考えましょう。「プログラム 設計」とかでググって適当に出てきたサイトからの引用です。</p>
<blockquote>
<p>プログラム設計書の書き方の例</p><p>定数リスト<br />
No|名称|値|型|クラス名|ファイル名|書式|説明<br />
1|BOOK_LIMIT|30|int|book|testdayo.Java static final int BOOK_LIMIT|収容できる本数の上限</p><p>関数定義<br />
書式:boolean check_book_limit(int storage)<br />
機能:収納したい本の数(storage)が収納の上限数(BOOK_LIMIT)内に収まるかを真偽値で返す<br />
引数int strageの意味:収納したい本の数<br />
戻り値:true:収納できる<br />
戻り値:false:収納数が上限を超えるため収納できない</p><p><a href="https://mid-works.com/columns/freelance-wordlist/must-know-words/1074371">プログラム設計書とは?|各設計書の違いと書き方 - Midworks</a></p>
</blockquote>
<p> おおすごい、ぜんぶ挙動が定義されてる……これなら機械処理できるんじゃね? と誰でも思います。とりあえず、クラスは省略してpythonで書いてみましょう。</p>
<pre class="code lang-python" data-lang="python" data-unlink>BOOK_LIMIT = <span class="synConstant">30</span>
<span class="synStatement">def</span> <span class="synIdentifier">boolean</span> check_book_limit(storage):
<span class="synStatement">return</span> storage <= BOOK_LIMIT
</pre><p> 上の「プログラム設計書」から下のコードくらいのものを生成できれば良い訳ですね。なるほど、楽勝だ……。20年くらい前にも同じようなことを考えた人たちがいて、やろうとしたのですが、あまりうまくいかなかったそうです。やっぱり、機能が複雑になったり、説明が曖昧だったり手抜きになったりすると破綻するのでしょう。</p><p> 思いつく問題点をとりあえず列挙してみると、</p>
<ul>
<li>上の例だとしっかり書かれていて「収納の上限数内に収まるか」なので曖昧さはないけど、「以上」「未満」「より」とか出てくると途端にカオスになって曖昧さが紛れ込む。自然言語はそんなものです</li>
<li>とりあえず、自然言語だと解析が辛いから、曖昧さのない形式言語で書いておきたい→プログラミング言語で書くのと何が違うの? という話に</li>
<li>そもそも、この粒度の仕様が作れるなら、仕様書書く代わりにプログラミングしても良いのでは……?(上の仕様からプログラムを書き起こすみたいな仕事は、AIに関係なく減っていくと思います)</li>
<li>現実に与えられる要求は「本が本棚に収まり切るかどうかチェックしたい」「ボタンを押すと画面が明るくなる」みたいなレベルのやつで、文脈とか背景知識があれば要求されている通りのものが作れるが、逆に機械にやらせようと思ったらそういう部分をぜんぶ打ち込まないといけない。つまり、へたにプログラムを打つより苦労する可能性がある</li>
<li>自動生成できてもパフォーマンスは保証してくれないことが多い。出てきたものがすごく遅かったとき、どうする?</li>
</ul><p> なかなか難しいですね。こういうところを解決できるのは人間だけです。いや、機械でも「ここ曖昧でよくわからんから教えてくれ」って人間にフィードバック返しながらやればできるのかもしれないけど、最初から人間が打ち込んだ方が楽なんじゃないかなぁ。</p>
</div>
<div class="section">
<h3>プログラマーを代替できる水準のAIが作れるなら、プログラマーに限らず色々な職業が消滅する</h3>
<p> こういう問題が解決して、適当に仕事を押し付ければ満足の行く結果を出してくれるAIが仮に作れたとしましょう。</p><p> そういうAIは人間のプログラマーと同じ水準の仕事ができる訳ですが、こういうAIが作れるようになって失業するのは何もプログラマーに限られません。消える職業の方が多いでしょう。</p><p> ことさらにプログラマーがどうの、という話をする前に、考えるべきことがたくさんある訳です。「プログラマーはAIに取って代わられるのか、じゃあなるのやめよう」と思って別業種に就職した就活生がいたとして、その職業が先にAIに取って代わられない保証はまったくないのです。</p><p> だから、真に受けてプログラマーの将来だけ心配するのは馬鹿馬鹿しいし、真剣に考えるなら社会全体の問題です。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> AIに関係なく言語や技術が廃れて「これまでやってきた仕事がなくなる」ことはこれまでにも頻繁にあったと思います。それはそれでなんとかしてきた訳で、当分はその延長線上で推移すると思うので、今までどおりなんとかなるでしょう。</p><p> 実際問題として20年先のこととかはわからないし、真面目に考えて人生設計に反映している人がどれだけいるんですか? という話でもあります。だから、別に気にしなくていいんじゃないですかね。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-b0afd61a" name="f-b0afd61a" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">といっても、今の研究はデータサイエンス寄りで、この辺にはほとんど絡みませんが……</span></p>
<p class="footnote"><a href="#fn-1210176c" name="f-1210176c" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">前もあったよ! といえば、それはまあその通りなのですが</span></p>
<p class="footnote"><a href="#fn-7c193047" name="f-7c193047" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">さも見てきたかのように書いていますが、実際に見たことはありません。こういうことをしていた世代の人は、古い人だともう鬼籍に入られている方も多いくらいでしょう</span></p>
</div>
hayataka2049
今あえて書く、目的別Pythonを使うメリット・デメリット
hatenablog://entry/17680117127165148971
2019-06-26T23:53:52+09:00
2019-06-26T23:54:35+09:00 はじめに ここ数年間、日本国内のPython事情は急速に変わったと思います。私が使い始めた4年前と比べても、ずいぶん垢抜けた感じになったというのが正直な感想です。 Python2からPython3への移行が(ようやく)進み、扱いやすくなった ライブラリも良いものが増えたり、使いやすくなったりした 解説記事などもずいぶん増えて、やりやすくなった 古くからの用途であるデータサイエンス、機械学習に代わって、プログラミング初心者の勉強用言語として選択する人が増えた というあたりが実情でしょうか。Pythonの急拡大を支えたAIバブルには陰りが見えてきた感もなくはありませんが、Python自体は一定の地…
<div class="section">
<h3 id="はじめに">はじめに</h3>
<p> ここ数年間、日本国内のPython事情は急速に変わったと思います。私が使い始めた4年前と比べても、ずいぶん垢抜けた感じになったというのが正直な感想です。</p>
<ul>
<li>Python2からPython3への移行が(ようやく)進み、扱いやすくなった</li>
<li>ライブラリも良いものが増えたり、使いやすくなったりした</li>
<li>解説記事などもずいぶん増えて、やりやすくなった</li>
<li>古くからの用途であるデータサイエンス、機械学習に代わって、プログラミング初心者の勉強用言語として選択する人が増えた</li>
</ul><p> というあたりが実情でしょうか。Pythonの急拡大を支えたAIバブルには陰りが見えてきた感もなくはありませんが、Python自体は一定の地位を確保しつつある感じがして、蛇使い<a href="#f-d6835bb8" name="fn-d6835bb8" title="Pythonユーザのことです、念の為">*1</a>としては嬉しい限りです。</p><p> こういう時期だからこそ、客観性を心がけつつ主観混じり的に見て「Pythonは良いのか、悪いのか」を少し書いておこうと思います。</p><p> Python言語全般についてというのは漠然としすぎなので、用途別に書きます。長い記事なので、時間のあるときに興味のあるセクションだけお読みください。</p>
<ul class="table-of-contents">
<li><a href="#はじめに">はじめに</a></li>
<li><a href="#Web">Web</a></li>
<li><a href="#いわゆるアプリケーションスマホアプリPCのデスクトップアプリケーションなどあるいはゲームなど">いわゆる「アプリケーション」(スマホアプリ、PCのデスクトップアプリケーションなど)。あるいはゲームなど</a></li>
<li><a href="#スクレイピングチャットbotなど">スクレイピング・チャットbotなど</a></li>
<li><a href="#プログラミング初心者の学習用">プログラミング初心者の学習用</a></li>
<li><a href="#データサイエンス機械学習深層学習その他の科学技術計算分野">データサイエンス・機械学習・深層学習・その他の科学技術計算分野</a><ul>
<li><a href="#データサイエンス">データサイエンス</a></li>
<li><a href="#機械学習">機械学習</a></li>
<li><a href="#深層学習">深層学習</a></li>
<li><a href="#その他科学技術計算">その他科学技術計算</a></li>
<li><a href="#画像処理">画像処理</a></li>
<li><a href="#音声処理">音声処理</a></li>
<li><a href="#自然言語処理">自然言語処理</a></li>
<li><a href="#シミュレーションとか数値解析とかスパコンで走らせるようなやつ">シミュレーションとか数値解析とかスパコンで走らせるようなやつ</a></li>
</ul>
</li>
<li><a href="#その他の考慮事項">その他の考慮事項</a><ul>
<li><a href="#言語仕様など">言語仕様など</a></li>
<li><a href="#インターネット情報">インターネット情報</a></li>
<li><a href="#環境構築の容易さ">環境構築の容易さ</a></li>
</ul>
</li>
<li><a href="#まとめ">まとめ</a></li>
</ul>
</div>
<div class="section">
<h3 id="Web">Web</h3>
<p> Webで使うのはあまり流行ってないし、正直(特に国内では)たぶん流行らない。以上。</p><p> Pythonは要するに普通のLLなので、なかなかPythonならではのメリットというのは見出しづらいのが実情でしょう。この分野はPHPやNode.jsなどが強すぎるし、それ以外に強いやつもたくさんいるので<a href="#f-bbdbca3b" name="fn-bbdbca3b" title="Web向けで高パフォーマンスのコンパイル言語で書きやすいってコンセプトだけで一体いくつあるんだよ、とか">*2</a>、積極的にPythonを選ぶシチュエーションは正直思いつきません。少なくとも、Web開発を勉強したいという人が最初に勉強するべき言語ではないと思います。</p><p> ちょっと擁護しておくとすれば、「それなりに良い(であろう)実用的なフレームワークは揃っている」「Pythonを使える人にとっては、書きやすい」という側面はあるので、いつのまにか蛇使いになっていたという人がWebを勉強したくなったときにはDjangoやFlaskが助けてくれることでしょう。ニッチな需要もいろいろあると思いますし、絶対ダメというほどでもありません。</p><p> いずれにせよ、Pythonは「Web分野のトップランナー」という感じではないです。勝手な想像ですが、先頭集団の末尾くらいのポジションだと思います。扱いに困ります。</p>
</div>
<div class="section">
<h3 id="いわゆるアプリケーションスマホアプリPCのデスクトップアプリケーションなどあるいはゲームなど">いわゆる「アプリケーション」(スマホアプリ、PCのデスクトップアプリケーションなど)。あるいはゲームなど</h3>
<p> スマホアプリははっきり言って論外。実用的なものを作る方法はほぼないと思います(まったくないとも言い切れないのが苦々しいところですが、あえてこう書きます)。</p><p> デスクトップアプリケーションですが、作れなくはないです。しかし、もっと向いている言語がいろいろある(windows向けならC#あたりでいいでしょう)ので、Pythonでやろうというのはかなりの変人の選択です。</p><p> やはりPythonはスクリプト言語なので、どうやって単一exeにして持っていくか(あるいは相手のPCにPythonをインストールさせるのか)というところで躓きます。単一exeにする場合、どうしても起動が遅いし容量がやたらでかくなる<a href="#f-094ee711" name="fn-094ee711" title="インタプリタ一式持っていくので……">*3</a>みたいな欠点があります。相手のPCにPythonをインストールさせれば問題は少ないのですが、そこまでしてPythonで動かしたいものって何? という疑問が生じます。</p><p> 例外として、UNIX系でOSに組み込まれているPythonをあてにして動くツールというのは実際にたくさんありますし、作っても良いと言えます。ただ、あれはあれで良い面も悪い面もある文化なので、一概には言えない感じがしますが……そういうものを作ろうとする人はこの記事を読まないかな。</p><p> 総評としては、そういうものを作るにはデメリットが目立つ、ということになります。</p>
</div>
<div class="section">
<h3 id="スクレイピングチャットbotなど">スクレイピング・チャットbotなど</h3>
<p> この手の処理はどんな言語でもできるといえばできるのですが、最近はPythonの情報が多い気がするので、やりやすいと思います。こういうことを気楽にやるのに向いている気もします。<br />
(ただし、それなりにプログラミング慣れしている人が相応の配慮の元行うのが前提です)</p>
</div>
<div class="section">
<h3 id="プログラミング初心者の学習用">プログラミング初心者の学習用</h3>
<p> この章は特に主観的な面が強いので、そのつもりで読んでください。</p><p> まず、私は「まずはC言語でプログラミングの基礎を理解しろ」という教育を受けたので、PythonみたいなLLから入ることには否定的です。すごく高級な言語なので、初心者は何やっているのかわからないと思います。そういう部分を丸暗記して、なんとなくで書き続ければ「Python」は書けるようにはなるかもしれませんが、「プログラミング」の勉強にはあまりならないような……</p><p> というのは哲学的なことなので、もう少し現実寄りのことを書いておくと、</p>
<ul>
<li>初心者向けの親切な教材やネット情報が少ない</li>
</ul><p> 致命的</p>
<ul>
<li>独自の構文みたいなのが多い</li>
</ul><p> 内包表記とか。覚えてもPython以外で役に立たない、知らないとPythonを読めない</p>
<ul>
<li>細かいハマリどころが割と多い</li>
</ul><p> インデントが狂ったりとかlist = [[]*3]*3とか。貴重な学習時間をつまらないことで潰したくないですよね</p><p> とまあ、初心者向けの言語ではないので、おすすめしません。同じポジションならRubyとかの方がまだ良いかもしれない。</p><p> そもそも<a href="https://www.python.org/doc/essays/foreword/">GuidoがUNIXハッカー受けを狙ってクリスマスの暇つぶしに作った言語</a>なので、初心者の学習用で使われるようになるというのは想定していなかったと思います。<a href="https://docs.python.org/ja/3/tutorial/">チュートリアル</a>の冒頭を読めばわかるとおり、「玄人向け」です。</p><p> Pythonが教育で使われているという事実はありますが、ちゃんと見てくれる先生のもとで限定された機能だけを使って学習していると思われます。このあたりに関してはまったく知識がないので憶測含みですが、おそらく基本的な演算とか制御構文、関数あたりの基本的な機能を使ってプログラミングの考え方に親しんでもらう、という趣旨の『教育』ではないでしょうか<a href="#f-c72d935e" name="fn-c72d935e" title="違うよ! こんな感じだよ! というご指摘があれば大歓迎です">*4</a>。</p><p> なので、プログラミングの勉強の第一歩としてPythonを始めた/始めようとしている人は、よく考え直しましょう。とても気に入っているならやめる必要はないかもしれませんが、向いていないと思ったら他のものに切り替えた方が賢明なはずです。<br />
<br />
</p>
</div>
<div class="section">
<h3 id="データサイエンス機械学習深層学習その他の科学技術計算分野">データサイエンス・機械学習・深層学習・その他の科学技術計算分野</h3>
<p> とりあえずこの辺のジャンルをざっくりまとめてしまいましたが、当然これらはすべて別の分野です。なので、節を分けて説明します。</p>
<div class="section">
<h4 id="データサイエンス">データサイエンス</h4>
<p> さて、データサイエンスと言っても漠然としていて何がなんだかという世界なのですが、とりあえず考慮するべきなのは以下くらいでしょうか。各項目同士でオーバーラップする部分もありますし、データサイエンスに含めるかどうか悩むものとかもありますが、あまり深く考えないでください。</p>
<ul>
<li>探索的データ解析(可視化など)</li>
<li>統計処理・分析(検定、分散分析とか)</li>
<li>統計的モデリング(回帰や判別とかいろいろ……)</li>
<li>多変量解析(いろいろ……)</li>
<li>その他いろいろ……</li>
</ul><p> 手持ちのデータに対してデータサイエンス的な分析を行いたいという場合、Pythonを積極的に選択するかどうかは悩むところです。この分野には強い競合がたくさんあります。当然Excelも選択肢になりますし、SPSSのようなリッチなソフトウェアもいろいろあります。立ち位置が近いものとしてはRがあります。あとは簡単な処理ならDB叩いてSQLでやっちゃうとか、いろいろ手はあります。</p><p> Pythonの立場は、どれもできなくはないけど、最強ではないしどちらかといえば微妙……という感じではないでしょうか。Pythonで可視化しようとすると面倒くさいし、検定とか統計処理は少し一般的でないことをやろうとするとパッケージがなくて困ったりするし……</p><p> たとえばRは統計系パッケージが充実しているとよく言われます。野良実装みたいなのまで含めればそらPythonにだってあるわ(PyPIにCRANの何倍登録されてると思ってるんじゃ)……と思ったりもするのですが、さすがに大人げないですね。</p>
<ul>
<li>中堅以上の(ある程度大きな信頼できるチームでまともに開発・メンテナンスされていて、普及している)パッケージで、どれくらい色々な手法なんかが使えるのか</li>
</ul><p> という観点で見ると、たぶんRが勝るということだと思います。</p><p> まあでも、pandasは強いしstatsmodelsもあるし、メジャーな手法のライブラリはなんだかんだで探せばあるし、というかマイナーなのでも探せばなんだかんだであったりはする。どマイナーなものは別に使えなくても困らないし、最悪必要になったら自分で書く。</p><p> と割り切れば、Pythonのエコシステムですべてが完結します。同じことができるのはたぶんRだけなので、一騎打ちですね。</p><p> あとは考慮するべきなのは好み、慣れ、使いたい手法のライブラリの対応状況、他の処理との兼ね合いくらいでしょうか。積極的に甲乙つける気にはなれないので、保留します。</p><p> 特定のことをやろうとするとPythonより良いツールはあるのですが、ぜんぶできるツールとしては最高かそれに準じる立ち位置なので、データサイエンスに向いていないということはまったくないと思います。</p>
</div>
<div class="section">
<h4 id="機械学習">機械学習</h4>
<p> 深層学習は別ジャンルなので、あくまでもコンベンショナルな機械学習の話です。</p><p> 基本的にはほぼデータサイエンス関連と同じ状況。強いて言えば、データサイエンス分野ほどにはRに負けていないか、むしろ勝っている気がします。scikit-learnのエコシステムが強いのと、流行っているのと、やっぱり(機械学習畑の人たちにとって)読み書きがしやすいからでしょう<a href="#f-e8a1f4a8" name="fn-e8a1f4a8" title="でもcaret見るとscikit-learnよりいろんなモデルに対応してていいなぁとか思ったりするんですが">*5</a>。</p><p> 使いやすいし、情報も多いので、機械学習やりたければPythonというのは良い選択だと思います。</p>
</div>
<div class="section">
<h4 id="深層学習">深層学習</h4>
<p> Pythonは深層学習フレームワークのwrapperを叩く環境として、唯一無二の地位を占めています。この分野では最強です。</p><p>Q:C++から呼べばいいのでは?<br />
<b>A:いやです。</b></p><p> が通用するので、この地位は揺らがないでしょう。</p><p> 私は正直ほとんど深層学習やったことがないのですが、ここが廃れると他もガタつくと思うので、蛇使い的には深層学習屋には頑張ってほしいなぁ、と思います。</p>
</div>
<div class="section">
<h4 id="その他科学技術計算">その他科学技術計算</h4>
<p> 面倒なのでひっくるめてしまいますが、いろいろありますよね。</p>
</div>
<div class="section">
<h4 id="画像処理">画像処理</h4>
<p> OpenCVのwrapperとして使っている人を一定数見かけます。悪くない選択だと思います。ただ、あのエラーメッセージは普通のPythonユーザが読んでも何のことやらって感じなのでは?</p>
</div>
<div class="section">
<h4 id="音声処理">音声処理</h4>
<p> ほとんど話題を見かけない。</p>
</div>
<div class="section">
<h4 id="自然言語処理">自然言語処理</h4>
<p> 自然言語処理の中にもいろいろあったり、最近はそもそも半ば深層学習に吸収されていたりといった感じですが、それはさておきPythonで自然言語処理というのはよく見かけます。</p>
</div>
<div class="section">
<h4 id="シミュレーションとか数値解析とかスパコンで走らせるようなやつ">シミュレーションとか数値解析とかスパコンで走らせるようなやつ</h4>
<p> ……この辺になると畑によってまちまちだと思いますが、さすがにコンパイル言語で書くのでは?</p><p> まあ、強いライブラリ(か、そのwrapper)がある分野では使えます。あとは、numpyやscipyがあるので、気楽にアルゴリズムを書いてみるのには便利です。</p>
</div>
</div>
<div class="section">
<h3 id="その他の考慮事項">その他の考慮事項</h3>
<p> 目的別にはだいたいこれくらい挙げれば良いような気がしますが<a href="#f-b218fe80" name="fn-b218fe80" title="この辺が漏れてるよ! というご指摘は大歓迎です">*6</a>、他に考えるべきことをいくつかあげます。</p>
<div class="section">
<h4 id="言語仕様など">言語仕様など</h4>
<p> Pythonの構文とプログラミングモデルは綺麗だと思います。私個人の感想です。</p><p> 公式でPEP8というコーディング規約まで定めて、スタイルの一貫性を重視しているのも良いところです。ただ、さすがに「誰が書いても同じようなコード」は実現できていないのが現状だと思いますが<a href="#f-e88e8b9b" name="fn-e88e8b9b" title="たとえば具体的に言うと、iterable周りで選択肢が多すぎて書き手の個性が出まくる">*7</a>。それでも、そういうポリシーを掲げるというのは立派なことだと思います。</p><p> 純粋なプログラミング言語として好きになれるようなものである、ということです。LISPに通じるものがあります(でも、そういう言語はPython以外にもあるでしょう)。</p>
</div>
<div class="section">
<h4 id="インターネット情報">インターネット情報</h4>
<p> かつて(私が学び始めた頃)は、Python関係で検索すると、Python2時代の(2008年くらいの)黴の生えたような「はてなダイアリー」の記事が出てきたりして、げんなりさせられました。</p><p> 最近はそういうことはずいぶん減って、新しくて質の高い情報がよく出てくるようになったと思います。要するに流行ったおかげなのですが、情報がなく、古くて困るということは今はあまりないと思います。</p><p> あと、(順番おかしいですが)それなりにちゃんと日本語に翻訳された公式ドキュメントもあります。日本語で出てこないときでも、英語では何かしら出てくるので、最悪google翻訳に通したりして読めば問題が解決するのもいいところです。</p><p> さすがにJavaとかとは比べられませんが、ある程度の検索スキルがあれば情報がなくて困るということはそう滅多にはないと思います。</p>
</div>
<div class="section">
<h4 id="環境構築の容易さ">環境構築の容易さ</h4>
<p> Pythonは環境構築が難しいとおっしゃる方は一定数いますね。でも、たとえばWindowsなら公式からインストーラを落としてきて入れるだけです。UNIX系も基本的にはパッケージマネージャで入れるだけです。</p><p> にも関わらず「難しい」印象になってしまうのは、</p>
<ul>
<li>「他バージョンのpip叩いちゃった問題」がつきまとう</li>
<li>anacondaのせい</li>
</ul><p> 慣れてない人が使うとかえってトラブルの原因になる</p>
<ul>
<li>pyenvのせい</li>
</ul><p> 同上。</p><p> あたりの事情が絡んでいる気がします。</p><p> たぶんこの手の操作(環境構築)に慣れている人にとっては簡単だし、慣れていないと難しいはずで、でもそれはどんな言語でもたぶん同じなので、Python固有のデメリットというほどでもないかなぁ、というのが率直な感想です。ただし、IDEのインストーラを走らせればすべてが完了するような言語と比べると、自分でやることが増える分難しいというのは真実かもしれません。</p>
</div>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> 書いていて思ったのですが、無条件でPythonがファーストチョイスと言えるのは深層学習を気楽にやりたいときくらいですね。統計・機械学習などでもかなりファーストチョイスに近い位置にはいますが、Rとカチ合います。それ以外の用途だと、やはりデメリットの方が多い気がします。</p><p> よく言われていることですが、Pythonは汎用のLL言語で、気楽に書けてオールマイティに色々使えるのが強みです。それに情報工学・計算機科学系のあれこれが乗っかっているので最強に見えます。Rには、この言語でなんでもできるという汎用性は(こう言い切っちゃうとR好きの人に怒られるかもしれないけど)ありません。</p><p> こういう特性を理解して使いこなせれば素晴らしい言語ですし、漫然と勉強しても活用することは難しいのかもしれません。メリットを活かした使い方をしよう、ということですね。</p><p># ところで、メリット・デメリットって銘打ったのに、箇条書きでメリットとデメリットをそれぞれまとめるという、よくある書き方をするのを忘れた……まあいいか。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-d6835bb8" name="f-d6835bb8" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">Pythonユーザのことです、念の為</span></p>
<p class="footnote"><a href="#fn-bbdbca3b" name="f-bbdbca3b" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">Web向けで高パフォーマンスのコンパイル言語で書きやすいってコンセプトだけで一体いくつあるんだよ、とか</span></p>
<p class="footnote"><a href="#fn-094ee711" name="f-094ee711" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">インタプリタ一式持っていくので……</span></p>
<p class="footnote"><a href="#fn-c72d935e" name="f-c72d935e" class="footnote-number">*4</a><span class="footnote-delimiter">:</span><span class="footnote-text">違うよ! こんな感じだよ! というご指摘があれば大歓迎です</span></p>
<p class="footnote"><a href="#fn-e8a1f4a8" name="f-e8a1f4a8" class="footnote-number">*5</a><span class="footnote-delimiter">:</span><span class="footnote-text">でもcaret見るとscikit-learnよりいろんなモデルに対応してていいなぁとか思ったりするんですが</span></p>
<p class="footnote"><a href="#fn-b218fe80" name="f-b218fe80" class="footnote-number">*6</a><span class="footnote-delimiter">:</span><span class="footnote-text">この辺が漏れてるよ! というご指摘は大歓迎です</span></p>
<p class="footnote"><a href="#fn-e88e8b9b" name="f-e88e8b9b" class="footnote-number">*7</a><span class="footnote-delimiter">:</span><span class="footnote-text">たとえば具体的に言うと、iterable周りで選択肢が多すぎて書き手の個性が出まくる</span></p>
</div>
hayataka2049
はてなブログで自動生成されるゴミページをnoindexにする
hatenablog://entry/17680117127155601918
2019-06-23T21:01:06+09:00
2019-07-10T20:57:26+09:00 はてなブログを利用していると、様々なページが自動生成されます。よくあるのは?pageのようなURLパラメータの付いた、よくわからないページでしょうか。 (アーカイブの絡みで出ているのがわかることもありますし、完全によくわからないけど存在するページというのもあります) 世の中には、こういったページが大量に存在するとSEO上よくない、という都市伝説があります。本当か嘘かはわかりませんが、どのみち気分的に良くないのは確かなので、こんなJavaScriptを書いてみました。 <script type="text/javascript"> <!-- var noindex_regexp = /\?pag…
<p> はてなブログを利用していると、様々なページが自動生成されます。よくあるのは?pageのようなURLパラメータの付いた、よくわからないページでしょうか。<br />
(アーカイブの絡みで出ているのがわかることもありますし、完全によくわからないけど存在するページというのもあります)</p><p> 世の中には、こういったページが大量に存在するとSEO上よくない、という都市伝説があります。本当か嘘かはわかりませんが、どのみち気分的に良くないのは確かなので、こんなJavaScriptを書いてみました。</p>
<pre class="code lang-javascript" data-lang="javascript" data-unlink><script type=<span class="synConstant">"text/javascript"</span>>
<!--
<span class="synIdentifier">var</span> noindex_regexp = <span class="synConstant">/\?page=|\?q=/</span>;
<span class="synStatement">if</span>( noindex_regexp.test(<span class="synStatement">location</span>.href)) <span class="synIdentifier">{</span>
<span class="synIdentifier">var</span> head = <span class="synStatement">document</span>.getElementsByTagName(<span class="synConstant">"head"</span>)<span class="synIdentifier">[</span>0<span class="synIdentifier">]</span>;
<span class="synIdentifier">var</span> meta = <span class="synStatement">document</span>.createElement(<span class="synConstant">"meta"</span>);
meta.setAttribute(<span class="synConstant">"name"</span>,<span class="synConstant">"robots"</span>);
meta.setAttribute(<span class="synConstant">"content"</span>,<span class="synConstant">"noindex"</span>);
head.appendChild(meta);<span class="synIdentifier">}</span>
<span class="synComment">//--></span>
</script>
</pre><p> JavaScriptに詳しい方が見たら笑われるようなコードかもしれませんが、ご容赦ください。とにかくこれで、pageとqのURLパラメータがURLに含まれていれば、動的にheadにnoindexを設定できます。</p><p> これはどこに入れても機能します。少しでも読み込み速度を上げる観点からすると、デザイン設定画面からフッタに入れると良いでしょう(おまじない程度ですが)。</p><p> この状態で一ヶ月くらい運用しましたが、googleのクローラはちゃんとJavaScriptをレンダリングしてくれるようで、確かにSearch Consoleを見ると狙ったようなページがnoindexになっています。なお、特段のSEO上の効果は今のところ実感できていませんが、デメリットも特になさそうなので設定しておいても良いのではないでしょうか。</p>
hayataka2049
teratailでのプログラミング初心者の質問の仕方
hatenablog://entry/17680117127165148782
2019-06-22T23:50:31+09:00
2019-08-05T14:48:43+09:00 はじめに teratailはプログラミングで生じた疑問を投稿すると、他のユーザーに回答してもらえる、便利でプログラミング初心者の方にとってはとても心強い味方になり得るサービスです。 一方で、「使い方がわからない」「どんな質問をすればいいの?」「こんな内容で投稿していいのか不安」という人も多いと思います。また、中には「質問したけど回答がつかなかった」「質問に低評価がついて心が折れた」「コメント欄で文句を言われた」という人もいることでしょう。 そこで、プログラミング初心者の方向けに「どんな風にteratailを使えばいいのか」を軽くまとめておきます。 なお、少し自己紹介しておくと私は普段回答者とし…
<div class="section">
<h3>はじめに</h3>
<p> teratailはプログラミングで生じた疑問を投稿すると、他のユーザーに回答してもらえる、便利でプログラミング初心者の方にとってはとても心強い味方になり得るサービスです。</p><p> 一方で、「使い方がわからない」「どんな質問をすればいいの?」「こんな内容で投稿していいのか不安」という人も多いと思います。また、中には「質問したけど回答がつかなかった」「質問に低評価がついて心が折れた」「コメント欄で文句を言われた」という人もいることでしょう。</p><p> そこで、プログラミング初心者の方向けに「どんな風にteratailを使えばいいのか」を軽くまとめておきます。</p><p> なお、少し自己紹介しておくと私は普段回答者としてteratailを利用しており、teratailのPythonタグで総合一位を持っています(2019年6月2日現在)。</p><p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190602/20190602002802.png" alt="証拠" title="f:id:hayataka2049:20190602002802p:plain" class="hatena-fotolife" itemprop="image"></span></p><p><a href="https://teratail.com/users/hayataka2049#reply">私のプロフィールページ</a></p><p> 思わず回答したくなるような素晴らしい質問も、思わず回答したくなくなる駄目質問も数えきれないほど見てきたので、以下の内容もそれほど間違ったことは書いていないつもりです。回答する側の立場として、こうしてくれたら嬉しいな! ということを書きますので、ご一読いただければと思います。</p><p> また、teratailの公式のヘルプページもできれば質問する前に読んでおいてください。</p><p><a href="https://teratail.com/help">ヘルプ|teratail(テラテイル)</a></p><p> 特に、「質問するときのヒント」は必見です。質問する方全員がこれを読んでくれていたら、と思うときがたまにあります。</p><p><a href="https://teratail.com/help/question-tips">質問するときのヒント|teratail(テラテイル)</a></p><p> この記事も、基本的にはこれらの記述に準拠した上で、回答者として日頃から思っていることを織り交ぜて書いています。ヘルプと重複する部分も多いので、時間のない人はこの記事を読まないで公式のヘルプだけ読んでいただくというのも一つの選択です。ただ、回答している人たちの考えていることを知りたいな、という人は、以下を読んでいただければスムーズなコミュニケーションにつながると思います。</p>
</div>
<div class="section">
<h3>どんなところなの?</h3>
<p> この記事を読んでいる人は、あまりteratailというサービスについて詳しくないと思うので、大まかな概要を先に説明します。</p><p> が、この記事を読み進める前に、まずは</p><p><a href="https://teratail.com/tour">3分でわかるteratail|teratail(テラテイル)</a></p><p> を一読してみてください。基本的な前提はこれで把握していただいて、補足的なことを中心にこの記事で書いていこうというつもりです。</p><p> ……さて、読んでいただけたでしょうか。では、説明してまいります。</p>
<div class="section">
<h4>どれくらい流行ってるの?</h4>
<p> 日本語圏のプログラミングQ&Aサービスでは、かなり活発に動いているところだと思います。一日に数百件程度は質問が投稿され、9割には回答がついています。</p><p> 他のQ&Aサービスとしてはスタック・オーバーフローもありますし、Qiitaで聞く、あるいはヤフー知恵袋や2ch,、Twitterで聞くという手もありますが、総合的な回答の得られやすさではteratailはかなり上位に位置するでしょう。</p>
</div>
<div class="section">
<h4>そもそも初心者が質問していいの?</h4>
<p> こういう疑問を持っている人も多いと思います。ページタイトルにも思いっきり「ITエンジニア特化型Q&Aサイト」って書いてありますし、現時点でITエンジニアではない人間が使って構わないのか? と思う人も多いですよね。</p><p> 確かに、運営がITエンジニア特化をうたっていることは事実です。ついでにいえば、少し前までは「思考するエンジニアのためのQAプラットフォーム」と銘打っていました。おそらく、本来目指していた方向性はそういうものだったのでしょう。</p><p> しかし、だからといって非エンジニアはお断り状態なのかというと、それも違います。実際にプログラミングに不慣れとおぼしき方の質問も多いですし、そういった質問にも親切な回答がつくことが多いです。ついでに言えば、私も現役のエンジニアではなく、学生の身分のまま一年以上回答していますが、それが問題になったことはありません。</p><p> 割と敷居の低いサイトですし、初心者質問であっても丁寧なものであれば歓迎されている、というのが私の個人的な肌感覚です。なので、プログラミング初心者の方でも遠慮せずに使って良いと思います。</p>
</div>
<div class="section">
<h4>なんでも聞いていいの?</h4>
<p> プログラミングに直接関連することであれば、基本的には何を聞いても構いません。</p><p> ただしある程度は制約があって、無条件でおすすめできるのは「エラーが出た」「思い通りに動かない」「こう書いてみたけど、あまりにも冗長なので書き換えたい。そのやり方がわからない」といったあたりまでです。要するに、コードを書いていて行き詰まったことを聞きましょう。</p><p> 「おすすめの書籍を教えてください」「プログラミングを勉強したいけど、おすすめのスクールは?」「エンジニアとしてのキャリアの積み方」みたいな質問はあまり推奨されていませんし、荒れる傾向にあります。</p><p> 自分の聞きたいことがそういったジャンルに該当するかも、と思う人は、投稿する前に下記のページを一読していただいた上で、投稿するかどうかを判断していただければ良いと思います。</p><p><a href="https://teratail.com/help/avoid-asking">推奨していない質問|teratail(テラテイル)</a></p><p> また、最短距離で解決したい場合は、teratailで質問するより良い方法がある場合があります。たとえば、マイナーなライブラリを使っていてそのバグっぽい挙動に悩まされたら、teratailで聞くよりは、そのライブラリのgithubのページを探してissueを投げた方が良いです。開発に使っている製品のサポートセンターがある場合は、そちらに先に問い合わせましょう。一般的なteratailユーザにとって回答が難しい質問は、そういったところを案内されて終わるパターンもあります。</p>
</div>
<div class="section">
<h4>気軽に質問していいの?</h4>
<p> これについては、「気軽に」の程度が人によって大きく異なるので一概に言えません。</p><p> ですが、できれば質問する前に自力で解決する努力をしてほしい、というのが全回答者ユーザの総意だと思います。で、いろいろ試行錯誤したこと、調べたことを質問文に具体的に書いてくれるのが理想的です。</p><p> 「タイプミスですね」とか「そのエラーで検索すると一番上にヒットする対処で解決しますね」みたいなのもたまにありますが、こういうのは時間の無駄ですし、虚しいです。</p><p> それと、質問する人の中には、teratailで短時間で疑問が解決したのに味を占めて、毎日のように「ちょっと考えればわかるだろ、それ」という質問を出すようになる人もいます。これは当然ながら迷惑ですし、自身の成長にも繋がりません。節度を守って利用しましょう。</p>
</div>
<div class="section">
<h4>回答者はなんでわざわざ回答してるの?</h4>
<p> これ、謎ですよね。私もよくわかりません。2400件以上答えてるのに。</p><p> もちろん人助けをしたいというのが基本的な動機でしょう。ボランティアです。また、回答する人も昔は初心者でいろいろな人に助けてもらった訳だし、インターネットの情報は今でも日々使っているでしょうから、恩返し的な意味で回答している、という側面もあるでしょう。</p><p> また、teratailでは色々な技術的な話題が交わされます。回答者をやっていると勉強になるのは事実です。私がはじめた理由はこれでした。</p><p> teratailで高い順位・スコアを誇っていれば転職などで活用できるという側面もありますが、これについてはあまり話が表に出てこないのでなんとも言えない面があります。でもまあ、そのためだけにやっている人というのもいないでしょう(自作のアプリケーションやWebサイトを作ったり、OSSで貢献した方が効率は良いでしょう)。</p><p> あるいは、知識自慢とか、マウントの取り合いのつもりなのかもしれません。そういう人も中にはいると思います。いわゆる「教えたがり君」ですね。</p><p><a href="https://ja.uncyclopedia.info/wiki/%E6%95%99%E3%81%88%E3%81%9F%E3%81%8C%E3%82%8A%E5%90%9B">https://ja.uncyclopedia.info/wiki/%E6%95%99%E3%81%88%E3%81%9F%E3%81%8C%E3%82%8A%E5%90%9B</a></p><p> それか、単なる暇つぶしとか娯楽、と答える人もいるかもしれません。</p><p> ……とまあ、いろいろな人がいると思います。(わざわざ節を立てて論じておいてなんですが)、いちいち考えるのは無駄ですので、気にしないほうが良いです。</p><p> 建前上は善意で回答しているということになっています。建前は尊重した方が安全なコミュニケーションが取れます。</p>
</div>
</div>
<div class="section">
<h3>使う上でのマナー</h3>
<p> さて、できれば「これくらいは守ってほしい」というマナーについて書いておきます。と言ってもそんなに押し付けがましいことを書くつもりはなく、質問者と回答者が快く、スムーズに問題を解決するための「マナー」です。</p><p> 一般的なネチケット、Q&Aサイトの利用方法は当然守ることを前提としています。その上で、特にteratail特有の事情について書いておきます。</p><p> ここでいうマナーとは私が勝手に決めたものではなく、おおむね以下に準拠します。<br />
<a href="https://teratail.com/help/question-tips">質問するときのヒント|teratail(テラテイル)</a><br />
<a href="https://teratail.com/help/avoid-asking">推奨していない質問|teratail(テラテイル)</a><br />
</p>
<div class="section">
<h4>質問する前に自力で解決できないか頑張る</h4>
<p> 基本的なことですが、質問する前にできるだけ自分で解決するように試みてほしいです。</p><p> ここで言っているのは、</p>
<ul>
<li>タイプミスしていないか確認する</li>
<li>言語やライブラリの公式マニュアルを見て使い方が間違っていないか確認する</li>
<li>エラーメッセージが出たらそれで検索して、出てくるサイトを読む。英語のサイトが出てくるかもしれないが、google翻訳を使ってでも読む</li>
</ul><p> というレベルの内容です。また、可能な範囲でできるだけデバッグしてください。<br />
(そういう努力の形跡が見られない質問が多すぎて、私が個人的に疲弊していることの裏返しでもあります。)</p><p> 実は、本当にどうしようもない質問だと5分くらいで解決したりすることもあるのですが、そういうのは質問者も回答者も互いに虚しいし、無益です。質問する人にとっては自力で解決するスキルが鍛えられませんし、回答する人はあまりにそういうのが多いと疲れます。</p><p> 行き詰まったら1時間は頑張ってみて、どうしても駄目なら10分くらいはかけて丁寧に質問を書く、というのが個人的にはいい塩梅だと思います。</p>
</div>
<div class="section">
<h4>最低限Markdownを使いこなす</h4>
<p> teratailはMarkdownに対応しています。Markdownという言葉を初めて聞いた人も多いと思いますが、これは「特定の書き方をすると、綺麗な見栄えに変換されて投稿される」という機能です。</p><p> Markdownはとても多機能なので、完璧に使いこなす必要はありません。ただでさえプログラミングの勉強で忙しいのに、Markdownの使い方まで学ぶ暇はないという人もいるでしょう。</p><p> ただし、teratailのシステムの仕様上、残念ながらMarkdownをまったく知らない人は「そもそもまともに質問できない」可能性が高いです。そういうシステムなので仕方ありません。</p><p> 以下に示す最低限のものは覚えて使ってください。数分で読み終えて理解できるはずですし、それで質問する側も回答する側も気分よく利用できるのですから、知っておいて損はありません。</p>
<div class="section">
<h5>コードはコードブロックの中に入れる</h5>
<p> 回答者にとって、質問者に守ってほしいであろうマナーNo.1です。</p><p> プログラムを直接質問に書くと、とても見づらい表示になってしまいます。</p><p><figure class="figure-image figure-image-fotolife" title="コードブロックを使わなかった例"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190602/20190602010559.png" alt="コードブロックを使わなかった例" title="f:id:hayataka2049:20190602010559p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>コードブロックを使わなかった例</figcaption></figure></p><p> インデントが潰れてしまうのと、# から始まるコメント行が見出しのMarkdownとして解釈されてしまうのが主な問題点です。他にも、Markdownとして解釈され得る記法があれば、そのまま表示されないことがよくあります(たとえばPythonの__init__などは斜体(イタリック)として解釈されます)。</p><p> こういうコード部分はコードブロックを使ってください。</p><p><figure class="figure-image figure-image-fotolife" title="コードブロックを使った例"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190602/20190602010934.png" alt="コードブロックを使った例" title="f:id:hayataka2049:20190602010934p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>コードブロックを使った例</figcaption></figure></p><p> コード部分の上下に```と書くだけです(キーボードが日本語配列なら半角モードでShift+@で入力できると思います)。なお、開始の```と終了の```は、基本的にはそれだけで一行になるようにしてください。余計な文字やスペースを入れるとうまく表示されないことがあります(後述の言語名は例外です)。</p><p> 手で打ち込むのが面倒くさい場合は、質問入力画面の<code>ボタンを押せば挿入できます。こちらでコードブロックを挿入してから間にペーストするか(繰り返しますが改行に注意)、先にコードを貼り付けてからコード部分を選択して<code>ボタンを押してください。</p><p> なお、上側の```の右側には言語の名前を入力できます。<code>ボタンで挿入した場合は、「ここに言語を入力」というテキストがデフォルトで入っていると思います。これについては、そのままでも、単に消しても構いません。また、これを消して代わりにpythonとか、C、Javaといった言語名を書けばそれに応じてシンタックスハイライトが付きます。</p><p> また、コードの他にも「エラーメッセージ」「CSVデータ」などもコードブロックの中に入れることをおすすめします。やはりそうしないと見づらくなるからです。</p>
</div>
<div class="section">
<h5>「文章中のコード」機能を使う</h5>
<p> こちらは上のコードブロックに比べると使う頻度が低いですが、``で囲むと行の中にコードを挿入できます。変数名や関数名などで使ってもいいでしょう。</p><p> また、変数や関数などの名前がMarkdownとして解釈されてしまってうまく書けないというときは、この機能を使う必要があります。</p><p><figure class="figure-image figure-image-fotolife" title="「文章中のコード」機能の使用例"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190602/20190602013137.png" alt="「文章中のコード」機能の使用例" title="f:id:hayataka2049:20190602013137p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>「文章中のコード」機能の使用例</figcaption></figure></p>
</div>
<div class="section">
<h5>見出しや水平線など</h5>
<p> これらは上のコードブロックと比べるとそれほど重要ではありませんが、必要に応じて活用してください。</p><p><figure class="figure-image figure-image-fotolife" title="見出しと水平線の例"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190602/20190602013748.png" alt="見出しと水平線の例" title="f:id:hayataka2049:20190602013748p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>見出しと水平線の例</figcaption></figure></p>
</div>
<div class="section">
<h5>Markdown総評</h5>
<p> とにかく、コードブロックだけは使ってくれ、というのが回答者の総意です。使われていない質問には修正依頼(後述)が飛ぶことも多いです。</p><p> また、せっかくMarkdownを使っていても、残念ながら失敗してうまく表示されていない質問もたまに見かけます。そのあたりは、プレビューを見ながら調整しましょう。</p><p> よりMarkdownについて詳しく知りたい場合は、</p><p><a href="https://teratail.com/help#about-markdown">対応しているMarkdownの機能を知りたい | ヘルプ | teratail(テラテイル)</a></p><p> を参照してください。<br />
<br />
</p>
</div>
</div>
<div class="section">
<h4>状況を再現できるだけの情報を示す</h4>
<p> 質問文の状況が再現できない、という質問も多いです。</p><p> 回答する人は、何十行もある長いコードを先頭から読んで、頭の中で動作を追いかけている訳ではありません。とりあえず手元の環境でコードを実行し、エラーやバグに関係ありそうな箇所を中心に見ています。なので、エラーになった・思い通りにならなかった状況が再現できないコードはとても困ります。</p><p> どういう点に注意するといいのかというと、だいたい以下の点です。</p>
<ul>
<li>OS, 言語, 開発環境, ライブラリなどのバージョンは明記する</li>
</ul><p> これは最低限守ってほしいところです。だけど、これがなくても解決できる質問はあるし、逆にこれだけではぜんぜん情報が足りない質問もあります。ケースバイケースです。</p>
<ul>
<li>コードは可能ならエラー原因箇所だけ抜き出して、そのままコピペすれば実行可能な状態で貼り付ける。難しければ、全体を示す</li>
</ul><p> 状況を再現できるミニマムなコードを掲載するのが一番ですが、それが難しい場合は実行可能な状態にして貼ってください。エラーが出ている関数のコードだけ、といった方法で載せる方がよくいますが、検証が難しくなります。</p>
<ul>
<li>入出力のあるコードの場合は、それを載せる。入出力データが必要なら貼る</li>
</ul><p> CSVを読み込んで動かすコードなのに、入力のCSVが示されていないというのが、一番よくある困ったパターンです。また、CSVはテキストエディタで開き、コピペする形で「テキスト」として貼り付けてください(エクセルのスクリーンショットなどを載せる人もいますが、とても扱いづらいです)。ただし、著作権の都合や機密情報が含まれているなどで掲載が難しい場合は、同様の状況を再現できるダミーデータを示すようにします。また、データ量が多い場合などは外部のアップローダー等にアップしてリンクを貼る形で掲載します。</p>
</div>
<div class="section">
<h4>コード、エラーメッセージは省略せずに示す</h4>
<p> 上の内容とも被りますが、コードやエラーメッセージを省略される方がよくいます。エラーが出た行だけ、エラーメッセージの最後の一行だけ、とか。</p><p> コードは問題の本質を残した上でできるだけ短くしていただくのが理想的です。難しければ、実際に書いていて詰まったコードをそのまま載せても構いません。読むのが大変になりますが、省略されてエラー原因箇所がわからなくなるよりは助かります。</p><p> また、エラーメッセージは必ず「全文」示してください。最後の一行だけ載せる人もよくいますが、検証が難しくなります。エラーメッセージにはエラー原因の詳細な情報が含まれているので、できれば全部見たいのです。</p><p> なお、コードやエラーメッセージに、ユーザ名、APIのID&キーなど、公開したくない・してはいけない情報が載っている場合があります。そういった部分は、貼り付ける前に必要に応じて一括置換して頂いても構いません。</p>
</div>
<div class="section">
<h4>できるだけ情報を整理する</h4>
<p> 情報を整理してください。読みづらい質問は回答もつきづらいです。</p><p> と大雑把に書いてしまいましたが、こんなこと言われてもと思う方が大半でしょう。私もこう言われたら困惑すると思います。</p><p> どんな情報が必要なのかはケースバイケースですが、</p>
<ul>
<li>必要なことが伝わって</li>
<li>簡潔で</li>
<li>わかりやすくい</li>
</ul><p> 質問は、そうではない質問より良いに決まっています。だから、文章構成とかにはそれなりに気を使ってください。回答する人もやっている作業ですから、同程度の労力は割いていただくのが妥当だと思います。</p><p> コードをコピペするだけして30秒くらいで投稿したんだろうな、という質問もみかけますが、見ていて悲しくなります。どうせ投稿してから30分くらいは回答が来ない可能性の方が高いです。投稿を急ぐよりは、質問内容を充実させた方が良い結果を産みます。</p><p> ものによっては、質問を整理している間にひらめいて問題が解決したりします。</p>
</div>
<div class="section">
<h4>質問タイトルに気を配る</h4>
<p> 質問タイトルはできるだけ検索性を意識してつけましょう。ひどいのだと「Python エラー」みたいなタイトルで投稿している人が、実際にたくさんいます。タイトルを見て何の質問だかわからない、という質問を増やさないでください。</p><p> どうしても良いタイトルが思いつかなかったら、エラーが出ている場合はエラーメッセージをタイトルにしてしまうというのが奥の手です。エラーメッセージがあれば問題を特定することはできるし、エラーで検索する人はたくさんいます。でも、これは積極的におすすめはしません。</p>
</div>
</div>
<div class="section">
<h3>質問した後の対応</h3>
<p> Q&Aサイトは質問して終わり、ではなく、当然ながら質問した後が本番です。予想もしなかったような回答がつくこともありますし、回答するには情報が足りないから追記してくれ、というリクエストが来ることもあります。</p>
<div class="section">
<h4>たまにはチェックする</h4>
<p> 基本的に、回答などがつけば登録したメールアドレスに連絡が行くはずです。また、teratailのサイト上でも通知が出ます。</p><p> 半日おきくらいにはチェックするようにしてください。あまり長時間スルーされると回答者も気になります。</p><p> たまに質問しっぱなしでその後一切の音沙汰がない人もいますが、なんのために質問したのだろうと思ってしまいます。もしかしたら自己解決しているのかもしれませんし、回答だけ見て「なるほど」と思って放置しているのかもしれませんが、自分で投稿した質問は自分の責任で適切な状態に保ってください。ベストアンサーにふさわしい回答がついて問題が解決したらベストアンサーに選ぶ、自己解決できたら自分で回答を付けて自己解決という扱いでクローズする。ということです。</p>
</div>
<div class="section">
<h4>追記・修正依頼がついたとき</h4>
<p> teratailには質問に対して追記・修正などを依頼する機能があります。<b>ここについたコメントは回答ではありません。</b></p><p><figure class="figure-image figure-image-fotolife" title="追記・修正依頼欄"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190602/20190602213907.png" alt="追記・修正依頼欄" title="f:id:hayataka2049:20190602213907p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>追記・修正依頼欄</figcaption></figure></p><p> 大抵は「これを試してみてくれ」「こういう情報がないと回答しづらいので、追記してくれ」といったコメントが付くと思います。そういった場合は、(新たに何かを実行する必要があれば実行して結果を確認したあとに)質問を編集して情報を追加してください。</p><p> 追記・修正依頼欄での返信で情報を追加される方もいますが、この欄はデフォルトでは折り畳まれていて、多くのユーザの目には触れません。あくまで質問の修正で対応するのがベストです。<br />
(質問の修正だけでも通知を飛ばせますが、「質問文に追記しました」といったコメントをこちらに書いていただいても構いません。そうしなくても特に問題はありません。)</p><p> また、teratailには評価という機能があり、あまりにひどい質問・回答には「低評価」がつきます。普通に使っていればそうそうお目にかかれないものですが、もしついてしまったら自分の投稿を省みて、直せる部分があれば直しましょう。<span style="font-size: 80%">たまに嫌がらせ的につくこともあるので、省みても悪い点が見当たらなければスルーしても大丈夫です。</span><br />
</p>
</div>
<div class="section">
<h4>解決したら質問をクローズする</h4>
<p> 適切な回答がついて疑問・行き詰まりが解消したら、ベストアンサーを選んで質問を閉じてください。</p><p> また、質問してから自己解決した、修正依頼欄のやり取りで解決してしまった、というケースもたまにあります。こういう場合は、自分で回答を付けてベストアンサーにし、自己解決としてクローズする機能がありますので、それを使ってください。自己解決にする場合は、問題を解決するための情報を自分でつける回答に含め、後から検索などでたどり着いた人が困惑しないようにします。</p>
</div>
</div>
<div class="section">
<h3>質問は自分ひとりのためにあるものではない</h3>
<p> ここまで読んできた人は、なんかこいつ面倒くさいこと言っているなーと思ったと思います。自分で読み返してみてもそう思っているので、正常です。</p><p> 「わからないことを聞きたいだけなのに、なんでこんな面倒くさいことをしないといけないの」と当然思われるはずですが、teratailはインターネット上のサービスです。あなたの投稿した質問が無事に解決すれば、将来において同じような問題を抱えている人の役に立つかもしれません。具体的に言うと、google検索で引っかかります。</p><p> だから、後から見る人の役に立つようにしよう、という発想が大切です。要するに、質問というのはちょっとしたレポートみたいなものなのです。</p><p> だけど、後から見る人まで意識した質問をする、ということができる人は実際問題として少ないし、そういう人はこの記事を読まなくても良いでしょう。初心者にはかなり高いハードルなので、そこまでの条件は万全に満たせていなくてもいいかな、と個人的には思っています(たまたま役立てば結果オーライ、程度)。</p><p> 最低限越えないといけないハードルは、teratailのコミュニティのメンバー全員にとって多少は有益な投稿である、ということだと思います。つまり、回答した人が最終的に「わざわざ回答してよかった」「自分の投稿が役に立ったみたいでよかった」と思えるような質問をする、というあたりです。互いに気分よく使える、というのは大切なことですから。</p><p> そのために何が必要か? というと、けっきょくは常識的な丁寧さ、誠実さだと思います。陳腐な言葉で説教じみていて恐縮なのですが、そういうことが伝わるかどうかが「駄目質問」と「ちゃんとした質問」の分かれ目かな、と思います。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> teratailで一年以上回答を続けた人間として、どんな質問が嬉しいのか、逆にどんな質問だと回答する気が失せるのか、ということを考えながら書いてみました。見直してみたら公式のヘルプをほぼなぞった内容になってしまった感もあり、少し落胆しています(というか、公式のが異常によく出来ている。ちゃんと読みましょう)。</p><p> 要約して言えば、</p>
<ul>
<li>質問する前に数十分程度は自分で頑張れ</li>
<li>質問するなら再現性を確保しろ</li>
<li>体裁を整えろ</li>
<li>投稿したからには責任を持て</li>
</ul><p> という感じでしょうか。これらは、プログラミング初心者の方でも注意を払えば十分実行できる程度のことだと思います。もちろん、ちゃんとやろうとすると手間は増えるのですが、その手間のおかげでいい回答がつくこともある(ちゃんと丁寧に投稿している質問者には普通は好感が持たれる)ので、損にはならないと思います。ぜひ実行してください。</p><p> 最後に、もしかしたらこの記事を読んだ方とteratailでお会いすることがあるかもしれません。そのときは、よろしくおねがいします。</p>
</div>
hayataka2049
技術ブログを書く意味について考えてみる。250記事目なので。
hatenablog://entry/17680117127193488497
2019-06-21T22:02:11+09:00
2019-09-01T22:24:55+09:00 はじめに 当ブログが250記事に達したので、振り返りを書こうと思いました。 といっても別に書くこともそれほどないので、ついでにこれから技術ブログを書こうと思っている人向けに、「なんのために書くのか」「書く意味あるのか」みたいなふわふわした話についても少し触れようと思います。たまにはいいやと思って。 なお、ここでいう「技術ブログ」は「主にプログラミングなどをテーマとした、ノウハウや問題解決手順などを中心に記載しているブログ」のことです。機械工学とかで書いても技術ブログは技術ブログに違いないと思うのですが、あまり見かけないし、私もそれについて語れる知識はないので除外します。 当ブログの歴史 201…
<div class="section">
<h3>はじめに</h3>
<p> 当ブログが250記事に達したので、振り返りを書こうと思いました。</p><p> といっても別に書くこともそれほどないので、ついでにこれから技術ブログを書こうと思っている人向けに、「なんのために書くのか」「書く意味あるのか」みたいなふわふわした話についても少し触れようと思います。たまにはいいやと思って。</p><p> なお、ここでいう「技術ブログ」は「主にプログラミングなどをテーマとした、ノウハウや問題解決手順などを中心に記載しているブログ」のことです。機械工学とかで書いても技術ブログは技術ブログに違いないと思うのですが、あまり見かけないし、私もそれについて語れる知識はないので除外します。</p>
</div>
<div class="section">
<h3>当ブログの歴史</h3>
<ul>
<li>2016年12月</li>
</ul><p> 血迷って始める。</p>
<ul>
<li>2017年 3月</li>
</ul><p> 飽きて放置。</p>
<ul>
<li>2018年 1月</li>
</ul><p> 久しぶりにログインしたら想像よりはるかにPVが伸びていた(平日で200PVくらい)。<br />
書きたいネタがいくつか出てきたので、あと過去記事を「まとも」な内容に直す必要を感じたので、再開。</p>
<ul>
<li>2018年 4月</li>
</ul><p> あと数倍程度アクセスが伸びれば、広告で小遣いが稼げることに気づく(この時点で平日一日700PV程度)。</p>
<ul>
<li>2018年10~11月</li>
</ul><p> 独自ドメインにしてグーグルの広告を首尾よく張り始める。</p>
<ul>
<li>2018年12月~2019年2月</li>
</ul><p> 大学生の卒研追い込み特需などでアクセスが最盛期をむかえる。最高で一日2900PVくらい。</p>
<ul>
<li>2019年 3月~</li>
</ul><p> 特需の終焉、グーグル検索のアルゴリズムアップデート、遅れてやってきた独自ドメイン化の副作用などによりPVが減少(平日一日1500PV前後)。<br />
やる気にむらが出てきて、一気にまとめて更新したり、数週間触らなかったりするようになる。</p>
<ul>
<li>2019年 6月~</li>
</ul><p> なんだかんだで平日の平均PVが2000強くらいまで回復したので、もう少し頑張ることにした(というかする。19日にもなって書く6月最初の記事がこれという時点で、察してください)。</p>
</div>
<div class="section">
<h3>感想</h3>
<p> 割と気まぐれと成り行きで更新しているブログなので、あまり大げさな感慨みたいなものはないのですが、とりあえずやっていてよかったと思います。ブログのネタにするべく色々なことに挑戦して勉強できた側面もあるし、大した額ではないとはいえ広告でお金が降ってくるのもありがたい話です。</p><p> 大半の記事は去年くらいに書いたのですが、今見返すと「なんでこんながむしゃらにやっていたんだろう」という感じもします。そのときはそうするのが楽しかったから、としか言いようがないのだと思いますが、へんな感じです。</p>
</div>
<div class="section">
<h3>技術ブログを書く意味</h3>
<p> 積極的に肯定できない感触。</p>
<ul>
<li>勉強になるとか転職活動に活かせるとかそういうメリットは結果論的に言えるだけで確実なことは言えないし、</li>
<li>やるならqiitaとかでやった方が孤独感がなくて楽しいはずだし<a href="#f-d37c06c2" name="fn-d37c06c2" title="逆に無駄に人と絡むのが苦痛、という人にはブログが向いています">*1</a>、</li>
<li>広告? そんな儲かる訳ないじゃん(趣味をやると費やした時間の1/3くらいのコストがお金として戻ってくるくらいの感覚)</li>
</ul><p> じゃあなんでやるのかという話になりますが、</p>
<ul>
<li>プログラミングの神に「私の真実の教えを述べ伝えよ」と言われた</li>
</ul><p> これはあり得る。私は神に会ったことないけど。</p>
<ul>
<li>世間に役立つ情報を提供しようという功名心、あるいは親切心</li>
</ul><p> 長年やっている人はそういうところに帰着する可能性が高いと思います。</p><p> 功名心はわかりやすいと思いますが、親切心というのはべつに善行を積むのがどうこうという訳ではなく、普段からインターネットの情報に助けられている側面はたくさんあるので、フリーライドするのではなく多少は世界に貢献もしておこうということだと思います。そういう意味では、やりがいのある仕事をしている人はブログをやる可能性が低いかもしれません(仕事で世界に貢献できるので、わざわざインターネット社会に貢献しなくてもいい)。</p><p> まあ、やる意味なんてよくわからないね、というのが率直なところです。タイトルを先に決めてから書いてるから、大した内容が思いつかなかった。ごめんなさい。</p>
</div>
<div class="section">
<h3>250記事書いてきて思う技術ブログをやる上で気をつけた方が良いこと</h3>
<p> このままだと内容が薄い記事になりそうだったので、一章追加しました。思いついた雑多なことを淡々と書いていきます。もし参考になれば幸いです。</p>
<div class="section">
<h4>読む人がいるか、読んだ人の役に立つのかも考える</h4>
<p> 誰も読まない記事はあっても仕方ないし、読んでも役に立たない記事はゴミです。</p><p> 自分が詰まったところとか、自分にとってわかりづらかったところとかを書いて、同じようなことで問題を抱えている人がたどり着けるような検索性を確保しておく必要があります。記事のタイトル、本文、エラーの載せ方など、それなりにいろいろ気を配る必要があります(検索して1ページ目に出てくるサイトを手本にすればいい)。</p>
</div>
<div class="section">
<h4>どれぐらいニッチなテーマで書くのかを考える</h4>
<p> 技術ブログに関しては、</p>
<ul>
<li>需要がたくさんあって、だけどみんなが同じようなネタのページをたくさんを書いているテーマ</li>
<li>需要は少ないけど確実にあって、でもほとんど誰も書いていないテーマ</li>
</ul><p> の2つあると思っています。もちろん「需要がある割に書かれていないテーマ」は美味しいし「需要がないわりにたくさん書かれているテーマ」はまずい訳ですが、インターネットの無料記事といえども何らかの需給曲線があってある程度は均衡しているはずです。</p><p> 前者は初心者向けの入門サイトとか、著名言語・ライブラリの解説などが当てはまります。後者はニッチな言語だったりライブラリ、環境なんかに関する記事や、一つのエラーメッセージに絞って説明するといった記事です。</p><p> で、みんなが書いているのと同じような内容を自分で書いても誰も幸せにならない可能性が高いので、普通は後者の方を狙った方が良いでしょう。</p><p> ただし、以下の2点には注意してください。</p>
<ul>
<li>需要がたくさんあるジャンルで書いて、SEOとか頑張ってgoogle検索で上位表示されるようになると、アクセスが山ほど来ます。</li>
</ul><p> 適切な処置を取るとお金に変換できます(広告貼っても良いし、フリーランスの人なら営業に使っても良いし)。でも効率よくやるのは難しい。</p>
<ul>
<li>ニッチすぎるジャンルだと心が折れたりします。残念ながら、書き手には「一週間に1PVしかアクセスを集めない記事」の価値は認識できない可能性が高いです。</li>
</ul><p> 毎週1人を確実に救っているとしてもです。だから、割り切ってまとまった需要のある記事(毎日アクセスがある程度には)を書くのも大切です。</p>
</div>
<div class="section">
<h4>収益化するのかしないのかも(そういう邪念が頭をよぎってしまった人は)考える</h4>
<p> 最初から収益度外視でやる人は考えなくて良いのですが、お金儲けを検討している人は気にしてください。</p><p> まず、本業は絶対無理です<a href="#f-d6875b47" name="fn-d6875b47" title="試算しても、5000記事以上書けばなんとか食えるかな? というレベルです。そんなに書ける技術力があるなら、普通に働けばいいのに">*2</a>。副業としても、割には合わないというか他に良い方法がある可能性が高いです。あくまで趣味をやると多少お金がもらえるという認識で取り組んでください。</p><p> で、独自ドメインで運営すると広告を貼って収益を生めます。私ははてなブログでブログを作ってしまいましたが、あとあとのことを考えるとwordpressかなにかで作った方がメリットがたくさんあることでしょう。</p><p> 逆にはてなとかのサブドメイン(無料で作れるブログ)でやっている限り、広告を貼ってお金を稼ぐのはかなり難しいし(各ASPが独自ドメインでないと登録しづらい仕様なので)、qiitaで投稿するなら最初から諦めることになります。</p><p> ただし、あまりにアクセスが少ないと収益を得ようと思っても旨味が少なすぎて無意味というか無理なので(ドメイン代+サーバ代で赤字とか)、ある程度は考える必要があります。</p><p> 平均して1記事1日あたり10PVくらい稼げていれば、それなりに意味のある金額が生まれてくるかもしれません。200記事書けば、googleアドセンスでやるとして、毎月1万円くらい振り込まれてくることでしょう(ちなみに、googleアドセンスでは月間の儲けが8000円未満だと支払いが翌月に繰り越されます。翌月分と合わせても8000円未満なら合わせて翌々月に繰り越されます。だから、毎月支払いが生じるくらいを最低ラインとして考えないと、心が折れると思います)。</p><p> 広告についてはこちらも御覧ください。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2018%2F12%2F02%2F095348" title="プログラミングのブログにアドセンスを貼る話 - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2018/12/02/095348">プログラミングのブログにアドセンスを貼る話 - 静かなる名辞</a></p><p></p>
</div>
<div class="section">
<h4>飽きたり心が折れたりしたら放置する</h4>
<p> ぜったい更新しなきゃいけないというものではないので、やる気がなくなったらブログを残したまま放置しておくといいと思います。</p><p> 放置している間にPVが10倍くらいになることもたまにありますし、気が向いたらまた書けば良いです。そういうものです。</p>
</div>
</div>
<div class="section">
<h3>まとめ</h3>
<p> なんだかとりとめのない記事になってしまいましたが、これは突き詰めて言えば一般化して語れる「技術ブログを書く意味」なんてものはないのだ、ということを表しているように思います。だから、あなたが書きたければ書けばよいし、書きたくなければ書かなくてよいでしょう。</p><p> でも、検索とかからこの記事にたどり着いた人は書こうと思っている可能性が高いはずなので、とりあえず気楽に立ち上げてみて様子を見れば良いと思います。飽きたらやめればいいわけですから。</p><p> 日本のIT技術力に対する日本語web圏の貢献は、当然ながら大きいものがあると思っています。日本語のインターネットで言及がない技術はなかなか広まりづらいのが実態ではないでしょうか。</p><p> なので、みなさんも頑張ってください。応援しています。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-d37c06c2" name="f-d37c06c2" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">逆に無駄に人と絡むのが苦痛、という人にはブログが向いています</span></p>
<p class="footnote"><a href="#fn-d6875b47" name="f-d6875b47" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">試算しても、5000記事以上書けばなんとか食えるかな? というレベルです。そんなに書ける技術力があるなら、普通に働けばいいのに</span></p>
</div>
hayataka2049
emacsでpythonを書くための設定 2019年版
hatenablog://entry/17680117127132308093
2019-05-15T23:59:45+09:00
2019-09-01T23:49:37+09:00 概要 emacsライトユーザーの私が、新規環境にemacs25を導入してpythonを書くにあたってやった設定を書いておきます。目的はpythonを書くことだけです。 前提として、以下の記事のように環境を作っています(読まなくてもなんとかなります)。Ubuntu 18.04 LTSにvenvでミニマムなPython3.7仮想環境を構築 - 静かなる名辞 あれこれやってもそこまで快適にならないので、flymakeとjediの設定をやっただけです。 インデントの設定 以前のinit.elからそのまま引き継ぎましたが、要らんかも。 (add-hook 'python-mode-hook (lambd…
<div class="section">
<h3>概要</h3>
<p> emacsライトユーザーの私が、新規環境にemacs25を導入してpythonを書くにあたってやった設定を書いておきます。目的はpythonを書くことだけです。</p><p> 前提として、以下の記事のように環境を作っています(読まなくてもなんとかなります)。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F05%2F05%2F003311" title="Ubuntu 18.04 LTSにvenvでミニマムなPython3.7仮想環境を構築 - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/05/05/003311">Ubuntu 18.04 LTSにvenvでミニマムなPython3.7仮想環境を構築 - 静かなる名辞</a></p><p> あれこれやってもそこまで快適にならないので、flymakeとjediの設定をやっただけです。</p>
</div>
<div class="section">
<h3>インデントの設定</h3>
<p> 以前のinit.elからそのまま引き継ぎましたが、要らんかも。</p>
<pre class="code" data-lang="" data-unlink>(add-hook 'python-mode-hook
(lambda () (setq python-indent-offset 4)))</pre>
</div>
<div class="section">
<h3>pyflakes・flymakeを入れる</h3>
<p> これは入れないとはかどらないので入れました。</p><p> まずpython側で、仮想環境をactivateした状態でpyflakesを入れます。</p>
<pre class="code" data-lang="" data-unlink>$ pip install pyflakes</pre><p> flymakeはemacsにデフォルトで入っていますが、設定が要ります。</p>
<pre class="code lang-lisp" data-lang="lisp" data-unlink><span class="synComment">; これも昔どこかからコピペして使っている秘伝のタレ・・・</span>
<span class="synSpecial">(</span><span class="synStatement">setq</span> flymake-allowed-file-name-masks <span class="synSpecial">'())</span>
<span class="synSpecial">(</span>add-hook <span class="synSpecial">'</span><span class="synIdentifier">find-file-hook</span> <span class="synSpecial">'</span><span class="synIdentifier">flymake-find-file-hook</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">when</span> <span class="synSpecial">(</span><span class="synStatement">load</span> <span class="synConstant">"flymake"</span> <span class="synStatement">t</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">defun</span> flymake-pyflakes-init <span class="synSpecial">()</span>
<span class="synSpecial">(</span><span class="synStatement">let*</span> <span class="synSpecial">((</span>temp-file <span class="synSpecial">(</span>flymake-init-create-temp-buffer-copy
<span class="synSpecial">'</span><span class="synIdentifier">flymake-create-temp-inplace</span><span class="synSpecial">))</span>
<span class="synSpecial">(</span>local-file <span class="synSpecial">(</span>file-relative-name
temp-file
<span class="synSpecial">(</span>file-name-directory buffer-file-name<span class="synSpecial">))))</span>
<span class="synSpecial">(</span><span class="synStatement">list</span> <span class="synConstant">"ほげほげ/bin/pyflakesの絶対パスを書く"</span> <span class="synSpecial">(</span><span class="synStatement">list</span> local-file<span class="synSpecial">))))</span>
<span class="synSpecial">(</span>add-to-list <span class="synSpecial">'</span><span class="synIdentifier">flymake-allowed-file-name-masks</span>
<span class="synSpecial">'(</span><span class="synConstant">"\\.py\\'"</span> flymake-pyflakes-init<span class="synSpecial">)))</span>
<span class="synComment">; show message on mini-buffer</span>
<span class="synSpecial">(</span><span class="synStatement">defun</span> flymake-show-help <span class="synSpecial">()</span>
<span class="synSpecial">(</span><span class="synStatement">when</span> <span class="synSpecial">(</span>get-char-property <span class="synSpecial">(</span>point<span class="synSpecial">)</span> <span class="synSpecial">'</span><span class="synIdentifier">flymake-overlay</span><span class="synSpecial">)</span>
<span class="synSpecial">(</span><span class="synStatement">let</span> <span class="synSpecial">((</span>help <span class="synSpecial">(</span>get-char-property <span class="synSpecial">(</span>point<span class="synSpecial">)</span> <span class="synSpecial">'</span><span class="synIdentifier">help-echo</span><span class="synSpecial">)))</span>
<span class="synSpecial">(</span><span class="synStatement">if</span> help <span class="synSpecial">(</span>message <span class="synConstant">"%s"</span> help<span class="synSpecial">)))))</span>
<span class="synSpecial">(</span>add-hook <span class="synSpecial">'</span><span class="synIdentifier">post-command-hook</span> <span class="synSpecial">'</span><span class="synIdentifier">flymake-show-help</span><span class="synSpecial">)</span>
<span class="synComment">; デフォルトだと赤波線になって見づらかったんで直した</span>
<span class="synComment">; 参考:https://suer.hatenablog.com/entry/20090307/1236403449</span>
<span class="synSpecial">(</span>custom-set-faces
<span class="synSpecial">'(</span>flymake-errline
<span class="synSpecial">((((</span><span class="synStatement">class</span> color<span class="synSpecial">))</span>
<span class="synSpecial">(</span>:foreground <span class="synConstant">"red"</span> :bold <span class="synStatement">t</span> :underline <span class="synStatement">t</span><span class="synSpecial">))))</span>
<span class="synSpecial">'(</span>flymake-warnline
<span class="synSpecial">((((</span><span class="synStatement">class</span> color<span class="synSpecial">))</span>
<span class="synSpecial">(</span>:foreground <span class="synConstant">"red"</span> :bold <span class="synStatement">t</span> :underline <span class="synStatement">t</span><span class="synSpecial">)))))</span><span class="synComment">; :background "white")))))</span>
</pre><p> これだけで使えるはずです。.pyを開けば効くようになります。</p>
</div>
<div class="section">
<h3>jediを入れる</h3>
<p> コード補完のない環境で書いていた期間も割と長く、なければないでやれることは実感として知っていたので入れるかどうか迷いましたが、せっかくなので入れることにしました。</p><p> 一応公式のマニュアルの通りにやればだいたいうまく行くはずですが、一回失敗してel-getから導入しなおしたら治ったみたいなこともあったので、割とハマりやすいと思います。要注意です(つーか正直emacsが面倒くさい。pythonに比べれば)。</p><p><iframe src="https://hatenablog-parts.com/embed?url=http%3A%2F%2Ftkf.github.io%2Femacs-jedi%2Flatest%2F" title="Jedi.el - Python auto-completion for Emacs — Emacs Jedi 0.2.0alpha2 documentation" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><a href="http://tkf.github.io/emacs-jedi/latest/">Jedi.el - Python auto-completion for Emacs — Emacs Jedi 0.2.0alpha2 documentation</a></p><br />
<p> とりあえず、el-getが動くようにしておきましょう。</p>
<pre class="code" data-lang="" data-unlink>M-x el-get-install RET jedi RET</pre><p> これを打ったら(しばらく時間はかかるけど)そのうちぜんぶ導入終わったというメッセージがミニバッファに出てきますので、その後にinit.elを編集します。</p>
<pre class="code" data-lang="" data-unlink>(require 'jedi)
(add-hook 'python-mode-hook 'jedi:setup)
(setq jedi:complete-on-dot t)</pre><p> で、残念なことにjediはこれだけでは使えず、サーバなるものをpython側に入れないといけません。</p><p> とりあえず、</p>
<pre class="code" data-lang="" data-unlink>$ pip install jedi</pre><p> するんですが(当然仮想環境で)、そもそもvenvで仮想環境を組んでいるのでどうしたものか(どう連携させるか)と考え込んでしまいました。virtualenvのやり方は調べると出てくるんですが、venvの場合はググってもよくわかりません。ドキュメントを読んでもさっぱり。</p><p> 思案した結果、「まあいいや、ダメ元でやろう」とpython仮想環境にvirtualenvを導入し(依存があるらしい。他にepcとかも要求されますが、jediと一緒に入ったような気もする)、仮想環境をactivateしたターミナルからemacsを立ち上げて、</p>
<pre class="code" data-lang="" data-unlink>M-x jedi:install-server RET </pre><p> してみました。そしたらぜんぶ良い感じにやってくれました。警戒して以下のような2行も書いてみたりしたのですが、けっきょくなくてもそこそこちゃんと動いたので消すかどうか迷い中。</p>
<pre class="code lang-lisp" data-lang="lisp" data-unlink><span class="synSpecial">(</span><span class="synStatement">setq</span> jedi:server-command
<span class="synSpecial">(</span><span class="synStatement">list</span> <span class="synConstant">"仮想環境をactivateした状態のwhich pythonの結果"</span> <span class="synConstant">"ほげほげ/lib/python3.7/site-packages/jediepcserver.pyみたいなの"</span><span class="synSpecial">))</span>
</pre><p> ただし、この2行がないと「仮想環境をactivateしたターミルから立ち上げないとちゃんと動かない」状態になります。それはそれで良いような気もするし、不便といえば不便。まあ、仕組みがよくわからないので触っていません。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> 終わってみれば大したことやってないのですが、正直けっこう苦労しました。</p><p> ライトユーザーにはけっこう難しいですが、とにかく環境は揃ったのでがんばります。</p>
</div>
hayataka2049
UbuntuのFirefoxでWebページが英語で表示されるのを直す
hatenablog://entry/17680117127130881364
2019-05-14T19:51:22+09:00
2019-05-14T19:51:22+09:00 UbuntuにはデフォルトでFirefoxが入っているので、特別な理由がなければこれを使う人が多いと思います。しかし、ネットを見ているとたまに英語で表示されてしまうページがあることに気づいたりします。 これはFirefoxが「こいつは英語ユーザだ」という情報を渡してくれているからで、設定をいじれば簡単に変えられます。なお、先にUbuntu自体を日本語化する必要があるはずです(最初から日本語化されたもので入れた場合どうなるかは検証していません。この設定すら要らないかも)。 方法 about:preferencesを開く 言語設定(O)...を開く 日本語を追加して最優先にする これだけです。 だ…
<p> UbuntuにはデフォルトでFirefoxが入っているので、特別な理由がなければこれを使う人が多いと思います。しかし、ネットを見ているとたまに英語で表示されてしまうページがあることに気づいたりします。</p><p> これはFirefoxが「こいつは英語ユーザだ」という情報を渡してくれているからで、設定をいじれば簡単に変えられます。なお、先にUbuntu自体を日本語化する必要があるはずです(最初から日本語化されたもので入れた場合どうなるかは検証していません。この設定すら要らないかも)。</p><p> 方法</p>
<ol>
<li>about:preferencesを開く</li>
<li>言語設定(O)...を開く</li>
<li>日本語を追加して最優先にする</li>
</ol><p> これだけです。</p><p> だいぶ快適さが変わるので、やっておくといいと思います。</p>
hayataka2049
Ubuntu 18.04 LTSにvenvでミニマムなPython3.7仮想環境を構築
hatenablog://entry/17680117127111603927
2019-05-05T00:33:11+09:00
2019-05-05T01:14:42+09:00 概要 まっさらなパソコンを開発環境として立ち上げることになり、表題の通りのことをやる必要があったのでまとめておきます。 venvを使うつもりなので、作業量としては少ないはずです。 Python3.7の導入 Ubuntu 18.04はデフォルトでpython2が導入されています。また、python3もありますが、バージョンは3.6です。 3.7くらいを使いたいので、必要そうなものをすべて突っ込んでおきます。 とりあえず以下をターミナルから実行(ぶっちゃけ必要なものの抜けとかはあるかもしれません。気づいたら反映します)。 $ sudo apt install tk-dev python3.7 py…
<div class="section">
<h3>概要</h3>
<p> まっさらなパソコンを開発環境として立ち上げることになり、表題の通りのことをやる必要があったのでまとめておきます。</p><p> venvを使うつもりなので、作業量としては少ないはずです。</p>
</div>
<div class="section">
<h3>Python3.7の導入</h3>
<p> Ubuntu 18.04はデフォルトでpython2が導入されています。また、python3もありますが、バージョンは3.6です。</p><p> 3.7くらいを使いたいので、必要そうなものをすべて突っ込んでおきます。</p><p> とりあえず以下をターミナルから実行(ぶっちゃけ必要なものの抜けとかはあるかもしれません。気づいたら反映します)。</p>
<pre class="code" data-lang="" data-unlink>$ sudo apt install tk-dev python3.7 python3.7-dev python3.7-tk python3.7-distutils python3.7-venv</pre><p> pipはget-pip.pyを落としてきて入れます。</p>
<pre class="code" data-lang="" data-unlink>$ curl -kL https://bootstrap.pypa.io/get-pip.py | sudo python3.7</pre><p> あと、wheelくらいは入れておくか。</p>
<pre class="code" data-lang="" data-unlink>$ sudo python3.7 -m pip install wheel</pre>
</div>
<div class="section">
<h3>venvで仮想環境を構築</h3>
<p> なにも考えずにやるとトラブりやすいので、注意が必要です。とりあえずドキュメントの上半分くらいを全部見ておいてください。</p><p><a href="https://docs.python.org/ja/3/library/venv.html">venv --- 仮想環境の作成 — Python 3.7.3 ドキュメント</a></p><p> コマンドとしては、これでやってみます。</p>
<pre class="code" data-lang="" data-unlink>$ mkdir ~/.venvs
$ python3.7 -m venv --copies ~/.venvs/e371</pre><p> --copiesは強く推奨します(詳しく書きたくないけど、昔--symlinksにしてひどい目に遭いました)。お名前とかはお好みで。この記事ではこれで説明しますが、自分が決めた名前に合わせて書き換えてください。</p><p> できていることを確認します。</p>
<pre class="code" data-lang="" data-unlink>$ source ~/.venvs/e371/bin/activate # (e371)のような文字列がプロンプトの先頭に付けばOK
$ python # python3.7が立ち上がればOK
$ pip show pip # さっきのインストール先のpipが見つかればOK
$ deactivate # 抜けられればOK</pre><p> そしたら.bashrcとかに以下を書きます。</p>
<pre class="code" data-lang="" data-unlink>alias ve37="source ~/.venvs/e371/bin/activate"</pre><p> 保存した後にsource ~/.bashrcなどで読み込み、ve37コマンドで仮想環境が有効になれば問題ありません。</p>
</div>
<div class="section">
<h3>パッケージの導入</h3>
<p> 各自行ってください。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> venvで仮想環境を組んでみました。とても簡単で余計なツールなどを入れる必要もなく、だいたい無難に作れるのがいいところです。</p>
</div>
hayataka2049
もう参照の値渡しとは(無条件では)言わせない
hatenablog://entry/17680117127077424552
2019-04-26T05:33:59+09:00
2019-09-03T19:01:58+09:00 注意:この記事では「参照の値渡し」がどういうものか、という点については説明しません。あくまで「参照の値渡し」を理解している方が対象読者です。 概要 「参照の値渡し」という言葉がありますが、この言葉に関してはずっとモヤモヤ感を抱いていました。 某所での議論を通じて、自分の考えがある程度まとまったので、記録しておきます。 結論を先に要約すると、 「参照の値渡し」は無条件で使える言葉ではない。むしろこの言葉が独り歩きするのであれば、かなり問題があると考える 個人的には「共有渡し(call by sharing)」というネーミングを推す です。 それぞれの理由について以下で述べます。 目次 概要 「参…
<p> 注意:この記事では「参照の値渡し」がどういうものか、という点については説明しません。あくまで「参照の値渡し」を理解している方が対象読者です。</p>
<div class="section">
<h3 id="概要">概要</h3>
<p> 「参照の値渡し」という言葉がありますが、この言葉に関してはずっとモヤモヤ感を抱いていました。</p><p> <a href="https://teratail.com/questions/84660#reply-276551">某所</a>での議論を通じて、自分の考えがある程度まとまったので、記録しておきます。</p><p> 結論を先に要約すると、</p>
<ul>
<li>「参照の値渡し」は無条件で使える言葉ではない。むしろこの言葉が独り歩きするのであれば、かなり問題があると考える</li>
<li>個人的には「共有渡し(call by sharing)」というネーミングを推す</li>
</ul><p> です。</p><p> それぞれの理由について以下で述べます。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#概要">概要</a></li>
<li><a href="#参照の値渡しの問題点">「参照の値渡し」の問題点</a><ul>
<li><a href="#参照の値が定義されていない言語では使うべきではない">「参照の値」が定義されていない言語では使うべきではない</a></li>
<li><a href="#参照と値渡しを理解していないとわからない">「参照」と「値渡し」を理解していないとわからない</a></li>
<li><a href="#そもそも言葉が抽象化されていない">そもそも言葉が抽象化されていない</a></li>
</ul>
</li>
<li><a href="#共有渡しを推してみる">共有渡しを推してみる</a></li>
<li><a href="#参照の値渡しを使っていいとき">「参照の値渡し」を使っていいとき</a></li>
<li><a href="#まとめ">まとめ</a></li>
<li><a href="#関連記事">関連記事</a></li>
</ul>
</div>
<div class="section">
<h3 id="参照の値渡しの問題点">「参照の値渡し」の問題点</h3>
<p> これはもともと「参照渡し」と「参照の値渡し」を混同して使うな! という文脈で流行りだした言葉なのだと思うのですが、呼び方として「参照の値渡し」が良いとは思えない理由がたくさんあります。</p><p> 幾つか挙げます。</p>
<div class="section">
<h4 id="参照の値が定義されていない言語では使うべきではない">「参照の値」が定義されていない言語では使うべきではない</h4>
<p> 「参照の値渡し」という言葉を好んで使う方は、おそらく「参照値」というものがあり、それを値渡ししている……というイメージを明確に持っています。というか、ぶっちゃけ「参照値=メモリ番地」というイメージまではっきり持っているでしょう。</p><p> ただし、メモリ番地どうこうというのは(相対的に見て)低水準の話です。よって、高級言語、特にLLのようなものでは、メモリ番地をプログラマから直接見る手段がないようなものが幾らでもあります。</p><p> ワーストケースでは、言語仕様上で「参照の値」の定義が存在しておらず、実装に委ねられている、ということがあり得ます。そういうケースでは当然「参照の値渡し」とは書けない。そもそも内部的に「参照の値渡し」である保証すらない(同様の動作の実装方法は「参照の値渡し」に限らないかもしれない)。</p><p> 逆に、「参照の値」が定義されている言語ではこの問題はありません。たとえば、この話題に関して検索すると割と上の方に出てくるJavaに関する記事<a href="#f-f6d6065e" name="fn-f6d6065e" title="タイトルのパクり元・・・">*1</a>では、この点が明確です。</p>
<blockquote>
<p>Java で「参照 (references)」といったら「参照値 (reference values)」という「値」のことです。</p><p><a href="https://qiita.com/mdstoy/items/2ef4ada6f88341466783">もう参照渡しとは言わせない - Qiita</a></p>
</blockquote>
<p> 「参照の値渡し」に関して言えば、Javaはかなり有利な立ち位置にいると言えます。・・・というか、Javaの人たちは「参照の値渡し→参照値の値渡し→そもそも値渡しである」という話の方に向かってしまう場合があります(上の記事もそうです)。こうみなすと、プリミティブ型にしろ参照型にしろ値渡しという一つの方法で扱われると言えるのですっきりするのです。</p><p> 問題は、このように「値渡し」とみなしても、特に良いことのないばかりか悪いことまで出てくる言語もたくさんある、ということです。</p><p> 私の好きなpythonはその代表格で、</p>
<ul>
<li>すべての変数は参照型、というかオブジェクト</li>
</ul><p> →「参照の値渡し」の部分は裏側に引っ込んでしまうので、あえて値渡しと呼称してもメリットはない</p>
<ul>
<li>当たり前だが「参照値」なんて定義されていないし、プログラムから触る手段もない</li>
</ul><p> →実際は(少なくともCPythonでは)変数表のdictのvalueのポインタがそれに相当する。ただし、pythonのレイヤでは完全に見えない</p><p> という事情があります。なので、pythonで「参照の値渡し」という言葉を使うインセンティブはありません。</p>
</div>
<div class="section">
<h4 id="参照と値渡しを理解していないとわからない">「参照」と「値渡し」を理解していないとわからない</h4>
<p> 「参照の値渡し」という言葉の残念な点は、それが「参照」と「値渡し」という概念に依存していることです。どちらも重要な概念で、しかも初心者のつまづきポイントです。</p><p> つまり、「ヤツらに参照渡しと参照の値渡しを区別してほしい!」と思っている対象の「ヤツら」はそもそも「参照」も「値渡し」もちゃんと理解していない可能性が相応にある、ということです。ということは、「参照の値渡し」も理解してくれませんよね。</p><p> また、一例として、これまでまったくプログラミングをやったことがない人とか、小学生とかにpythonを教えることを考えてみましょう。</p><p> 「参照」は理解してもらうしかないでしょう。すべての変数が参照型である以上、やむを得ません。でも、「値渡し」は上述した通りpythonのレイヤでは意識する必要がないので、教える必要はありません<a href="#f-f1e9d1c6" name="fn-f1e9d1c6" title="もちろんプログラミングを続けるのであれば、いずれ理解する必要が生じるでしょうけど">*2</a>。しかし、「値渡し」を教えないと問題が発生します。「参照の値渡し」は引数の渡り方という超重要なトピックなので必ず教える必要があり、そのためには「値渡し」を教えないといけない・・・なにかが破綻しています。純粋に「参照の値渡し」という言葉が悪いのです。</p>
</div>
<div class="section">
<h4 id="そもそも言葉が抽象化されていない">そもそも言葉が抽象化されていない</h4>
<p> もっとも根本的な問題です。「参照の値渡し」は何も抽象化していない言葉です。「参照値が値渡しされる」と言っているのと同じですから。</p><p> これは、「値渡し」と言う代わりに「実引数の値がコールスタックにpushされて・・・」と言うのと同じことです。単に動作を説明しているだけです。</p><p> モジュール化して適切な名前を付け、ブラックボックスにして抽象化し、使いやすくする、というのはプログラミングにおいては極めて重要なことです。これを否定する人はいないでしょう。なのに、そういう大切な原則が守られていない言葉なのです。</p><p> この言葉に対して私が個人的に抱いているモヤモヤ感も、けっきょくその辺りに起因する気がします。「名前」が「動作の説明」になってはいけません。</p>
</div>
</div>
<div class="section">
<h3 id="共有渡しを推してみる">共有渡しを推してみる</h3>
<p> 上で述べた通り、「参照の値渡し」はまずい点の多い言葉です。ただし、この言葉を使わないのであれば、代わる候補を探す必要があります。</p><p> ということで、共有渡しを推します。</p>
<ul>
<li>オブジェクトが(あるいはメモリ領域が)関数の間で共有される、という現象を捉える上で自然な言葉。</li>
<li>上述した「参照の値渡し」の問題がない。</li>
<li>英語圏ではもともと「call by sharing」が「参照の値渡し」とほぼ同じ意味で使われており、ならばこれの訳語を使うのが自然<a href="#f-971d191f" name="fn-971d191f" title="callとpassは英語でもどちらでも良いものらしいので、問題にはなりません">*3</a>。</li>
</ul><p> 特に異論はないと思います。「共有渡し」唯一の難点は日本語圏ではまったく流行っていないことですが、どうせ「参照の値渡し」もリアルでは通じないことの方が多いでしょうから、大きな問題ではないでしょう。</p>
</div>
<div class="section">
<h3 id="参照の値渡しを使っていいとき">「参照の値渡し」を使っていいとき</h3>
<p> この記事でこれまで述べてきた通り、「参照の値渡し」という言葉にはかなり問題があります。なので、使用場面は本来は極限されるべきであると考えます。</p>
<ul>
<li>参照値が定義されている言語で、</li>
<li>共有渡しより通じやすい可能性があり、</li>
<li>共有渡しより文脈上適当と考えられ、</li>
<li>その他の他の候補と比べて適切であると認められる場合<a href="#f-d8134095" name="fn-d8134095" title="たとえば「ポインタ渡し」や「アドレス渡し」という言葉もあり、Cであればこちらを使った方が良いと思われます">*4</a></li>
</ul><p> 上で挙げたJavaの例などはこれに当てはまる可能性があります。ただし、この場合も、「(一般名詞の)『参照の値渡し』と呼ばれる動作です」と言うよりは、「参照値が値渡しされます」と説明的に書いた方がはるかに親切でわかりやすいことに留意してください。</p><p> つまり、理想論を言えば使途はかなり限定されるべきであろう(=ほぼ使われるべきではない)、ということです。</p><p> ただし純粋に呼び方の問題でしかないので、理想論を押し通したところで、得られるメリットはほとんどありません。それが最大の難点です。「まあ細かい齟齬はあるかもしれないけど、『参照の値渡し』でも別にいいんじゃない?」と言われたら何も言い返せません。正しくはないと思うけど、自分の思う正しさを押し付ける蛮勇を振るうのは大変です。ぶっちゃけいまいち積極的になれません(という気分がタイトルにもにじみ出ているのを感じ取っていただければ)。</p><p> この記事を読んだ上で、いろいろな理由で「それでも私は『参照の値渡し』と呼ぶ」と決意する方がいれば、私から言うことは特にありません。あくまでもこれは消極的な提言であるとご理解ください。できれば共有渡し派が増えてくれると嬉しいのですが・・・</p><p> けっきょく、この記事にしてもこういう思いを共有してくれる人に向けて書いているだけなのです。(なんつーオチだ)</p>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> 「参照の値渡し」という言葉は考えれば考えるほどケチがつけられるので、やっぱり問題含みだと思う。</p>
</div>
<div class="section">
<h3 id="関連記事">関連記事</h3>
<p> (昔書いたものなので、今見ると拙い部分もあります。この記事のアップに伴って多少修正しましたが、私自身100%内容に満足している訳ではないことはご理解ください。)<br />
<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2018%2F06%2F19%2F181657" title="共有渡しと参照の値渡しと - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2018/06/19/181657">共有渡しと参照の値渡しと - 静かなる名辞</a></p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-f6d6065e" name="f-f6d6065e" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">タイトルのパクり元・・・</span></p>
<p class="footnote"><a href="#fn-f1e9d1c6" name="f-f1e9d1c6" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">もちろんプログラミングを続けるのであれば、いずれ理解する必要が生じるでしょうけど</span></p>
<p class="footnote"><a href="#fn-971d191f" name="f-971d191f" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">callとpassは英語でもどちらでも良いものらしいので、問題にはなりません</span></p>
<p class="footnote"><a href="#fn-d8134095" name="f-d8134095" class="footnote-number">*4</a><span class="footnote-delimiter">:</span><span class="footnote-text">たとえば「ポインタ渡し」や「アドレス渡し」という言葉もあり、Cであればこちらを使った方が良いと思われます</span></p>
</div>
hayataka2049
はてなブログの独自ドメイン化でカバレッジが切り替わらないときの対処
hatenablog://entry/17680117127035594040
2019-04-16T17:04:42+09:00
2019-07-10T20:57:26+09:00 はじめに 去年の秋頃、このブログを独自ドメイン化しましたが、今年に入ってもSearch Console上で古いサイトのインデックス・カバレッジが大量(数百件とか)に残ったままでした。 思いついた方法を試したところ、さほど重要でないページ数件*1を残してカバレッジをすべて新URLに移動できました。 前提 サイトの移転に際して、googleは以下の手順を踏むことを推奨しています。 サイトを移転する 0.サイト移転に関する基本情報を確認します。 手順の概要とユーザーや掲載順位に与える影響について確認しておきます。HTTP から HTTPS へ移転する場合は、HTTPS に関するおすすめの方法を確認し…
<div class="section">
<h3>はじめに</h3>
<p> 去年の秋頃、このブログを独自ドメイン化しましたが、今年に入ってもSearch Console上で古いサイトのインデックス・カバレッジが大量(数百件とか)に残ったままでした。</p><p> 思いついた方法を試したところ、さほど重要でないページ数件<a href="#f-249b6b75" name="fn-249b6b75" title="なぜ残ったのかは不明だが、実害もないので放置">*1</a>を残してカバレッジをすべて新URLに移動できました。</p>
</div>
<div class="section">
<h3>前提</h3>
<p> サイトの移転に際して、googleは以下の手順を踏むことを推奨しています。</p>
<blockquote>
<p>サイトを移転する<br />
0.サイト移転に関する基本情報を確認します。 手順の概要とユーザーや掲載順位に与える影響について確認しておきます。HTTP から HTTPS へ移転する場合は、HTTPS に関するおすすめの方法を確認してください。<br />
1.新しいサイトを準備して、十分にテストします。<br />
2.現在の URL から対応する新しい形式への URL マッピングを準備します。<br />
3.元の URL から新しい URL にリダイレクトするようサーバーを設定して、サイト移転を開始します。<br />
4.元の URL と新しい URL 両方のトラフィックを観察します。<br />
<a href="https://support.google.com/webmasters/answer/6033049?hl=ja">概要: URL の変更を伴うサイト移転 - Search Console ヘルプ</a></p>
</blockquote>
<p> これだけだとはてなブログProの契約でやってくれる移転処置とSearch Consoleから行う手続きだけでぱっと見大丈夫なのですが、ヘルプページをよく読み込んだ結果、以下の記述を発見しました。</p>
<blockquote>
<p>移転先のサイトについては、元の URL と新しい URL を含む、事前に用意した 2 つのサイトマップを送信します。このようにすると、Google のクローラが元の URL から新しい URL へのリダイレクトを検出しやすくなり、サイトの移転がスムーズに進むようになります。<br />
<a href="https://support.google.com/webmasters/answer/6033080?hl=ja&ref_topic=6033084">3. サイト移転を開始する - Search Console ヘルプ</a></p>
</blockquote>
<p> あー、元のURLと新しいURLを含んだサイトマップ? そんなものが必要なんですね。</p><p> しばらく考え込んだ結果、「googleのクローラが旧URLのクロールを試みる→301リダイレクトを検出→インデックスを切り替える」という流れで処理されるのだろう、と察しました。</p><p> 移転後、旧URLへのクロールは一日10未満という数字が続いていました。毎日10ページ処理してくれればそれでもいずれ切り替わることが期待されますが、外部リンクから来ているクローラだったりすると同じページしかクロールしてくれない訳で、クロールされなかったページは切り替わらないわな・・・。</p>
</div>
<div class="section">
<h3>対処</h3>
<p> はてなブログではサイトマップを編集できません(重要)。また、なぜか不具合があり、そもそも通常の状態でもいまいち正常に機能していなかったりする(googleがうまく読み込んでくれない)のがはてなのサイトマップです。改善してほしいのですが。</p><p> サイトマップを頼るわけには行かないので、他の方法で旧URLをクロールさせます。理屈の上ではどうやってもいいはずです。</p>
<div class="section">
<h4>方法1:Fetch as Googleを使う</h4>
<p> Fetch as Googleを使って旧URLにクローラを巡回させます。・・・と書いておいて恐縮ですが、Fetch as GoogleというツールはSearch Consoleのバージョンアップに従って消滅しています。今はURL検査ツールというもので代替できます。</p><p> とにかく、これらを使えば任意のページをクロールさせる(厳密にはクロールしてくれ、とお願いする)ことが可能です。ということで、何ページか送信してみたところ、それなりに効果があるような雰囲気を感じました。</p><p> ただ、何百件もちまちま送信するのは大変ですし、やりすぎると自動操作を疑われるのか、画面上で操作できなくなる(やろうとしてもエラーになる)問題があります。数件だけ残ってしまったというのならともかく、普通の状況では使いづらいかと。</p>
</div>
<div class="section">
<h4>方法2:旧URLのカバレッジで表示されるページすべてへのリンクをサイト内に張る</h4>
<p> googleのクローラーはリンクを辿ってくれますから、理屈の上ではクロールしてほしいURLへのリンクを張ったページを作ってそのページをクロールさせれば、リンク先も見てくれます。</p><p> ただし、この方法は若干ハイリスクです。リンクだけ載せまくったページなんて作ったらスパム認定されかねません。更に、このブログではGoogle Adsenseも使ってしまっているため、そちらの規約との兼ね合いも考慮する必要があります。</p><p> ・・・ということで、プロフィールページの下部に載せておきました。他にコンテンツのあるページならなんとか許してもらえるでしょう。</p><p> やり方としては、まずSearch Consoleで旧URLのインデックス・カバレッジを開き、有効なURL一覧をダウンロードします。</p><p><figure class="figure-image figure-image-fotolife" title="ダウンロードボタンは右の下矢印"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190416/20190416165513.png" alt="ダウンロードボタンは右の下矢印" title="f:id:hayataka2049:20190416165513p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>ダウンロードボタンは右の下矢印</figcaption></figure></p><p> csvで落とせるので、適当にいじってwebリンクになるようにします。私はリンクテキストをURLとしたaタグに変換したりするスクリプトを書きました(3行くらい。URLをそのまま貼ってもだいたいリンクが自動挿入されるのだが、一部パラメータなどがうまく認識されない)。できたらそのまま、好きなページに貼り付けます。</p><p> この方法を取ったところ、次の日くらいにSearch Console上のクロールの統計情報で旧URLが猛烈にクロールされていることが確認でき、数日後には旧URLのサイトで登録されていたページが新URLのカバレッジに移動しました。成功です。</p><p> ちなみに、プロフィールページ下部のリンクは、その後一週間ほど様子を見たあと削除しました。</p>
</div>
</div>
<div class="section">
<h3>懸念</h3>
<p> Search Console上ではすでにほとんどのページが移転できているのですが、なぜか旧URLに一定の検索流入が残っています。google検索で適当なキーワードを入れて確認した感じ、一部のページは旧URLのまま表示されてしまっているようです。</p><p> これがキャッシュなどが一時的に残っていることによる効果なのか、変則的なことをしたせいで問題が発生しているのかは不明。</p><p> ちなみに、これをやった直後は検索流入が1割ほど減りました。回復傾向にありますが、元の水準まで回復するかはなんとも言えない状況です。</p><p> また、それなりのリスクもあり、上手くいく保証もないので、この記事を読んだ方は安易に試さないでください。旧URLのままでも実害は少ないですし、しばらく待てば自然に切り替わる可能性もあります。ただ、数ヶ月待っても駄目なときはこれを試す価値はあるかもしれません。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> この方法で私のサイトの場合はうまくいきました、という報告です。一般的に使えるテクニックかどうかはまた別だと思いますが、1つの事例として参考にしてください。</p>
</div>
<div class="section">
<h3>追記</h3>
<p> 切り替わらないページが多いため、旧サイトの「除外」に含まれる「クロール済み - インデックス未登録」など他の項目も載せたところ、多くのページの検索表示が新URLに切り替わりました(まだカバレッジレポートには反映されていません。3週間も止まったままなのです・・・)。</p><p> カバレッジの表示件数と実際に有効なページ数は一致しないケースがあるようです。「ページにリダイレクトがあります」以外は疑った方が良いでしょう。</p>
</div>
<div class="section">
<h3>追記2</h3>
<p> その後経過を観察して何度か同様の措置を行い、結果的にはほぼすべてのページのインデックスを切り替えることができました(一部ゴミみたいな自動ページが旧ドメインのままだが、実害もないので無視)。</p><p> ただし、この方法はあまりおすすめできない面があります。googleのペナルティを受ける確率が0ではないこと、新ドメインにカバレッジが切り替わっても検索順位の低下をもたらすだけで、あまり短期的なメリットがないからです(ただし新ドメインのドメインパワー向上にはつながるので、長い目で見ればメリットはあるかもしれない)。自然に切り替わるのを待った方が良いかもしれません。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-249b6b75" name="f-249b6b75" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">なぜ残ったのかは不明だが、実害もないので放置</span></p>
</div>
hayataka2049
TechAcademyのその後
hatenablog://entry/17680117127028515779
2019-04-15T14:59:20+09:00
2019-09-03T19:02:30+09:00 はじめに 以前このような記事を書きました。TechAcademyがteratailの質問・回答を盗用していた件 - 静かなる名辞 TechAcademy盗用事件 公式発表と深まる疑念 - 静かなる名辞 TechAcademyに問い合わせたところまでで終わっていましたが、その後すこし私生活がバタバタしていたので、ブログを更新する暇がありませんでした。少し落ち着いてきたので、その後の流れをまとめます。 まあ、動きらしい動きはないんですが・・・。 メール TechAcademyが「お知らせ」を出した後、私は彼らに対してメールによる問い合わせを行いました。先の記事にも書きましたが、再掲します(下に要約…
<div class="section">
<h3>はじめに</h3>
<p> 以前このような記事を書きました。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F03%2F22%2F092150" title="TechAcademyがteratailの質問・回答を盗用していた件 - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/03/22/092150">TechAcademyがteratailの質問・回答を盗用していた件 - 静かなる名辞</a><br />
<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F03%2F26%2F093433" title="TechAcademy盗用事件 公式発表と深まる疑念 - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/03/26/093433">TechAcademy盗用事件 公式発表と深まる疑念 - 静かなる名辞</a></p><p> TechAcademyに問い合わせたところまでで終わっていましたが、その後すこし私生活がバタバタしていたので、ブログを更新する暇がありませんでした。少し落ち着いてきたので、その後の流れをまとめます。</p><p> まあ、動きらしい動きはないんですが・・・。</p>
</div>
<div class="section">
<h3>メール</h3>
<p> TechAcademyが「お知らせ」を出した後、私は彼らに対してメールによる問い合わせを行いました。先の記事にも書きましたが、再掲します(下に要約を載せるので読まなくて構いません)。</p>
<blockquote>
<p>キラメックス株式会社様</p><p>貴社のオウンドメディアに対して、指摘のブログ記事を投稿したはやたかという者です。差し出し元の証明のため、このメールの文面は送信と同時に私のブログにて公開しますので、ご確認ください。<br />
<a href="https://www.haya-programming.com/">https://www.haya-programming.com/</a></p><p>今回の騒動を受けて、貴社の行った発表(<a href="https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/">https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/</a>)を拝見させていただきました。残念ながらこちらの内容は、少なくとも私にとっては不満の残るものでした。この発表を読んだ多くのteratailユーザ、貴社サービス利用者も同じ思いを抱いていると確信しています。よって、以下の問い合わせに応じていただきたく思います。</p><p>まず、以下の疑問にお答えください。<br />
・TechAcademyマガジンの盗用疑惑は数ヶ月前からインターネット上で囁かれており、その度に記事削除の対応が行われていた。より早い段階から把握していた社員もいたはずであり、どうしてこれほど対応が遅れたのか。<br />
・そもそも(仮に盗用がなかったとしても)「質問の存在を捏造して掲載する」という行為自体がTechAcademyマガジンのユーザ・読者を裏切る行為である。この点については社内でどれだけの人間が認識していたのか。問題とは思わなかったのか。</p><p>また、次のような要望があります。これについてはTechAcademyのサービスに関わる問題なので、ユーザではない私から申し上げるのも恐縮だと思いますが、あえて貴社のユーザを代弁する形で書かせていただきます。<br />
上でも述べましたが、今回の件については、「そもそも実際に寄せられたものではない架空の質問と回答を創作し、実際にTechAcademyに対して寄せられた質問であると偽って掲載し、企業の宣伝等に用いるという行為自体に深刻な倫理的・コンプライアンス的な問題がある」と考えています。貴社の発表では、これについてどう考えているのかが読み取れませんでした。<br />
また、キラメックス株式会社のお知らせページでの公表は、必ずしも多くの貴社サービスのユーザに触れるものではありません。しかし、貴社の行われた行為はそれらのユーザを裏切ったものであり、自社のユーザに対して謝罪する姿勢がなければ、このことを知ったユーザは「TechAcademyは信用できるサービスではない」という印象を抱くでしょう。<br />
よって、以下の2点について要望します。<br />
・まず「架空の質問・回答を『実際に寄せられた』ものとして掲載したこと」について立場をはっきりさせるような声明を出すこと。<br />
・TechAcademyのページやTechAcademyマガジンのページ、SNS等にも声明を出し、今回の件について周知を図るとともに、謝罪する姿勢を示すこと。</p><p>何卒よろしくおねがいします。</p>
</blockquote>
<p> 要約すると、まず</p>
<ul>
<li>発表しなかった範囲で確実に対応を行っていた件</li>
<li>そもそもユーザから質問があったという事実から捏造してた件</li>
</ul><p> についての経緯と責任の所在を明示するよう求め、</p>
<ul>
<li>捏造の件についても声明を出すこと</li>
<li>会社サイト以外の多くのユーザが閲覧するサイト(TechAcademyやTechAcademyマガジン、SNS等)での周知</li>
</ul><p> を要望しました。</p><p> 2019/03/26にメールを送りましたが、現時点で返信はなく、要望が聞き入れられた形跡もないため、スルーされた形です。</p><p> 少し言い訳させてもらうと、これはいずれもタダでは済まない痛みを伴う要望であり(外部に対して責任を示すこと、売上に直結するような周知を行うこと)、聞き入れられるかどうかはメールを出した時点でも、楽観的に見て五分五分くらいだと考えていました。スルーされたことに驚きはありませんが、少し悲しいと言えば悲しいところです。</p><p> @TechAcademy社員の皆さん もし見ていたら、今からでも良いのでメールに返信して、要望も可能な範囲でいいので検討してください。よろしくおねがいします。</p>
</div>
<div class="section">
<h3>キラメックスの「お知らせ」第二弾</h3>
<p> キラメックスは自社サイトで、ひっそりとお知らせ第二弾を発表しています。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.kiramex.com%2Fnews%2Finfo%2F2019%2F5cac6a996d027a1777000316%2F" title="弊社オウンドメディアの運営体制に関して(2019年4月9日)" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.kiramex.com/news/info/2019/5cac6a996d027a1777000316/">弊社オウンドメディアの運営体制に関して(2019年4月9日) | キラメックス株式会社</a></p><p> なぜ出したのかは不明。私がああいうメールを送って、確実に把握しているであろう状況でも、頑なに企業サイトにだけ掲載する根性って・・・</p><p> 「今後の対応方針等」と「既存コンテンツへの校閲等」の2つが主な内容となっています。まあ、かいつまんで見ていきます。前文等は必要ないので省略しています。</p>
<blockquote>
<p>1.今後の対応方針等 <br />
(1) 今後の対応方針 <br />
(内容が少ないので省略)</p><p>(2) 今後問題を発生させない仕組み作り <br />
今回のような問題を今後発生させないために、運営体制を強化し、事前に問題が発生することを防ぐような仕組みを構築し、強化して参ります。具体的には、以下のような対応を実施して参ります。</p><p>・記事製作ガイドラインの改訂 <br />
・コンテンツ作成フローの見直し <br />
・コンテンツ作成フローにおける編集員による複数名での記事内容確認体制の徹底 <br />
・情報流用をチェックする第三者事業者提供のツール導入を含めた、第三者によるコンテンツの確認体制の新設 <br />
・運営体制強化のためのオウンドメディア編集者増員 <br />
・コンテンツ管理およびチェックプロセスの強化 <br />
・社内規程の改訂による厳罰化</p><p>(3) 情報取り扱いリテラシーに関する意識改革 <br />
今後、今回のような問題を発生させないためには、問題の発生を防ぐ仕組み作りとともに、実際に運営に携わる弊社社員および関係者の意識改革が不可欠だと考えております。そのため、弊社社員および協業する弊社関係者に対し、情報取り扱いリテラシー教育を実施し、それを徹底して参ります。 <br />
また、弊社におけるガイドラインおよびポリシーが適切に遵守されているかどうかをチェックすべく、コンテンツに関わる社員および関係者に対し、弊社ガイドラインおよびポリシーに対する理解度チェックを行って参ります。</p>
</blockquote>
<p> そのまま読んで面白いものはありません。ぱっと見ありきたりな内容です。まあ、こういうのは言うは易しの典型なので、頑張って実行してくださいとしか思えません。</p><p> そう思いつつ、「『編集者増員』ってこれまでどれだけ貧弱な体制で編集やってたんねん」と思って「techacademyマガジン 編集」とか何気なくgoogle先生に聞いてみたら、3番目くらいに答えが出てきてしまいました。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.wantedly.com%2Fcompanies%2Fkiramex%2Fpost_articles%2F113539" title="元受講生から、新卒第1号入社。TechAcademyマガジン編集長の小嶋が3年目を前に思うこと KiRAMEX TALK|小嶋 大貴 | キラメックス株式会社" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.wantedly.com/companies/kiramex/post_articles/113539">元受講生から、新卒第1号入社。TechAcademyマガジン編集長の小嶋が3年目を前に思うこと KiRAMEX TALK|小嶋 大貴 | キラメックス株式会社</a></p><p> <span style="font-size: 120%">1992年生の新卒を入社後いきなり編集長にしてるぅ</span></p><p> たぶん、実質的に、すべて彼一人の実績(やらかし)の可能性が高い、ってことですよね。なんとなくすべてを理解してしまったような気持ちになりました。</p><p> ちょっとブログが書けたりする若者を新卒採用で捕まえてきて、一人でオウンドメディア運営を任せる構図かぁ・・・</p><p> 念のために書いておきますが、編集長の彼個人を責める意図は私にはまったくありません。個人の責任に帰してしまえば、集団の非を問えなくなります。あくまでも会社組織の責任であり、こういう人事采配を行ったキラメックスに対しては憤りを感じますが、編集長個人はきっと限られたリソースと能力の中で善戦したのでしょう。まだ将来のある方ですし、今回の件を反省し、今後は健全なWebメディアの運営に尽力していただければと思います。</p><p> とても「駄目な例」なので、メディア運営に携わっている皆さんは反面教師にすると良いと思います。会社の看板です。イメージ下がるような看板は出さない方がマシです。</p><p> この件はこれ以上特に言うことはありませんが、他にもキラメックスは既存コンテンツへのチェックを行ったとしています。</p>
<blockquote>
<p>2.既存コンテンツに対する校閲等 <br />
今回の問題を受けまして、弊社において、2,000記事以上の弊社既存コンテンツ全てに対する再校閲を実施いたしました。また、流用記事を作成した外部エンジニアおよび外部ライターに対しては、2019年3月25日付けのお知らせのとおり、既に業務依頼を停止いたしました。</p>
</blockquote>
<p> ほーん。</p><p> たとえばこれ。</p><p><a href="https://techacademy.jp/magazine/19292">Pythonのimportメソッドの使い方【初心者向け】 | TechAcademyマガジン</a><br />
<a href="https://megalodon.jp/2019-0415-1436-07/https://techacademy.jp:443/magazine/19292">(どうせ修正されるので魚拓)</a></p><p> import「文」でしょ?</p><p><a href="https://docs.python.org/ja/3/reference/simple_stmts.html#the-import-statement">7.11. import 文 | 7. 単純文 (simple statement) — Python 3.7.3 ドキュメント</a></p><p> 技術記事の校閲なんて、技術のわかる人がチェックしないと駄目です。理系の専門書を出す出版社では、そのためにわざわざ理工系出身者を採用していたりするくらいです。</p><p> こういうのはまともな編集者(それこそトップクラスのエンジニアとして働ける実力のある人間)を置かないとどうにもならないと思います。そういう人はメンターには結構いても、正社員にはほとんどいないという構図なのでしょう。某侍とかと同じ体質です。</p><p> ほんと、こういうのなんとかしろよ、と思うのですが。初心者が困惑するような記事をネットにばらまくのは害悪です。せめてコメント欄を開けておいて、第三者が気軽に指摘してくれるような仕組みにしないと。</p>
</div>
<div class="section">
<h3>本ブログの今後の対応</h3>
<p> 私は今回の件については直接の利害関係は一切ないただの第三者なのですが、なにしろこれを含めて3記事も書いてしまったので、何も言わずに平常運転に戻すのもなんだか変な感じがします。そこで、ここで今後の対応について示しておきます。</p>
<div class="section">
<h4>今後この件についての記事は書きません。</h4>
<p> 100%ないとは言い切れませんが、たぶん書かないと思います。</p><p> もし何かあれば、必要と認められる範囲で既存記事を加筆します。ただし、匿名掲示板やSNS等はすでにリアルタイムでヲチしていないため、はっきり言って状況を把握しきれません。最新情報等は期待しないでください。</p>
</div>
<div class="section">
<h4>ヘッダでの周知は継続します。</h4>
<p> この事件が発生して以来、本ブログのヘッダ部に関連記事へのリンクを貼っていますが、これは無期限で継続します。ただし、「TechAcademyがマガジン・SNS等での周知を行えば」解除します。また、運営上の都合でサイドバー等他の場所に移動する可能性も皆無ではありませんが、少なくとも目立つ位置には貼り続ける予定です。</p><p> 本ブログには初心者の方もたくさん来られていて、プログラミングスクールの受講を考えている方、すでに受講されている方もいると思います。私にネットのIT界隈を大炎上させるような影響力はありませんが、せめて見に来てくれた方に対しては判断材料を提供しよう、という考えです。</p>
</div>
</div>
<div class="section">
<h3>まとめ</h3>
<p> 今後、TechAcademyが健全に運営され、teratailユーザのような第三者、そして受講者の方々に不利益がないことを願います。</p>
</div>
hayataka2049
TechAcademy盗用事件 公式発表と深まる疑念
hatenablog://entry/17680117126999705726
2019-03-26T09:34:33+09:00
2019-09-03T19:02:57+09:00 TechAcademyマガジンで、teratailの質問・回答の盗用疑惑があり、前回の記事で取り上げました。私が書いたその記事はTwitterやはてブ経由で拡散して多くの方に見ていただき、TechAcademyマガジンの運営上の問題が多くのインターネットユーザに共有されました。それを受けてか、昨日teratail運営、TechAcademy運営からそれぞれ公式のアナウンスがありました。
<div class="section">
<h3>これまでの経緯</h3>
<p> TechAcademyマガジンで、teratailの質問・回答の盗用疑惑があり、前回の記事で取り上げました。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F03%2F22%2F092150" title="TechAcademyがteratailの質問・回答を盗用していた件 - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/03/22/092150">TechAcademyがteratailの質問・回答を盗用していた件 - 静かなる名辞</a></p><p> 私が書いたその記事はTwitterやはてブ経由で拡散して多くの方に見ていただき、TechAcademyマガジンの運営上の問題が多くのインターネットユーザに共有されました。それを受けてか、昨日teratail運営、TechAcademy運営からそれぞれ公式のアナウンスがありました。</p><p><blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">【ご報告】teratailのQ&Aと類似したコンテンツが他メディアに掲載されていた件に関して、先方よりリリースが出されました。<a href="https://t.co/wBe9wWjlpi">https://t.co/wBe9wWjlpi</a></p>— teratail【テラテイル】 (@teratail) <a href="https://twitter.com/teratail/status/1110179926303371266?ref_src=twsrc%5Etfw">2019年3月25日</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><br />
<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.kiramex.com%2Fnews%2Finfo%2F2019%2F5c98d89a6d027a17770002ea%2F" title="弊社運営のオウンドメディアへのご指摘について(2019年3月25日)" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/">弊社運営のオウンドメディアへのご指摘について(2019年3月25日) | キラメックス株式会社</a></p><p> TechAcademyの一方的な盗用であったことが確認された形です。とはいえ、これですべて腑に落ちたかというと幾つか疑念が残ってしまったので、それについて書いておきます。</p>
</div>
<div class="section">
<h3>teratail運営側の説明</h3>
<p> teratail運営側の説明している内容をまとめると、</p>
<ul>
<li>TechAcademy運営が勝手にやったことである。</li>
</ul><p> という一点です。また、ユーザの投稿を活用する際は適切な周知を行う(teratail運営承認のもとで今回のように勝手に不当利用されることはないので安心してほしい)としています。</p>
<blockquote>
<p>なおteratailがこれまで他メディアに対して、コンテンツ使用に関するライセンス等を行なったことはありません。<br />
今後、仮にユーザー様の投稿を活用した活動を行う場合でも、ユーザー様が認識できる方法で事前にお知らせをいたします。</p>
</blockquote>
<p> よってteratail運営はこの件に関しては100%白であることが確定しました。</p><p> 一方、teratail運営は、</p>
<ul>
<li>teratailの保有する権利の侵害に対する、損害賠償請求などを含めた対応</li>
<li>今後はこれ以上追求しないのか</li>
</ul><p> といった点については明らかにしていません。まだ検討中という可能性もありますし、大きな実害を被った訳ではないこと、運営会社同士には(TechAcademyの受講生の就職を斡旋するといった)ある程度の友好関係があることを考えると、これ以上ことを荒立てるつもりはなく、穏便に済ませるつもりなのかもしれません。まあ、これらに関しては運営会社同士で勝手にやってくれれば良いので、私からとやかく言うことはありません。</p><p> ということで、とりあえず私個人としてはteratailを当分は使い続けるつもりです。運営側に黒い要素がなくて少しだけ安心しました。</p>
</div>
<div class="section">
<h3>TechAcademy運営側の説明</h3>
<p> TechAcademyを運営するキラメックス株式会社は、会社のホームページ上のお知らせで声明を発表しました。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.kiramex.com%2Fnews%2Finfo%2F2019%2F5c98d89a6d027a17770002ea%2F" title="弊社運営のオウンドメディアへのご指摘について(2019年3月25日)" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/">弊社運営のオウンドメディアへのご指摘について(2019年3月25日) | キラメックス株式会社</a></p><p> 基本的に盗用した事実は認めているのですが、読んでみた感想はというと、頷ける部分もあるものの全体としては「んんん?」です。死体蹴りっぽくなっちゃいますが、いちいちツッコミを入れてみます。</p>
<div class="section">
<h4>『■ご指摘に対する時系列の対応について 』について</h4>
<p> キラメックス株式会社の発表によると、今回の件の「時系列の対応」は以下の通りです。彼らの発表を元に一部要約・編集して掲載します。</p>
<blockquote>
<p>・2019年3月20日23時 <br />
はてなブログ「saitouena」にて質問と回答の盗用に関する上記のご指摘が公開される<a href="#f-b745e5d6" name="fn-b745e5d6" title="[https://evalcat.hatenablog.com/entry/2019/03/20/234322]">*1</a><br />
・2019年3月20日23時 <br />
ブログの内容をもとに該当記事の精査を行うため、ご指摘の記事を含めて35件の一時削除を実施<br />
・2019年3月22日9時 <br />
はてなブログ「静かなる名辞」にて質問と回答の盗用に関するご指摘が公開される<a href="#f-8e380a18" name="fn-8e380a18" title="[https://www.haya-programming.com/entry/2019/03/22/092150]">*2</a><br />
・2019年3月22日18時 <br />
代表取締役社長を筆頭に調査チームを組成し、過去の記事について精査。問題のある記事を一斉削除。</p><p>(以下は元の記述を踏まえて私が付け加えたものです)<br />
・日時不明(22日か25日)<br />
teratail運営に対して直接伺い謝罪。</p><p>・2019年3月25日<br />
Webサイトに報告<a href="#f-e9e73707" name="fn-e9e73707" title="[https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/]">*3</a></p>
</blockquote>
<p> 私のブログをきっかけに調査チームを立ち上げたのですか・・・ちなみに3月22日時点では件の記事はせいぜい150PV程度しか集めていません(土日に伸びて現在は累計2500PVほどです)。金曜日中にtwitterで投稿された方はいましたが(ブログ読者の方や私の知り合いが主)、それを察知したとしたら恐るべきエゴサ力とでも言うべきでしょうか。</p><p> ということは置いておいて、この時系列表を見て浮かぶ疑問点は以下の3つです。</p>
<ul>
<li>2019年3月20日以前にもSNSや匿名掲示板で散発的に話題にされていて、記事削除の対応もsaitouenaさんが取り上げる以前に行われていた。少なくとも数ヶ月前から、一部の記事に問題があることを把握している社員(ないし少なくとも記事を削除する権限のある人間)がいたことになる。それについての説明はなし。</li>
<li>「精査を行うために一時削除」とあるが、もみ消しと捉えられても仕方ないのでは。</li>
<li>それでも精査していたとしたら、2019年3月20日にsaitouenaさんが言及してから、22日に私が言及するまで丸一日以上あったのに、何をしていたのか。見れば一発で分かる問題であり、最速で動けば21日に調査チーム結成、当日中に状況把握と記事削除を済ませ、22日にはteratail運営への謝罪と公式発表というスケジュールでやれたはず。</li>
</ul><p> はっきり言って、21日頃まではもみ消す方向で動いていたけど、(私のブログが中途半端にバズったせいもあって)もみ消しきれないと悟った結果が22日以降の動きなのでは? というのが「時系列の対応」を見て思った率直な感想です。あるいは、権限のある上層部が状況を把握していなかったということかもしれませんが。</p><p> グダグダ書いていて自分でも嫌になってきましたが、こんな感じであげつらっていくつもりです。</p>
</div>
<div class="section">
<h4>『■今回の問題とその原因 』について</h4>
<p> TechAcademy運営側は、以下のように書いています。長いですが全文引用します(読み飛ばしてください)。</p>
<blockquote>
<p>■今回の問題とその原因 <br />
TechAcademyマガジンでは2018年4月から2018年7月まで、TechAcademyマガジンの読者などからプログラミングを学習する上でぶつかりやすい疑問や質問を集め、それに対して現役エンジニアが回答するコンテンツ「実際のエンジニアが回答するシリーズ」を公開していました。</p><p>このコンテンツ制作作業の中で、一部記事では学習者の声から疑問を持ちやすいキーワードを社内編集部が設定し、それに関連した質問案作成を外部ライターに依頼、それを社内の編集チームが確認のうえで、ライターがコンテンツ投稿まで行っていました。また、回答に関しては、現役エンジニアが質問をピックアップし、記事の投稿を行っていました。</p><p>そして、この時期公開したコンテンツのなかに、今回問題となりましたteratailの内容がそのまま使用されていた記事がありました。</p><p>この問題が起きた原因として、協力を依頼した外部のライター・エンジニアの一部メンバーに著作権などに関する意識が不十分な方がいたこと、外部の方に執筆頂いたTechAcademyマガジンの記事は全て弊社で編集を行なっておりましたが、それらのコンテンツに対する著作権保護に準じた弊社内での記事の流用チェックが十分に機能していなかったことが挙げられます。</p>
</blockquote>
<p><span style="font-size: 150%"> (゜ロ゜)。。。</span></p><p> 5回くらい読み直して、ようやく何を言っているのかおぼろげにわかってきました。わかりやすくイラストで説明します。</p><p> まず、外面的な記事の体裁はこうでした。</p><p><figure class="figure-image figure-image-fotolife" title="外面的な体裁"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190326/20190326083623.png" alt="外面的な体裁" title="f:id:hayataka2049:20190326083623p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>外面的な体裁</figcaption></figure></p><p> この通りやっていれば、何ら問題なかったでしょう。でも実際はこうでした。</p><p><figure class="figure-image figure-image-fotolife" title="実際"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20190326/20190326083650.png" alt="実際" title="f:id:hayataka2049:20190326083650p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>実際</figcaption></figure></p><p> ・・・これ現実的ですかね? 質問と回答は独立に作られているということらしいですが。。。</p><p> どちらも同じteratailのページからコピペされているケースも多々あった訳で、単純に一人でぜんぶコピペしたんじゃ? という気がします。まあ、この通りだとしたら、</p>
<ul>
<li><b>質問者役コピペライター:「コピペで質問作ったろ!」</b></li>
<li><b>回答者役コピペライター:「おっ、この質問teratailからのコピペだ! 回答もコピペしたろ!」</b></li>
</ul><p> という素晴らしい共同作業があった訳ですね。</p><p> あと、さらっと流していますが、</p>
<blockquote>
<p>一部記事では学習者の声から疑問を持ちやすいキーワードを社内編集部が設定し、それに関連した質問案作成を外部ライターに依頼</p>
</blockquote>
<p> とありますが、そうやって作成した記事を<b>「現役エンジニアが回答」と偽って発表している</b>時点で言い逃れできませんから。それに、実際にTechAcademyに寄せられた質問なんてそもそもあったのでしょうか? 現時点でTechAcademyマガジンのサイトで「現役エンジニアが回答」のようなキーワードで検索をかけてみたら1記事もヒットしなかったので(リンクテキスト等除く)、この形式の記事はすべて削除されてしまった訳です。そもそもすべてが「なんちゃって寄せられた質問」だったのでは? という疑惑があります。</p><p> まあ、どうやって記事を作っていたのかは正直どうでも良いです。それよりこの節の全体に言えますが、TechAcademy側がどこまでコピペに関与したのか、まったく把握していなかったのかある程度はわかっていたのか、どのタイミングで把握してどう動いたのか、等、肝心な部分の説明がぼかされています。文字通り受け取るなら外部の人間が勝手にやって20日~22日に把握したたという主張のようですが、信じがたい点がいくつもあります。そのせいで、納得の行く説明にはなっていない感があります。</p><p> 個人的には、本当に外部の人が勝手にやらかしてチェックをすり抜けてしまったのなら、もっとスムーズに対応できたでしょ、という気がしています。数ヶ月前から散発的に話題になっていた訳ですし、運営はそれを把握していた<a href="#f-863c9154" name="fn-863c9154" title="話題に上がった記事を削除するといった動きはかなり以前からありました。たとえば[https://medaka.5ch.net/test/read.cgi/prog/1549938681/611]など">*4</a>でしょうから、その時点で動くべきだった。動けなかったのは、よほど重大な責任が内部にあったのでは? という気しかしません。</p>
</div>
<div class="section">
<h4>『■今後の対策 』について</h4>
<p> キラメックスは以下のように述べています。</p>
<blockquote>
<p>他サイトなどからの著作物の流用がないように、下記対策を徹底し、誠意をもって運営に努めて参ります。</p><p>1)協業する外部ライター・エンジニアへの情報取り扱いリテラシー教育の徹底 <br />
2)運営体制強化のための社内のTechAcademyマガジンの編集者増員 <br />
3)情報流用をチェックする第三者事業者提供のツール導入 <br />
4)当該の流用を行った外部エンジニア・ライターへの業務依頼の停止</p>
</blockquote>
<p> いや、上でも書いたけど<b>「現役エンジニアが回答」と偽って発表している</b>時点で、単純な著作権侵害の問題ではありませんからね?</p><p> 外部に責任を押し付けたいようですが、運営体質そのものを変えないと駄目だと思う。</p>
</div>
<div class="section">
<h4>そもそも論</h4>
<p> この発表は、「キラメックス株式会社のお知らせページ」に掲載すべきものだったのでしょうか?</p><p> はっきり言って、誰が読むんだという感じです。「祭り」に乗っかった人たちに読んでもらえれば良く、できるだけこの事実が広がらないようにしようという魂胆が透けて見えます。同様の声明はTechAcademyのトップページやTechAcademyマガジンには今の所掲載されていません。Facebook, Twitter等のSNSでの発信もなし。</p><p> もちろんteratailのユーザや運営に対する謝罪も大切だとは思いますが、それよりも謝罪しないといけないのは、彼らが裏切ったTechAcademyマガジンの読者、TechAcademyのユーザに対してではないでしょうか。私から言うのはどうなのかという面もありますが、はっきり言ってどうかと思います。</p>
</div>
</div>
<div class="section">
<h3>ひどかったので問い合わせる</h3>
<p> ここまで読んでいただいた方には理解していただけたと思いますが、キラメックス株式会社の対応は少なくとも私にとって不満の残るものでした。ということで、以下の文面でキラメックス株式会社に対して問い合わせを行いました。</p>
<blockquote>
<p>キラメックス株式会社様</p><p>貴社のオウンドメディアに対して、指摘のブログ記事を投稿したはやたかという者です。差し出し元の証明のため、このメールの文面は送信と同時に私のブログにて公開しますので、ご確認ください。<br />
<a href="https://www.haya-programming.com/">https://www.haya-programming.com/</a></p><p>今回の騒動を受けて、貴社の行った発表(<a href="https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/">https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/</a>)を拝見させていただきました。残念ながらこちらの内容は、少なくとも私にとっては不満の残るものでした。この発表を読んだ多くのteratailユーザ、貴社サービス利用者も同じ思いを抱いていると確信しています。よって、以下の問い合わせに応じていただきたく思います。</p><p>まず、以下の疑問にお答えください。<br />
・TechAcademyマガジンの盗用疑惑は数ヶ月前からインターネット上で囁かれており、その度に記事削除の対応が行われていた。より早い段階から把握していた社員もいたはずであり、どうしてこれほど対応が遅れたのか。<br />
・そもそも(仮に盗用がなかったとしても)「質問の存在を捏造して掲載する」という行為自体がTechAcademyマガジンのユーザ・読者を裏切る行為である。この点については社内でどれだけの人間が認識していたのか。問題とは思わなかったのか。</p><p>また、次のような要望があります。これについてはTechAcademyのサービスに関わる問題なので、ユーザではない私から申し上げるのも恐縮だと思いますが、あえて貴社のユーザを代弁する形で書かせていただきます。<br />
上でも述べましたが、今回の件については、「そもそも実際に寄せられたものではない架空の質問と回答を創作し、実際にTechAcademyに対して寄せられた質問であると偽って掲載し、企業の宣伝等に用いるという行為自体に深刻な倫理的・コンプライアンス的な問題がある」と考えています。貴社の発表では、これについてどう考えているのかが読み取れませんでした。<br />
また、キラメックス株式会社のお知らせページでの公表は、必ずしも多くの貴社サービスのユーザに触れるものではありません。しかし、貴社の行われた行為はそれらのユーザを裏切ったものであり、自社のユーザに対して謝罪する姿勢がなければ、このことを知ったユーザは「TechAcademyは信用できるサービスではない」という印象を抱くでしょう。<br />
よって、以下の2点について要望します。<br />
・まず「架空の質問・回答を『実際に寄せられた』ものとして掲載したこと」について立場をはっきりさせるような声明を出すこと。<br />
・TechAcademyのページやTechAcademyマガジンのページ、SNS等にも声明を出し、今回の件について周知を図るとともに、謝罪する姿勢を示すこと。</p><p>何卒よろしくおねがいします。</p>
</blockquote>
</div>
<div class="section">
<h3>まとめ</h3>
<p> とりあえず進展はあったけど、まだ腑に落ちないという感じです。私としては、腑に落ちるまでやってくれ、と思います。</p><p> とりあえず以上です。新たな動き等があればこの記事に追記していきます。</p>
</div>
<div class="section">
<h3>続報</h3>
<p> けっきょくもう1記事書きました。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F04%2F15%2F145920" title="TechAcademyのその後 - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/04/15/145920">TechAcademyのその後 - 静かなる名辞</a></p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-b745e5d6" name="f-b745e5d6" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://evalcat.hatenablog.com/entry/2019/03/20/234322">https://evalcat.hatenablog.com/entry/2019/03/20/234322</a></span></p>
<p class="footnote"><a href="#fn-8e380a18" name="f-8e380a18" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://www.haya-programming.com/entry/2019/03/22/092150">https://www.haya-programming.com/entry/2019/03/22/092150</a></span></p>
<p class="footnote"><a href="#fn-e9e73707" name="f-e9e73707" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/">https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/</a></span></p>
<p class="footnote"><a href="#fn-863c9154" name="f-863c9154" class="footnote-number">*4</a><span class="footnote-delimiter">:</span><span class="footnote-text">話題に上がった記事を削除するといった動きはかなり以前からありました。たとえば<a href="https://medaka.5ch.net/test/read.cgi/prog/1549938681/611">https://medaka.5ch.net/test/read.cgi/prog/1549938681/611</a>など</span></p>
</div>
hayataka2049
TechAcademyがteratailの質問・回答を盗用していた件
hatenablog://entry/17680117126997516710
2019-03-22T09:21:50+09:00
2019-09-03T19:03:41+09:00 はじめに 私はteratailというQAサイトで回答をしていて、pythonカテゴリ総合一位だったりします。あちこちのサイトを見ていたら、TechAcademyというサイトがteratailの質問と回答を盗用しているという話を見つけました。図々しいと思いながらも情報をまとめておきます。
<div class="section">
<h3>編集履歴</h3>
<div class="section">
<h4>2019/03/22 朝</h4>
<p> 投稿。その後数回微調整。</p>
</div>
<div class="section">
<h4>2019/03/22 夜</h4>
<p> タイトルと内容を全面的に改稿。</p>
<ul>
<li>現時点で確証がない部分について表現・内容を修正</li>
<li>情報を追加</li>
</ul>
</div>
<div class="section">
<h4>2019/03/23 朝</h4>
<ul>
<li>追記</li>
</ul>
</div>
<div class="section">
<h4>2019/03/25</h4>
<ul>
<li>teratailへの問い合わせ結果を掲載</li>
</ul><p> 「ライセンスしていない」とのことです。</p>
<ul>
<li>それに伴ってタイトルおよび内容を調整</li>
</ul>
</div>
<div class="section">
<h4>2019/03/25 深夜</h4>
<ul>
<li>teratail運営とTechAcademy運営からそれぞれ公式のアナウンスがありました。</li>
</ul><p><blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">なおteratailがこれまで他メディアに対して、コンテンツ使用に関するライセンス等を行なったことはありません。<br>今後、仮にユーザー様の投稿を活用した活動を行う場合でも、ユーザー様が認識できる方法で事前にお知らせをいたします。</p>— teratail【テラテイル】 (@teratail) <a href="https://twitter.com/teratail/status/1110181672400478210?ref_src=twsrc%5Etfw">2019年3月25日</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><br />
<iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.kiramex.com%2Fnews%2Finfo%2F2019%2F5c98d89a6d027a17770002ea%2F" title="弊社運営のオウンドメディアへのご指摘について(2019年3月25日)" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.kiramex.com/news/info/2019/5c98d89a6d027a17770002ea/">弊社運営のオウンドメディアへのご指摘について(2019年3月25日) | キラメックス株式会社</a></p><p> これらを踏まえた続報記事を公開しました。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F03%2F26%2F093433" title="TechAcademy盗用事件 公式発表と深まる疑念 - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/03/26/093433">TechAcademy盗用事件 公式発表と深まる疑念 - 静かなる名辞</a></p><p> また、この記事の内容は古い情報に準拠しています。いずれ更新していくと思いますが、現時点では手を付けられていません。最新の情報を知りたい方は、続報記事もあわせて御覧ください。</p>
</div>
</div>
<div class="section">
<h3>はじめに</h3>
<p> 私はteratailというQAサイトで回答をしていて、<a href="https://teratail.com/users/hayataka2049">pythonカテゴリ総合一位</a>だったりします。あちこちのサイトを見ていたら、TechAcademyというプログラミングスクールのマガジンページがteratailの質問と回答を盗用しているかも? という話を見つけました。図々しいと思いながらも情報をまとめておきますので、読者の皆さんはなにかの参考にでも役立ててください。</p>
</div>
<div class="section">
<h3>先人たちのまとめ</h3>
<p> こちらのブログ記事などが概要を掴むのに良いと思います。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fevalcat.hatenablog.com%2Fentry%2F2019%2F03%2F20%2F234322" title="techacademyがteratailの質問を転載して記事を作っている - saitouena" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://evalcat.hatenablog.com/entry/2019/03/20/234322">techacademyがteratailの質問を転載して記事を作っている - saitouena</a></p><p> 5ちゃんねるのteratailヲチスレでも取り上げられているので(現在進行形)、とりあえずリンクを貼っておきます。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fmedaka.5ch.net%2Ftest%2Fread.cgi%2Fprog%2F1552140552%2F" title="teratailもりあがっtail? 26問目" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://medaka.5ch.net/test/read.cgi/prog/1552140552/">teratailもりあがっtail? 26問目</a></p><br />
<p> 要約すると、</p>
<ul>
<li><a href="https://techacademy.jp/magazine/">「TechAcademyマガジン」</a>というオウンドメディアで、主に「TechAcademyに実際に寄せられた質問に現役エンジニアのメンターが回答しました。」という体裁の記事にteratailからの転載と思われる投稿が多数(少なくとも2桁、下手したらそれ以上)ある。</li>
<li>有志の作成した「転載記事リスト」には特定のメンターの名前(複数人。実名なのかどうか、そもそも実在する人物なのかは不明)が多く上がる。</li>
<li>TechAcademy側は「Twitterや匿名掲示板などで取り上げられた」記事を削除して対応中。</li>
</ul><p> という感じです。</p>
</div>
<div class="section">
<h3>一例</h3>
<p> こんな感じです。この問題が盛り上がり始めた、最初期のツイートで取り上げられたものです。なお、TechAcademyの元記事は消えていたのでWeb魚拓です。</p><p><blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">techacademyのこの記事、<a href="https://t.co/7iXdPqkAJD">https://t.co/7iXdPqkAJD</a><br>teratailの質問・回答をまるまるパクッてる。<a href="https://t.co/ju0NI1oztG">https://t.co/ju0NI1oztG</a><br><br>パクリ側の方、日付は2017/8/11って書いてあるけど、作業ファイルの登録日付は2018年5月だし嘘だと分かる。</p>— kuracom (@kuracom) <a href="https://twitter.com/kuracom/status/1100790561143812098?ref_src=twsrc%5Etfw">2019年2月27日</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p><p><a href="https://megalodon.jp/2019-0320-1751-05/https://techacademy.jp:443/magazine/18047">【魚拓】curlコマンドをJavaScriptのAjaxで実行する方法とは【メンターが回答】 | TechAcademyマガジン</a><br />
<a href="https://teratail.com/questions/19322">jQuery - curlコマンドをjqueryのajaxで実行する方法|teratail</a></p><p> 見ていただければわかる通り、出典として元の質問を示す訳でもなければ(まあ「TechAcademyに寄せられた」という体裁なので示せないのですが)、内容を書き換えて誤魔化すといった小手先の芸もありません。コードはもちろん、質問・回答の文言もほぼそのままコピペです。良識を疑うとかそれ以前に、「なんでこれで問題にならないと思ったの?」というのが率直な感想です。</p><p> こういうのがン十件あり、深刻な事態を伺わせます。</p>
</div>
<div class="section">
<h3>法律上はどうなるのか</h3>
<p> ふと「teratailの規約が緩すぎて法律上何ら問題ない」ということになったら大変だと思い<a href="#f-662adae2" name="fn-662adae2" title="私がteratailを使い続けるかどうかも考え直さないといけなくなります">*1</a>、teratailの規約を調べました。</p>
<blockquote>
<p>第9条(権利帰属)</p><p>3.登録ユーザーは、投稿データについて、当社に対し、世界的、非独占的、無償、サブライセンス可能かつ譲渡可能な使用、複製、編集、改編、掲載、転載、公衆送信、上映、展示、提供、販売、譲渡、貸与、翻訳、翻案、配布などができる権利および二次的著作物に関する現著作権者の権利(著作権法21条ないし28条の権利をいい、商用利用を含む)に関するライセンスを付与します。<br />
<a href="https://teratail.com/legal">利用規約|teratail(テラテイル)</a></p>
</blockquote>
<p> 基本的には健全な内容でした。teratailのユーザはteratailの運営会社に対して諸権利をライセンスしている、という立場です。</p><p> よって、</p>
<ul>
<li>teratail運営がTechAcademy運営に対して、こういう使い方が可能になるライセンスを付与したのであればセーフ</li>
<li>それ以外は法的にアウト</li>
</ul><p> という状況であると考えられます。ユーザがライセンスを付与しているのはteratailの運営会社に対してであって、それに関係ない事例に対しては通常の場合と同じ扱いになるからです。</p><p> なお、こういう使い方をされるのを承知でteratail運営がデータの権利を渡した確率は蓋然的には限りなく0に近いと考えられます。あまりにも酷い使われ方であり、これを承諾したのであればteratail運営の信用問題にも発展しかねません。・・・が、その可能性も皆無ではないため、初稿の時点でこの記事に多くあった「断定的な表現」は後から修正しています(2019/03/22夜時点<a href="#f-11606428" name="fn-11606428" title="なお、それまでにこの記事が集めたPVは本ブログの一日の総PVの1割未満であり、集めたはてブやtwitterのシェアも片手で数えられる程度で、現時点で世間にさほど大きな影響を及ぼしてはいないことを付記しておきます">*2</a><a href="#f-1b34007c" name="fn-1b34007c" title="また、この件については私からteratail運営に問い合わせを行っています。結果が返ってくれば追記しますが、あまり期待しないでください">*3</a>)。</p><p> <b>※この件についてteratailに対して問い合わせを行っていましたが、2019/03/25に返信があり、ライセンスは行っていないとのことでした。</b></p><p> よって、TechAcademyが合法的(?)にライセンスを得て掲載していた可能性はなくなりました。</p><p> また、「TechAcademyに実際に寄せられた質問に現役エンジニアのメンターが回答しました。」という記載は著作権以外の問題も発生させます。teratailの質問・回答をコピペしてつくったQ&A記事の質問が実際にTechAcademyに寄せられている訳はないので、実態より多くの質問が寄せられている、と誤認させていることになります。これは一種の誇大広告「みたいなもの」でしょう。「こんなに賑わっているプログラミングスクールなら安心して勉強できる」と思って入会する人がいれば詐欺「のようなもの」です。ただ、私に法律関連の知識はないので、これがどの程度深刻なものかは正直なところわかりません。あくまでも参考として書いておきます。</p>
</div>
<div class="section">
<h3>そもそもTechAcademyとは何ぞや</h3>
<p> プログラミングスクールです。「最短○○でエンジニアに!」のような広告などをよく目にすると思います。</p><p> スクールとしての評判は、ググって出てくるページなどを読んでください。実際に自分が体験した訳でもありませんし、これ以上述べることはしません。</p><p> また、ありがちなことですが、この運営会社は営業活動の一貫としてオウンドメディアを運営し、Web記事も発信しています。「スーツを着たイケメンのお兄さんと女子大生風の女の子のアイコンがセリフでしゃべるページ」と言えば、検索で引っかかった記憶がある方も大勢いると思います。</p><p> で、こういう盗用?なんて真似をしている会社はどんなところなのでしょうか? 去年に大炎上した侍エンジニア塾の場合、元中の人によれば「設立が新しく、資本規模も小さい会社」であり、いろいろな杜撰さも同情に値するかどうかは別として「わからんではない」という面がありました。</p><p><a href="https://www.inodev.jp/entry/samurai">古巣の侍エンジニア塾(株式会社侍)の炎上について思うこと【2018/10/23追記】 - INODEVLOG</a></p><p> ということで、運営会社のページです。重要そうなところだけ抜粋しています。</p>
<blockquote>
<p>会社名 キラメックス株式会社<br />
事業内容 プログラミング教育事業<br />
設立 2009年2月2日<br />
資本金 4,800万円(資本準備金を含む)<br />
親会社 ユナイテッド株式会社(東京証券取引所マザーズ市場)</p><p><a href="https://techacademy.jp/company">運営会社 | TechAcademy [テックアカデミー]</a></p>
</blockquote>
<p> 歴史はそれなり(10年)にあるようです。</p><p> ふーん、マザーズ上場企業が親会社ですか。立派な会社なのかな? と思ってしまいますが、どうやら完全に子会社化されたのは近年のようです。</p><p><a href="https://www.kiramex.com/news/info/2016/56b1a5c46d027a0b8b000046/">ユナイテッド株式会社によるキラメックス株式会社の完全子会社化について(2016年2月3日) | キラメックス株式会社</a></p><p> それ以前に資本関係があったのかどうかまでは調査不足で不明です。とはいえ、問題の記事は子会社化されてから出てきたものが多くを占める訳で、けっきょく「上場企業(の子会社)がこんな杜撰な真似をしている」という構図には変わりはありません。こういうのってコンプラ的に一発アウトだと思うんですが、どうなんでしょうね。</p>
</div>
<div class="section">
<h3>なぜ人は間違えるのか(なんでこんなことになってしまうのか)</h3>
<p> ここまでの説明でも、あまりにも酷い状況なのは皆さんにおわかりいただけたと思うのですが、「どうしてこんなことするの?」という疑問を持った方も大勢おられることでしょう。簡単にですが私が説明できる範囲で大雑把な背景を説明します(正確を心がけますが、憶測も含みます)。</p><p> 基本的に、まともな記事を供給する、というのはけっこうお金がかかります。「エンジニア」として食っていける実力のある人が一時間とか二時間かけて記事を書いたら、時給ン千円以上ですから相当なコストになります。ASCII.jpとかならそれでやっているかもしれませんが(まあ彼らも彼らで厳しいだろうけど)、ほとんどのところはコストを捻出できないでしょう。更に、オウンドメディアの場合は「安いコストで宣伝に寄与してくれればいい」程度に思われていて、それほど予算を割かれていないといった状況が容易に想像できます。</p><p> なので、多くのIT系オウンドメディアは給料の安い自社社員(当然専門的な技術力はない)に書かせるか、クラウドソーシングなどで安く書いてくれる人を探して書かせるか、インターンにやらせるか、といった運営方法を取っていると思います。結果、qiitaの殴り書きよりひどいクオリティのオウンドメディア記事が量産されてしまう訳です。</p><p> では、今回の件は、TechAcademyがクラウドソーシングとかで雇った人が暴走しちゃった?</p><p> その可能性はほぼない、と個人的には考えます。普通、ライターにそこまでの裁量権はないからです。ああいう記事をライターの方が作ってしまうとしたら、「teratailの質問をTechAcademyに寄せられた質問として転載してほしい」という依頼を受けた、というケース以外まったく考えられません。</p><p> 頼まれもしないのにこっそりやってバレたら、次の仕事はなくなります。ヘタしたら「企業イメージを損なった」って訴えられかねない。</p><p> だって、確実に真っ黒で法律違反な行為ですよ? ライターの裁量でできる訳がない。</p><p> また、「インターネットで囁かれ始めてからの対応が『記事の削除』だった」という話もあり、限りなくTechAcademy本体<a href="#f-6e56f874" name="fn-6e56f874" title="あるいはメディア運営をまるごと別会社に委託しているとか、そういう可能性もあるかもしれませんが、考慮しません">*4</a>が黒と言う他ありません。</p><p> ではどの辺まで黒いか? 以下はすべて憶測になりますが、常識的な遵法意識とリスク感覚を持つ(であろう)上位の経営陣が最初からすべて把握していた、というのは考えづらい状況です。どちらかといえば、担当者数名くらいが暴走してこうなったような気がします、というかそれくらいが自然に思えます。</p><p> いずれにせよまともな会社のやることとしては悪質すぎるし、企業イメージへの悪影響も大きいので、上の憶測が正しい場合、もしこれ以上オオゴトになれば担当者は誰かしら処分されるんじゃない? と見ています。あーあ、、、、</p>
</div>
<div class="section">
<h3>他にもがばいよ!</h3>
<p> さすがに盗用と比べると霞んで見えますが、クオリティは低いです。</p>
<blockquote>
<p>ソースコード</p>
<pre class="code lang-python" data-lang="python" data-unlink>n = <span class="synConstant">1</span>
n+=<span class="synConstant">1</span>
<span class="synIdentifier">print</span> (n)
</pre><p><a href="https://techacademy.jp/magazine/18190">https://techacademy.jp/magazine/18190</a><br />
</p>
</blockquote>
<p> そのままコピペしました。きっと真似して書いた人は「IndentationError: unexpected indent」に悩まされるでしょう。</p><p> 推して知るべし・・・</p>
</div>
<div class="section">
<h3>今後の展開</h3>
<ul>
<li>とりあえずTechAcademyは事実関係を認めて謝罪した方が良いと思います。ライセンスの件についてはイマイチはっきりしませんが、アクセスしたユーザに嘘をついた(teratailのコピペをTechAcademyに寄せられた質問と回答として紹介した)ことは事実です。「なかったこと」にするには遅すぎます(最初から遅すぎるのだが)。逆に、本格的に炎上する前に傷を閉じられれば、相対的に浅く済む可能性もあります。</li>
<li>teratail運営はできれば早急にこの件についての立場を示すべき。「ああいう使い方をされるのを承知で売っていた疑惑」が少しでも残っている限り、ちょっと安心して使い続けることができません。</li>
</ul><p><b> →2019/03/25に問い合わせの結果が来て、「ライセンスしていない」とのことでした。今後の対応は協議中とのことです。</b><br />
詳細は記事末尾の追記を御覧ください。</p><p> 以下の2つは、権利の不当な侵害があったとした場合ですが、</p>
<ul>
<li>権利侵害の不当利益返還請求とかは、個人で考える気には正直なれません。<s>理論的にはできるだろうけど、手間に見合った額が取れるかと言うととても微妙な気しかしない。</s>そもそもteratailの投稿で投稿者が直接経済的な利益を得ている訳ではなく、ユーザから不当利益返還請求は難しいのでは? という考えに傾いています。teratail運営はTechAcademyの記事にPVが流れた分の損失を被っているので、できるかもしれないけど。</li>
<li>teratailの運営は、不当に権利を侵害されたのであればなんか言ってみるのはありだと思います。ただ、teratailの運営会社のレバレジーズ(本業は人材アウトソーシングや転職支援などです)と、TechAcademy側にはそれなりの取引関係があることを考慮すると、最終的に「穏便に済ませる」といった判断に落ち着くのではないでしょうか。さすがに「今後も野放し」というのは、一teratailユーザとしては支持できないところなので、ほどほどの落とし所を探ってほしいのですが。</li>
</ul><p> おまけ。</p>
<ul>
<li>この記事のアクセスが伸びる(伸びて)</li>
</ul>
</div>
<div class="section">
<h3>今後の予防策</h3>
<p> プログラミングスクールや、オウンドメディア系のIT記事などが世間を騒がせた事例は去年幾つかありました。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fqiita.com%2Fnkmk%2Fitems%2Fee346c0da365e988e2dd" title="侍エンジニア塾とAidemyの杜撰さから学ぶべきこと - Qiita" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://qiita.com/nkmk/items/ee346c0da365e988e2dd">侍エンジニア塾とAidemyの杜撰さから学ぶべきこと - Qiita</a></p><p> さすがにここまで続くと構造的な問題があるとしか言えません。予防策を書きます。</p><p> とりあえず一般ユーザーに対しては、以下くらいしか言えることがありません。</p>
<ul>
<li>オウンドメディア系記事は検索で出てきても信用しない。はっきり言ってクオリティの平均値は個人のブログ以下ですし、オウンドメディアによくある初心者向け的な内容であれば、書籍やチュートリアルを読んだ方がわかりやすくて正確な知識がつきます。</li>
<li>プログラミングスクールは・・・まあ、どうしても必要なら評判とか見て選んでください。オンライン学習なら書籍+progateとかやっすいサービスでも(優秀な人は)できると思うので、そういうのを検討するのもありです。また、オンラインスクール系よりは昔ながらの「専門学校」などの方が安定はしているでしょう。</li>
</ul><p> IT企業などの経営者の方が読んでいたらとしたら、私から伝えたいことは</p>
<ul>
<li>半端な気持ちで自社メディア、あるいは教育事業を運営できると思うな</li>
</ul><p> の一言ですね。まともにやるなら、相当のコストを覚悟してください。それで運営して黒字にならないなら、やるべきではないと思います。</p><p> また、すでにそういう自社メディア、事業を抱えてしまっている企業の方がもしいたら、</p>
<ul>
<li>いますぐ相当のコストを投入して、品質に問題がないかチェックし、問題があれば修正する</li>
</ul><p> のがおすすめです。潜在的な破壊力はすでに証明されていますから、もはや時限爆弾みたいなものです。炎上するまで放置するより、先になんとか処理した方が賢明だと思います。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> <b>とにかくひどい。</b>そういう感想しかありません。なんかあれこれ論評するまでもない。</p><p> とりあえず、関係者の皆さんには「まともに」対処してほしいところですね。</p>
</div>
<div class="section">
<h3>2019/03/23 追記</h3>
<p> 現時点では、これに関係する記事がほとんど削除されているようです。このまま幕引きを図るつもりだと思われます。</p><p> 今後の動向をチェックし続け、何かあれば編集します。また、この件についてteratailの運営にも問い合わせているので、そちらの進展もいずれご報告します。</p>
</div>
<div class="section">
<h3>2019/03/25 追記</h3>
<p> teratail運営への問い合わせで返信が得られたので、許可を得てこちらに掲載します。</p><p> 要約を先に書いておくと、</p>
<ul>
<li>teratailからのライセンスは行っていない</li>
<li>今後の対応は協議中</li>
</ul><p> とのことです。</p><p> 私が問い合わせた内容。</p>
<blockquote>
<p>送信日時: 2019/03/22 20:09:52<br />
タイトル: TechAcademyに投稿されたteratailの投稿と酷似した記事について<br />
本文 :<br />
お世話になっています。表題の件について伺いたいことがあります。<br />
TechAcademyというサービスのオウンドメディア上において、teratailの質問・回答と酷似した内容が投稿されているということがインターネット上で話題になっております。<br />
この件について以下の点について確認したいと思います。<br />
1. これはレバレジーズが正式に権利をライセンスしたものか<br />
2.a. 1.について、そうであれば、妥当なものと判断し、今後対応も行わないというこか<br />
2.b. 1.について、そうでなければ、現時点で今後の対応は検討しているか<br />
(2.aと2.bは当てはまる方だけ回答していただければ構いません)<br />
3. 利用規約第9条(権利帰属)から、ライセンスされたものであれば各ユーザはTechAcademyの運営会社について関連する権利を主張できない反面、そうでなければ原理的には通常通り権利侵害を申し立てられると理解しているが、それで正しいか</p><p>また、このメールと返信の公開の可否についてもお伺いしたいと思います。<br />
お忙しいとは思いますが、何卒よろしくおねがいします。</p>
</blockquote>
<p> 返信。</p>
<blockquote>
<p>いつもご利用ありがとうございます。teratailサポートチームです。</p><p>この度は、お問い合わせありがとうございます。</p><p>お問い合わせいただいた件について、teratail側から記事使用のライセンス等は行っておりません。<br />
teratailがユーザー様の投稿を活用した活動を行う場合は、ユーザー様が認識できる方法でお知らせをさせていただきます。</p><p>今後の対応については、現在協議中です。<br />
ユーザー様に安心してご利用いただけるサービス運営に努力してまいります。</p><p>こちらの返信内容については、そのまま公開していただいて差し支えありません。</p><p>今後もteratailをよろしくお願いいたします。</p>
</blockquote>
<p> 何はともあれ、teratailからライセンスはしていないとのことで、ほっとしました。</p><p> 今後は、</p>
<ul>
<li>teratail運営の(公式発表、TechAcademy側への措置などを含めた)対応</li>
<li>TechAcademy側の対応</li>
</ul><p> に注目が集まりそうです。</p>
</div>
<div class="section">
<h3>2019/03/26 追記</h3>
<p> 25日の夜に動きがありました。</p><p> 以降は続報記事で扱います。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F03%2F26%2F093433" title="TechAcademy盗用事件 公式発表と深まる疑念 - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/03/26/093433">TechAcademy盗用事件 公式発表と深まる疑念 - 静かなる名辞</a><br />
</p>
</div>
<div class="section">
<h3>2019/04/15 続報</h3>
<p> その後動きはほとんどなかったのですが、続報とまとめです。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F04%2F15%2F145920" title="TechAcademyのその後 - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/04/15/145920">TechAcademyのその後 - 静かなる名辞</a></p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-662adae2" name="f-662adae2" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">私がteratailを使い続けるかどうかも考え直さないといけなくなります</span></p>
<p class="footnote"><a href="#fn-11606428" name="f-11606428" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">なお、それまでにこの記事が集めたPVは本ブログの一日の総PVの1割未満であり、集めたはてブやtwitterのシェアも片手で数えられる程度で、現時点で世間にさほど大きな影響を及ぼしてはいないことを付記しておきます</span></p>
<p class="footnote"><a href="#fn-1b34007c" name="f-1b34007c" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">また、この件については私からteratail運営に問い合わせを行っています。結果が返ってくれば追記しますが、あまり期待しないでください</span></p>
<p class="footnote"><a href="#fn-6e56f874" name="f-6e56f874" class="footnote-number">*4</a><span class="footnote-delimiter">:</span><span class="footnote-text">あるいはメディア運営をまるごと別会社に委託しているとか、そういう可能性もあるかもしれませんが、考慮しません</span></p>
</div>
hayataka2049
multiprocessing.Poolがやたらメモリを消費するときの対策
hatenablog://entry/10257846132691519570
2018-12-28T20:35:55+09:00
2019-02-21T00:16:40+09:00 概要 multiprocessing.Poolは原理的にプロセスをforkさせるので、メインプロセスに大きなデータが残っているとそれが丸々コピーされてメモリ領域を食います。 グローバル関数限定ですが、initializerを使って必要ないデータを消すことができます。また、Poolを作るタイミングを工夫することでそもそも大きいデータが子プロセスに引き継がれないようにすることができます。 前提状況の説明 以下のようなコードです。 import subprocess from multiprocessing import Pool import numpy as np a = np.arange(1…
<div class="section">
<h3>概要</h3>
<p> multiprocessing.Poolは原理的にプロセスをforkさせるので、メインプロセスに大きなデータが残っているとそれが丸々コピーされてメモリ領域を食います。</p><p> グローバル関数限定ですが、initializerを使って必要ないデータを消すことができます。また、Poolを作るタイミングを工夫することでそもそも大きいデータが子プロセスに引き継がれないようにすることができます。</p>
</div>
<div class="section">
<h3>前提状況の説明</h3>
<p> 以下のようなコードです。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">import</span> subprocess
<span class="synPreProc">from</span> multiprocessing <span class="synPreProc">import</span> Pool
<span class="synPreProc">import</span> numpy <span class="synStatement">as</span> np
a = np.arange(<span class="synConstant">10</span>**<span class="synConstant">7</span>)
<span class="synStatement">def</span> <span class="synIdentifier">f</span>():
subprocess.run(<span class="synConstant">"ps -aux | grep [m]emory_test"</span>, shell=<span class="synIdentifier">True</span>)
p = Pool(<span class="synConstant">1</span>)
p.<span class="synIdentifier">apply</span>(f)
p.close()
p.terminate()
<span class="synIdentifier">print</span>(a.shape)
</pre><p> 見るからにメモリをドカ食いしそうな10**7のnumpy配列を確保しています。実行すると、以下のようになります。</p>
<pre class="code" data-lang="" data-unlink>username 7407 44.0 1.2 543952 100056 pts/0 Sl+ 20:25 0:00 python memory_test.py
username 7411 0.0 1.1 347344 94640 pts/0 S+ 20:25 0:00 python memory_test.py
(10000000,)</pre><p> もし子プロセスで走らせたいのがaを使わない処理なら、無駄に大容量のメモリを食っていることになります。</p>
</div>
<div class="section">
<h3>対策1:initializerで消す</h3>
<div class="section">
<h4>実験</h4>
<p> 以下のようなコードを書いてみます。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">import</span> subprocess
<span class="synPreProc">from</span> multiprocessing <span class="synPreProc">import</span> Pool
<span class="synPreProc">import</span> numpy <span class="synStatement">as</span> np
a = np.arange(<span class="synConstant">10</span>**<span class="synConstant">7</span>)
<span class="synStatement">def</span> <span class="synIdentifier">f</span>():
subprocess.run(<span class="synConstant">"ps -aux | grep [m]emory_test"</span>, shell=<span class="synIdentifier">True</span>)
<span class="synStatement">def</span> <span class="synIdentifier">initializer</span>():
<span class="synStatement">del</span> <span class="synIdentifier">globals</span>()[<span class="synConstant">"a"</span>]
p = Pool(<span class="synConstant">1</span>, initializer=initializer)
p.<span class="synIdentifier">apply</span>(f)
p.close()
p.terminate()
<span class="synIdentifier">print</span>(a.shape) <span class="synComment"># ちゃんといることの確認</span>
</pre><pre class="code" data-lang="" data-unlink>username 7427 0.0 1.2 543948 100112 pts/0 Sl+ 20:26 0:00 python memory_test.py
username 7431 0.0 0.2 269212 16548 pts/0 S+ 20:26 0:00 python memory_test.py
(10000000,)</pre><p> だいぶ改善しました。</p>
</div>
<div class="section">
<h4>本末転倒というか・・・</h4>
<p> まあ、見ての通りエレガントな方法ではありません。また、globals()は書き換えられてもlocals()は書き換えられないので、ローカル変数には効きません。</p><p> そこで2番目の対策を考えます。</p>
</div>
</div>
<div class="section">
<h3>対策2:早めにPoolを作る</h3>
<div class="section">
<h4>説明</h4>
<p> 上のコードでaが作られる以前にPoolを作れば、その時点でforkするのでメモリどか食い現象は回避できます。</p><p> こんな感じですね。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">import</span> subprocess
<span class="synPreProc">from</span> multiprocessing <span class="synPreProc">import</span> Pool
<span class="synPreProc">import</span> numpy <span class="synStatement">as</span> np
<span class="synStatement">def</span> <span class="synIdentifier">f</span>():
subprocess.run(<span class="synConstant">"ps -aux | grep [m]emory_test"</span>, shell=<span class="synIdentifier">True</span>)
p = Pool(<span class="synConstant">1</span>)
a = np.arange(<span class="synConstant">10</span>**<span class="synConstant">7</span>)
p.<span class="synIdentifier">apply</span>(f)
p.close()
p.terminate()
<span class="synIdentifier">print</span>(a.shape)
</pre><pre class="code" data-lang="" data-unlink>username 7525 0.0 1.2 543952 100116 pts/0 Sl+ 20:31 0:00 python memory_test.py
username 7529 0.0 0.2 269216 16512 pts/0 S+ 20:31 0:00 python memory_test.py
(10000000,)</pre><p> initializerで消すのと同等の効果がありますが、こちらだとローカル変数でも大丈夫です。また、グローバル変数をdelする方法だと、initializerが走るまでの一瞬の間は無駄なデータがメモリを消費する訳で、そういう面でもこちらの方が有利だと思います。</p>
</div>
</div>
<div class="section">
<h3>まとめ</h3>
<p> 早めに(重いデータがメモリに読み込まれる前に)forkしておくのが基本ですが、どうしても駄目なときは削除も試してみましょう。</p>
</div>
<div class="section">
<h3>追記</h3>
<p> プロセスの開始方法に"spawn"を指定することでも可能だとコメントでご指摘をいただきました。</p>
<blockquote>
<p>spawn<br />
親プロセスは新たに python インタープリタープロセスを開始します。子プロセスはプロセスオブジェクトの run() メソッドの実行に必要なリソースのみ継承します。特に、親プロセスからの不要なファイル記述子とハンドルは継承されません。この方式を使用したプロセスの開始は fork や forkserver に比べ遅くなります。</p><p>Unix と Windows で利用可能。Windows でのデフォルト。</p><p><a href="https://docs.python.jp/3/library/multiprocessing.html#contexts-and-start-methods">17.2. multiprocessing — プロセスベースの並列処理 — Python 3.6.5 ドキュメント</a><br />
</p>
</blockquote>
<p> multiprocessing.get_context('spawn')とすると、multiprocessingモジュールと同じAPIを持つオブジェクトが返り、これからPoolを作ることで解決できます。これを利用しても良さそうです。</p>
</div>
hayataka2049
【python】numbaを使ってライフゲームを書いてみた
hatenablog://entry/10257846132685252226
2018-12-15T17:31:45+09:00
2020-04-14T02:55:43+09:00 概要 ライフゲームを書きました。 素のpythonだと何をやっても激遅だったので、numbaで高速化しました。 方針 まず実装の方針を決めます。主要な関数としては以下のものがあればできると思いました。 update_cell 1セルの状態を更新する update_field フィールド全体を更新する main メインループ、描画など 最初からnumbaを使ってみるつもりでしたが、numbaは割と制約が多いので、基本的にpython的なコードにするとJITコンパイルに失敗します。それを意識してコーディングしました。 (nopython=Trueオプションを付けてコンパイルできる状態でないと、まっ…
<div class="section">
<h3>概要</h3>
<p> ライフゲームを書きました。</p><p> 素のpythonだと何をやっても激遅だったので、numbaで高速化しました。</p>
</div>
<div class="section">
<h3>方針</h3>
<p> まず実装の方針を決めます。主要な関数としては以下のものがあればできると思いました。</p>
<ul>
<li>update_cell</li>
</ul><p> 1セルの状態を更新する</p>
<ul>
<li>update_field</li>
</ul><p> フィールド全体を更新する</p>
<ul>
<li>main</li>
</ul><p> メインループ、描画など</p><p> 最初からnumbaを使ってみるつもりでしたが、numbaは割と制約が多いので、基本的にpython的なコードにするとJITコンパイルに失敗します。それを意識してコーディングしました。<br />
(nopython=Trueオプションを付けてコンパイルできる状態でないと、まったく速くなりません。みなさんも注意してください)</p>
</div>
<div class="section">
<h3>実装の説明</h3>
<p> 実装の詳細について説明します。</p>
<div class="section">
<h4>グローバル変数</h4>
<p> グローバル変数として以下の2つを定義しました。</p>
<pre class="code lang-python" data-lang="python" data-unlink>field_w = <span class="synConstant">200</span>
field_h = <span class="synConstant">200</span>
</pre><p> フィールドのサイズはグローバル変数で書いておいた方が楽だろう、という判断です。なお、とりあえず200*200を指定していますが、私のマシンでは600*600くらいまでは1ステップ1秒未満で計算できます。見てて楽しいのはもっと小さいフィールドですが。</p>
</div>
<div class="section">
<h4>get_ijlst関数</h4>
<p> ライフゲームを書こうとしたとき、誰もが思うのは「周囲8セルの座標を出すのが面倒くさい」ということでしょう。(i, j+1), (i, j-1), (i+1, j+1),...みたいにやっていけば良いことはわかりますが、フィールドからのはみ出しなどを考慮すると大変そうです。</p><p> そこで、その部分を簡略化するべく関数を1つ作りました。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">@</span><span class="synIdentifier">nb.jit</span>(nopython=<span class="synIdentifier">True</span>)
<span class="synStatement">def</span> <span class="synIdentifier">get_ijlst</span>(x, limit):
ret = []
<span class="synStatement">if</span> <span class="synConstant">0</span> < x:
ret.append(x-<span class="synConstant">1</span>)
<span class="synStatement">if</span> x < limit-<span class="synConstant">1</span>:
ret.append(x+<span class="synConstant">1</span>)
ret.append(x)
<span class="synStatement">return</span> ret
</pre><p> 基本的には[x-1, x+1, x]のlistを返しますが、0 <= x < limitの範囲に収まらない要素は返り値のlistの中に含めないような処理をするための関数です。なお、これは次に説明するupdate_cell関数から呼ぶため、jitコンパイルしています。</p>
</div>
<div class="section">
<h4>update_cell関数</h4>
<p> 先にコードを示します。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">@</span><span class="synIdentifier">nb.jit</span>(nopython=<span class="synIdentifier">True</span>)
<span class="synStatement">def</span> <span class="synIdentifier">cell_update</span>(i, j, field, out):
i_lst = get_ijlst(i, field_h)
j_lst = get_ijlst(j, field_w)
s = <span class="synConstant">0</span>
<span class="synStatement">for</span> ni <span class="synStatement">in</span> i_lst:
<span class="synStatement">for</span> nj <span class="synStatement">in</span> j_lst:
s += field[ni, nj]
s -= field[i,j]
<span class="synStatement">if</span> s < <span class="synConstant">2</span>:
out[i,j] = <span class="synConstant">0</span>
<span class="synStatement">elif</span> s == <span class="synConstant">2</span>:
out[i,j] = field[i,j]
<span class="synStatement">elif</span> s == <span class="synConstant">3</span>:
out[i,j] = <span class="synConstant">1</span>
<span class="synStatement">elif</span> s >= <span class="synConstant">4</span>:
out[i,j] = <span class="synConstant">0</span>
<span class="synStatement">else</span>:
<span class="synStatement">raise</span> <span class="synType">Exception</span>
</pre><p> 座標値のi,jとnumpy配列のfield, outを受け取り、fieldに従って計算した次の状態をoutに書き込みます。</p><p> 上のforループのあたりのコードは周囲8マスの総和の計算ですが、実は中心の(i,j)の値もループ対象にして総和を格納する変数sに加算し、後から中心の値をsから引いています。ループの中にifなどを入れて判定するより処理速度的に安上がりだろうという判断です。</p><p> その下にあるif文はライフゲームのルールを実装しています。周囲8マスの総和をsとおくと、</p>
<ul>
<li>sが2未満なら死(過疎)</li>
<li>sが2なら元と同じ値</li>
<li>sが3なら誕生する。元の生死にかかわらず1</li>
<li>sが4以上なら死(過密)</li>
</ul><p> と表せます。なお、これ以外のパターンはルール上ありえないので、万が一へんな値が来たときに備えてelse節で例外を投げています(限りなくデバッグ用に近い)。</p>
</div>
<div class="section">
<h4>update_field関数</h4>
<p> こちらはシンプルです。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">def</span> <span class="synIdentifier">update_field</span>(pair_lst):
<span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(field_h):
<span class="synStatement">for</span> j <span class="synStatement">in</span> <span class="synIdentifier">range</span>(field_w):
cell_update(i, j, pair_lst[<span class="synConstant">0</span>], pair_lst[<span class="synConstant">1</span>])
pair_lst.append(pair_lst.pop(<span class="synConstant">0</span>))
</pre><p> 工夫したのはpair_lstでしょうか。これは同じサイズ(shape=(field_h, field_w))の2つのnumpy配列を要素に持つlistを受け取ることを想定しています。このlistは呼び出し元(main)で定義します。</p><p> 最後の行が何をしているのか、初見では理解できないと思いますが、</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> lst = [<span class="synConstant">0</span>,<span class="synConstant">1</span>]
>>> lst.append(lst.pop(<span class="synConstant">0</span>))
>>> lst
[<span class="synConstant">1</span>, <span class="synConstant">0</span>]
</pre><p> このように値を入れ替えられるというアイデアです。つまり、2つの配列を最初に作り、ずっと同じ2つを新旧を入れ替えながら使うということです。これによりオーバーヘッドの削減を狙っています。</p>
</div>
<div class="section">
<h4>main</h4>
<p> 必要な配列を定義し、更新・描画のループを回しているだけです。手抜きによりmatplotlibでアニメーション描画しています。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">def</span> <span class="synIdentifier">main</span>():
field = (np.random.random(size=(field_h, field_w)) > <span class="synConstant">0.9</span>).astype(np.int16)
out = np.zeros(shape=(field_h, field_w)).astype(np.int16)
pair_lst = [field, out]
img = plt.imshow(field)
<span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">1000</span>):
update_field(pair_lst)
img.set_data(pair_lst[<span class="synConstant">0</span>])
plt.pause(<span class="synConstant">0.001</span>)
</pre><p><span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><br />
<p></p>
</div>
<div class="section">
<h4>コード全文</h4>
<p> コードの全体を以下に示します。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">import</span> numpy <span class="synStatement">as</span> np
<span class="synPreProc">import</span> numba <span class="synStatement">as</span> nb
<span class="synPreProc">import</span> matplotlib.pyplot <span class="synStatement">as</span> plt
field_w = <span class="synConstant">40</span>
field_h = <span class="synConstant">60</span>
<span class="synPreProc">@</span><span class="synIdentifier">nb.jit</span>(nopython=<span class="synIdentifier">True</span>)
<span class="synStatement">def</span> <span class="synIdentifier">get_ijlst</span>(x, limit):
ret = []
<span class="synStatement">if</span> <span class="synConstant">0</span> < x:
ret.append(x-<span class="synConstant">1</span>)
<span class="synStatement">if</span> x < limit-<span class="synConstant">1</span>:
ret.append(x+<span class="synConstant">1</span>)
ret.append(x)
<span class="synStatement">return</span> ret
<span class="synPreProc">@</span><span class="synIdentifier">nb.jit</span>(nopython=<span class="synIdentifier">True</span>)
<span class="synStatement">def</span> <span class="synIdentifier">update_cell</span>(i, j, field, out):
i_lst = get_ijlst(i, field_h)
j_lst = get_ijlst(j, field_w)
s = <span class="synConstant">0</span>
<span class="synStatement">for</span> ni <span class="synStatement">in</span> i_lst:
<span class="synStatement">for</span> nj <span class="synStatement">in</span> j_lst:
s += field[ni, nj]
s -= field[i,j]
<span class="synStatement">if</span> s < <span class="synConstant">2</span>:
out[i,j] = <span class="synConstant">0</span>
<span class="synStatement">elif</span> s == <span class="synConstant">2</span>:
out[i,j] = field[i,j]
<span class="synStatement">elif</span> s == <span class="synConstant">3</span>:
out[i,j] = <span class="synConstant">1</span>
<span class="synStatement">elif</span> s >= <span class="synConstant">4</span>:
out[i,j] = <span class="synConstant">0</span>
<span class="synStatement">else</span>:
<span class="synStatement">raise</span> <span class="synType">Exception</span>
<span class="synStatement">def</span> <span class="synIdentifier">update_field</span>(pair_lst):
<span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(field_h):
<span class="synStatement">for</span> j <span class="synStatement">in</span> <span class="synIdentifier">range</span>(field_w):
update_cell(i, j, pair_lst[<span class="synConstant">0</span>], pair_lst[<span class="synConstant">1</span>])
pair_lst.append(pair_lst.pop(<span class="synConstant">0</span>))
<span class="synStatement">def</span> <span class="synIdentifier">main</span>():
field = (np.random.random(size=(field_h, field_w)) > <span class="synConstant">0.9</span>).astype(np.int16)
out = np.zeros(shape=(field_h, field_w)).astype(np.int16)
pair_lst = [field, out]
img = plt.imshow(field)
<span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">1000</span>):
update_field(pair_lst)
img.set_data(pair_lst[<span class="synConstant">0</span>])
plt.pause(<span class="synConstant">0.001</span>)
<span class="synStatement">if</span> __name__ == <span class="synConstant">"__main__"</span>:
main()
</pre>
</div>
</div>
<div class="section">
<h3>計測</h3>
<p> 描画処理をコメントアウトし、JITコンパイルを付けたときと外したときで200*200のフィールドを20ステップ進めるのにかかる時間を計測してみました。</p>
<ul>
<li>JITコンパイルなし</li>
</ul><p> 8.8秒</p>
<ul>
<li>JITコンパイルあり</li>
</ul><p> 1.4秒</p><p> 6倍強の高速化が達成されました。・・・ってちょっと微妙ですね。威張るほどでもない。</p><p> numbaの型指定をしていないからかもしれないし、そもそもこんなものという可能性もあります。</p>
</div>
<div class="section">
<h3>画像</h3>
<p> 50*50のフィールドで、グライダーが生まれたタイミングを見計らって一枚スクショしてみました。</p><p><figure class="figure-image figure-image-fotolife" title="結果"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20181215/20181215172956.png" alt="結果" title="f:id:hayataka2049:20181215172956p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>結果</figcaption></figure></p><p> 色合いが変なのはcmapをデフォルトのまま変えていないからです。</p><p> 動いているのが見たい方は、コードをコピペして手元環境で実行してください。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> 案外シンプルに書けたし、numbaでの高速化を試す良い機会にもなったと思います。</p>
</div>
<div class="section">
<h3>追記</h3>
<p> CUIでも実行できるようにしました。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F01%2F12%2F174853" title="【python】ターミナル上でCUIでライフゲーム - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><a href="https://www.haya-programming.com/entry/2019/01/12/174853">【python】ターミナル上でCUIでライフゲーム - 静かなる名辞</a><br />
</p>
</div>
<div class="section">
<h3>追記2</h3>
<p> 最近numbaの正しい使い方を知りました。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2020%2F04%2F09%2F062624" title="numbaとnumpyで速いループ処理を書くためのガイド(スレッド並列化のおまけつき)(実はポエム) - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://www.haya-programming.com/entry/2020/04/09/062624">www.haya-programming.com</a></cite></p><p> この知見を活かして型の情報を書いてみました。2つに分けていた関数は大した処理ではないのでまとめました。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">@</span><span class="synIdentifier">nb.jit</span>(<span class="synConstant">"void(i8, i8, i2[:, :], i2[:, :])"</span>, nopython=<span class="synIdentifier">True</span>)
<span class="synStatement">def</span> <span class="synIdentifier">update_cell</span>(i, j, field, out):
i_lst = [i]
j_lst = [j]
<span class="synStatement">if</span> <span class="synConstant">0</span> < i:
i_lst.append(i-<span class="synConstant">1</span>)
<span class="synStatement">if</span> <span class="synConstant">0</span> < j:
j_lst.append(j-<span class="synConstant">1</span>)
<span class="synStatement">if</span> i < field_h:
i_lst.append(i+<span class="synConstant">1</span>)
<span class="synStatement">if</span> j < field_w:
j_lst.append(j+<span class="synConstant">1</span>)
s = <span class="synConstant">0</span>
<span class="synStatement">for</span> ni <span class="synStatement">in</span> i_lst:
<span class="synStatement">for</span> nj <span class="synStatement">in</span> j_lst:
s += field[ni, nj]
s -= field[i,j]
<span class="synStatement">if</span> s < <span class="synConstant">2</span>:
out[i,j] = <span class="synConstant">0</span>
<span class="synStatement">elif</span> s == <span class="synConstant">2</span>:
out[i,j] = field[i,j]
<span class="synStatement">elif</span> s == <span class="synConstant">3</span>:
out[i,j] = <span class="synConstant">1</span>
<span class="synStatement">elif</span> s >= <span class="synConstant">4</span>:
out[i,j] = <span class="synConstant">0</span>
<span class="synStatement">else</span>:
<span class="synStatement">raise</span> <span class="synType">Exception</span>
</pre><p> 元のコードでは1.4秒(ライブラリのアップデートにも関わらずほとんど変わらなかった)かかっていたものが、0.9秒に高速化されました。</p><p> こうなるともう少し速くならないかと思うのが人情で、こっちもJITコンパイルすることにします。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">@</span><span class="synIdentifier">nb.jit</span>(<span class="synConstant">"void(i2[:, :], i2[:, :])"</span>, nopython=<span class="synIdentifier">True</span>)
<span class="synStatement">def</span> <span class="synIdentifier">update_field</span>(a, b):
<span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(field_h):
<span class="synStatement">for</span> j <span class="synStatement">in</span> <span class="synIdentifier">range</span>(field_w):
update_cell(i, j, a, b)
</pre><p> 呼び出し側はこうします。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">def</span> <span class="synIdentifier">main</span>():
field = (np.random.random(size=(field_h, field_w)) > <span class="synConstant">0.9</span>).astype(np.int16)
out = np.zeros(shape=(field_h, field_w)).astype(np.int16)
pair_lst = [field, out]
t1 = time.time()
<span class="synComment"># img = plt.imshow(field)</span>
<span class="synStatement">for</span> i <span class="synStatement">in</span> <span class="synIdentifier">range</span>(<span class="synConstant">20</span>):
update_field(*pair_lst)
pair_lst.append(pair_lst.pop(<span class="synConstant">0</span>))
<span class="synComment"># img.set_data(pair_lst[0])</span>
<span class="synComment"># plt.pause(0.001)</span>
t2 = time.time()
<span class="synIdentifier">print</span>(t2- t1)
</pre><p> 0.4秒に高速化されました。こんな感じで速くなるので、なかなか大したものだと思いました。</p>
</div>
hayataka2049
プログラミングのブログにアドセンスを貼る話
hatenablog://entry/10257846132678855445
2018-12-02T09:53:48+09:00
2019-07-10T20:56:54+09:00 はじめに 一ヶ月ほど前から当ブログはGoogle Adsenseを導入しています*1。 このブログはいわゆる「技術ブログ」と呼ばれるようなプログラミングのブログですが、プログラミング関連のジャンルでアドセンスを貼った場合の収益性についてはネット上にもあまり情報がありませんでした。なので貼る前は「びっくりするほど儲からなかったらどうしよう」などと思っていたのですが、とりあえずそれに関しては杞憂かな、という水準では稼げそうです。 ご報告を兼ねて、内実をレポートします。 なお、規約の絡みでPVや収益などの指標の具体的な数字は公表できません。あしからず。以下に出てくる数字は、有効数字一桁くらいのアバウ…
<div class="section">
<h3>はじめに</h3>
<p> 一ヶ月ほど前から当ブログはGoogle Adsenseを導入しています<a href="#f-40d98614" name="fn-40d98614" title="邪魔と思われている読者の方も当然おられるかと思いますが、私の小遣いに直結する問題なので、生暖かい目で見守っていただければなぁ、と思います。">*1</a>。</p><p> このブログはいわゆる「技術ブログ」と呼ばれるようなプログラミングのブログですが、プログラミング関連のジャンルでアドセンスを貼った場合の収益性についてはネット上にもあまり情報がありませんでした。なので貼る前は「びっくりするほど儲からなかったらどうしよう」などと思っていたのですが、とりあえずそれに関しては杞憂かな、という水準では稼げそうです。</p><p> ご報告を兼ねて、内実をレポートします。</p><p> なお、規約の絡みでPVや収益などの指標の具体的な数字は公表できません。あしからず。以下に出てくる数字は、有効数字一桁くらいのアバウトなものだと思ってください。基本的にボカして書いています。</p>
</div>
<div class="section">
<h3>このブログのPVと収益性</h3>
<p> まずこのブログの一日のPVですが、先月の数字を平均すると一日2000 PV弱くらいです。記事数はこの記事で183記事目で、1記事あたり10 PV強が得られていることになります。</p><p> アドセンスの収益性の指標としては、ページRPMというものがあります。これは1000 PVで得られる収益のことです。これを1000で割れば収益[円]/閲覧数[PV]になるので、こちらで示します。当ブログでは0.2円/PV前後です。</p><p> なので、アバウトですが一日400円弱ほど儲かるかなぁ、という収益性になっています。一ヶ月では一万円くらいです。これをしょぼいと見るか、小遣い稼ぎとしては優秀と見るかは、人によって分かれると思います。</p>
</div>
<div class="section">
<h3>収益の傾向</h3>
<p> プログラミングのブログというジャンルには、幾つかの特色があるようです。世間で言われているアドセンスとは、ちょっと違う傾向が見えました。</p>
<div class="section">
<h4>ユーザのほとんどはPCからアクセス</h4>
<p> アクセスの9割はPCからです。プログラミングをしながら調べごとをして当ブログにたどり着く方が多いと思うので、当たり前だと思います。</p><p> このおかげで、PC向けに最適化すればとりあえず問題なく収益があがります。</p><p> SEOとかアフィリエイトのサイトには、「現在はモバイルからのアクセスがほとんどなので、サイドバー広告は効果が少ない」なんて書いてあるところが幾らでもありますが、当ブログではサイドバー広告は立派な主力です。</p><p> モバイル向けに最適化しようとすると、入れるのが面倒な上に本格的に邪魔な記事中広告を主力にせざるを得ないと思うので、これは嬉しい傾向です。サイトのユーザビリティを大きく損なわずにアドセンスで稼げます。<br />
(余談ですが、一番稼いでくれるのはブログの一番上にでかでかと貼ってあるヘッダ広告です。印象は最悪なんだろうけど、全収益の2/5くらいをはじき出しています)</p>
</div>
<div class="section">
<h4>低いクリック率とそこそこのクリック単価</h4>
<p> よく巷のサイトには「ITスキルの高いユーザが多いサイトは広告のクリック率が下がる」などと書いてありますが、その理論で行くとプログラミングのジャンルのユーザなんてITスキル最強みたいなものですからクリック率は低いはずです。このブログも案の定というか、0.1%という「低い」クリック率をはじき出しています(平均で0.3%、本格的なアフィサイトであれば1%くらいは行くそうです)。</p><p> それでも、クリックが「0ではない」というのは励みになる要素で、まあ何千人も来ていれば一定の確率で広告をクリックする人はいるということでしょう。</p><p> 「そんなにクリック率が低くて儲かるのかよ」と思う方もいると思いますが、広告単価が高いものが多いっぽく、なんとか補えます。恐らく、単価が高めの転職系、学習系、IT製品系などが表示されていることの結果だと思います。</p><p> アドセンスのクリック単価の平均は30~40円くらいらしいですが、当ブログはその倍は軽く叩き出しています。</p><p> なので、最終的にはクリック率の低さと広告単価の高さが相殺しあって、世間並みにはカネになってるのかな? という印象です。</p>
</div>
<div class="section">
<h4>準主力のCPM</h4>
<p> アドセンスというと、普通はクリック単価広告の印象が強いと思いますが、実はCPMというインプレッション単価型の広告(広告の表示で収益が発生する/広告主からすると表示される回数にお金を払う)も存在します。</p><p> なんか、軽く調べた感じだと、普通のサイトではCPM型の総収益比は2割未満らしいのですが……何しろ上述の通りのクリック率なので、このブログではCPMも準主力くらいには稼いでくれます。日によって変動はありますが、一日の収益の1/3~1/2くらいは稼いでくれていると思います。インプレッション収益も、クリック単価型と遜色ありません。むしろ日によっては上回ることすらあります。</p><p> CPM型の広告は、PVに比例して着実に収益が伸びていきます。サイト運営者からすれば運次第な要素のあるクリック単価型広告とは違い、十数分おきに確認するたびに(確認してどうするんだ、って話ですが)コツコツ1円ずつ収益が積み上がっていくので、心に優しい広告です。</p>
</div>
</div>
<div class="section">
<h3>割に合うの?</h3>
<p> これについて知りたい方も多いと思いますが、結論から言えばたぶん仕事としては割に合わないです。ある程度効率的に運営できたとしても、時給500円くらいだと思います(記事を書く労力、維持管理する労力を適当に時間換算すれば、自ずと結論はでます)。</p><p> ただし、ブログ運営は「趣味」ですから、そう考えると「趣味」をやるだけで、</p>
<ul>
<li>時給500円稼げる</li>
<li>さやかながら我が国のITの発展に貢献できる(かもしれない)</li>
</ul><p> なので、皆さんも(書くネタがあれば)プログラミングとか技術系のブログを作ってみてください<a href="#f-43f0cceb" name="fn-43f0cceb" title="でもものすごく流行っちゃって、広告の需給が悪化して単価下がったりすると(私が)困るので、この記事を読んで「プログラミングのブログを始めてみようかな」と思い立つ人は2人か3人いればそれで良いです">*2</a>。<br />
<br />
</p>
</div>
<div class="section">
<h3>結論</h3>
<p> 儲かるかというと微妙なのですが、稼げないというほどでもないという程度には稼げます。</p><p> 強弁すれば小遣い稼ぎにはちょうど良いと見れなくもありませんが、積極的に人におすすめはしません。でも、このブログを完全放置しても月1万円になるので<a href="#f-edcf8d7b" name="fn-edcf8d7b" title="ただし1万円をずっと維持できる訳ではないことに注意。プログラミングの記事なんて、数年もすれば検索順位下落・トレンドの移り変わりで読まれなくなることでしょう">*3</a>、私は貼り続けます。そんなところです。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-40d98614" name="f-40d98614" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">邪魔と思われている読者の方も当然おられるかと思いますが、私の小遣いに直結する問題なので、生暖かい目で見守っていただければなぁ、と思います。</span></p>
<p class="footnote"><a href="#fn-43f0cceb" name="f-43f0cceb" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">でもものすごく流行っちゃって、広告の需給が悪化して単価下がったりすると(私が)困るので、この記事を読んで「プログラミングのブログを始めてみようかな」と思い立つ人は2人か3人いればそれで良いです</span></p>
<p class="footnote"><a href="#fn-edcf8d7b" name="f-edcf8d7b" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">ただし1万円をずっと維持できる訳ではないことに注意。プログラミングの記事なんて、数年もすれば検索順位下落・トレンドの移り変わりで読まれなくなることでしょう</span></p>
</div>
hayataka2049
C言語でshellの多段パイプを実装
hatenablog://entry/10257846132666181702
2018-11-08T18:53:49+09:00
2018-11-28T19:08:40+09:00 はじめに 学校の課題でCでshellもどきを書きました。 今後、同じ目にあう人のために、「shellの多段パイプをどうやって実装したら良いのか」を記事としてまとめておきます。 目次 はじめに パイプの概要 使用する関数 int pipe(int pipefd[2]) int close(int fd) int dup2(int oldfd, int newfd) pid_t fork(void) pid_t wait(int *status) int execvp(const char *file, char *const argv[]) パイプの実装方針 コード 改良した方が良い点 まとめ …
<div class="section">
<h3 id="はじめに">はじめに</h3>
<p> 学校の課題でCでshellもどきを書きました。</p><p> 今後、同じ目にあう人のために、「shellの多段パイプをどうやって実装したら良いのか」を記事としてまとめておきます。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#はじめに">はじめに</a></li>
<li><a href="#パイプの概要">パイプの概要</a></li>
<li><a href="#使用する関数">使用する関数</a><ul>
<li><a href="#int-pipeint-pipefd2">int pipe(int pipefd[2])</a></li>
<li><a href="#int-closeint-fd">int close(int fd)</a></li>
<li><a href="#int-dup2int-oldfd-int-newfd">int dup2(int oldfd, int newfd)</a></li>
<li><a href="#pid_t-forkvoid">pid_t fork(void)</a></li>
<li><a href="#pid_t-waitint-status">pid_t wait(int *status)</a></li>
<li><a href="#int-execvpconst-char-file-char-const-argv">int execvp(const char *file, char *const argv[])</a></li>
</ul>
</li>
<li><a href="#パイプの実装方針">パイプの実装方針</a></li>
<li><a href="#コード">コード</a></li>
<li><a href="#改良した方が良い点">改良した方が良い点</a></li>
<li><a href="#まとめ">まとめ</a></li>
<li><a href="#参考にしたサイト">参考にしたサイト</a></li>
</ul>
</div>
<div class="section">
<h3 id="パイプの概要">パイプの概要</h3>
<p> shellのパイプとは……という話はさすがに要らないと思いますが、以下のような機能があります。なお、下記サンプルの実行時に、カレントディレクトリに今回の記事で紹介するCのコードtest.cを置いてあるとします(内容については後述します)。</p>
<pre class="code" data-lang="" data-unlink>$ cat test.c | head | grep char
char *cmd1[] = {"cat", "test.c", NULL};
char *cmd2[] = {"head", NULL};
char *cmd3[] = {"grep", "char", NULL};
char **cmds[] = {cmd1, cmd2, cmd3};</pre><p> 「cat test.c」はtest.cの内容を標準出力に吐き出します。が、今回はその出力はパイプによって「head」に繋がれます。「head」は入力の先頭10行を出力するコマンドです。その出力も「grep char」の入力に繋がれて、先頭10行の中でcharにマッチする行だけが出てきます。</p><p> C言語のコードでこれと同じものが動くことが今回の目標です。</p>
</div>
<div class="section">
<h3 id="使用する関数">使用する関数</h3>
<p> shellのパイプ機能を実装するために最低限必要な関数を示します。なお、上の例のtest.cで察した方もおられるかと思いますが、コマンドの入力やパースは今回省略し、あくまで「実行するとパイプでコマンドをつないで一回動作するプログラム」を作ります。</p><p> 更に、エラー処理等も省略し、コードを極力シンプルな形になるまで削ぎ落としてあります。ヘッダファイルは「unistd.h」だけincludeすればコンパイルできます。使う関数はたった6種類です。</p><p> 以下に使用する関数の簡単な説明を記述します。あくまでも簡単な説明なので、ちゃんとした説明が必要ならmanなどを読んでください。</p>
<div class="section">
<h4 id="int-pipeint-pipefd2">int pipe(int pipefd[2])</h4>
<p> 名前無しパイプを生成します。pipefdは配列のアドレスを渡し、ファイルディスクリプタを受け取ります。pipefd[1]にデータを書き込むとpipefd[0]から読み出せます。</p>
</div>
<div class="section">
<h4 id="int-closeint-fd">int close(int fd)</h4>
<p> 引数に渡されたファイルディスクリプタを閉じます。</p><p> パイプをうまく機能させようと思うと、必要のないファイルディスクリプタは片っ端から閉じておく必要があります。無駄に開いている読み出し口や書き込み口があると、入力が終わってもEOFが返されません。するとパイプで繋がれたプログラムが終了しないので、いつまでも待ち続ける羽目になります。必要なものだけ開いた状態にするのが鉄則です。</p>
</div>
<div class="section">
<h4 id="int-dup2int-oldfd-int-newfd">int dup2(int oldfd, int newfd)</h4>
<p> newfdをoldfdのコピーとして作成します。</p><p> と急に言われても何をするのかよくわかりませんが、上で説明したpipe()でパイプを作っておいたとして、</p>
<pre class="code lang-c" data-lang="c" data-unlink>dup2(pipefd[<span class="synConstant">1</span>], <span class="synConstant">1</span>);
</pre><p> で標準出力をパイプの書き込み口に繋ぐことができ、同様に</p>
<pre class="code lang-c" data-lang="c" data-unlink>dup2(pipefd[<span class="synConstant">0</span>], <span class="synConstant">0</span>);
</pre><p> とすれば標準入力をパイプの読み出し口に繋ぐことができる、ということだけ覚えておけば、今回は十分です。</p>
</div>
<div class="section">
<h4 id="pid_t-forkvoid">pid_t fork(void)</h4>
<p> プロセスをforkします。返り値はpid_tという型ですが、これはただの整数型です。forkが成功した場合、pid_tが0なら子プロセス、0以外(実際には子プロセスのPID)なら親プロセスです。失敗すると-1が返ります。</p>
</div>
<div class="section">
<h4 id="pid_t-waitint-status">pid_t wait(int *status)</h4>
<p> 子プロセスが返るのを待ちます。成功した場合、返り値は子プロセスのPIDで、statusに終了情報が格納されます。</p>
</div>
<div class="section">
<h4 id="int-execvpconst-char-file-char-const-argv">int execvp(const char *file, char *const argv[])</h4>
<p> コマンドを実行します。第一引数はコマンドの文字列、第二引数は引数の配列でNULL終端とする必要があります。</p><p> 要するに、</p>
<pre class="code lang-c" data-lang="c" data-unlink><span class="synType">char</span> *cmd1[] = {<span class="synConstant">"ls"</span>, <span class="synConstant">NULL</span>};
</pre><p> と定義しておけば、</p>
<pre class="code lang-c" data-lang="c" data-unlink>execvp(cmd1[<span class="synConstant">0</span>], cmd1);
</pre><p> でlsが実行できます。</p>
</div>
</div>
<div class="section">
<h3 id="パイプの実装方針">パイプの実装方針</h3>
<p> さて、シェルのパイプを作ることを考えます。ここで考え込んでもあまり良いアイデアは浮かんでこないので、とりあえず実際のコマンドを見ます。</p>
<pre class="code" data-lang="" data-unlink>$ cat test.c | head | grep char</pre><p> では3つのコマンドを2つのパイプで繋いでいます。要するにコマンド数-1のパイプを作れば良い訳です。</p><p> ということは、パイプを配列で管理するのかな? と一瞬思いますが、それでも確かにできるのですが、ちょっと煩雑そうです。</p><p> もう少し簡単にする方法はないでしょうか? あります。再帰を使います。</p><p> まずメインのプロセスからforkして、パイプを作り、更にforkします。親はstdinをパイプに繋いで右端(右から0番目)のコマンドの実行、子はstdoutをパイプに繋いで更にパイプを作ってforkして、今度は親になった先程の子が右端から1番目のコマンドを実行、子はまたforkしてパイプを作り……と繰り返していって、左端のコマンドに達したら単に実行して終わりです。この手続きは再帰的に行えます。</p><p> 「なぜ素直に左端からforkしないの?」と疑問を持つ方もいると思いますが、実は左から始めてもパイプそのものはできます。ただし、execしてしまうとプロセスの制御は呼び出し元に戻ってきません。execの中でexitされると思ってください。</p><p> なので、左端からforkすると左端のコマンドが終了した段階でメインプロセス側のwaitが返り、他のコマンドがまだ実行途中であっても制御が戻ってしまいます。実際にやるとわかりますが、出力の途中でプロンプトが出てきたりして、ちょっと不格好な結果になります。右端からforkすれば、右端のコマンドは最後に終了するので、確実にメインプロセス側でコマンドの終了を検知できます。左端からforkする方法でこの問題を回避しようとすると、何らかの制御手段を追加する必要があります。</p><p> 左端からやろうと右端からやろうと、execしてしまう以上、途中では親が子をwaitできないことに違いはありません。ゾンビにならないの? と思うかもしれませんが、この場合は最終的に親が死ぬので、initが引き取ってくれてゾンビになりません。大本の親だけ回収しておけば、それほど気にする必要はありません。</p><p> 説明だけ読んでいてもどうなっているのかよくわからないと思うので、図にしてみました。</p><p><figure class="figure-image figure-image-fotolife" title="パイプ実行時のforkの流れ"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/h/hayataka2049/20181108/20181108184925.png" alt="パイプ実行時のforkの流れ" title="f:id:hayataka2049:20181108184925p:plain" class="hatena-fotolife" itemprop="image"></span><figcaption>パイプ実行時のforkの流れ</figcaption></figure></p><p> この図は上から下に実行されていると思ってください。分岐はfork、合流はwaitでプロセスを看取っていることを示します。分岐の左側がforkの親で、右側が子です。</p><p> cmd3はメインプロセスが看取ります。省略していますが、cmd1とcmd2はcmd3が看取られた後にinitが看取ります。</p>
</div>
<div class="section">
<h3 id="コード">コード</h3>
<p> 実際に書いたコードを以下に示します。上の説明はこのコードを書いてから起こしたものなので、ここまでの内容を読んだ方であれば簡単に理解できると思います。50行ちょっとなので読みやすいはずです。</p><p><b>test.c</b></p>
<pre class="code lang-c" data-lang="c" data-unlink><span class="synPreProc">#include </span><span class="synConstant"><unistd.h></span>
<span class="synType">char</span> *cmd1[] = {<span class="synConstant">"cat"</span>, <span class="synConstant">"test.c"</span>, <span class="synConstant">NULL</span>};
<span class="synType">char</span> *cmd2[] = {<span class="synConstant">"head"</span>, <span class="synConstant">NULL</span>};
<span class="synType">char</span> *cmd3[] = {<span class="synConstant">"grep"</span>, <span class="synConstant">"char"</span>, <span class="synConstant">NULL</span>};
<span class="synType">char</span> **cmds[] = {cmd1, cmd2, cmd3};
<span class="synType">int</span> cmd_n = <span class="synConstant">3</span>;
<span class="synType">void</span> dopipes(i) {
pid_t ret;
<span class="synType">int</span> pp[<span class="synConstant">2</span>] = {};
<span class="synStatement">if</span> (i == cmd_n - <span class="synConstant">1</span>) {
<span class="synComment">// 左端なら単にexecvp</span>
execvp(cmds[<span class="synConstant">0</span>][<span class="synConstant">0</span>], cmds[<span class="synConstant">0</span>]);
}
<span class="synStatement">else</span> {
<span class="synComment">// 左端以外ならpipeしてforkして親が実行、子が再帰</span>
pipe(pp);
ret = fork();
<span class="synStatement">if</span> (ret == <span class="synConstant">0</span>) {
<span class="synComment">// 子プロセスならパイプをstdoutにdup2してdopipes(i+1)で再帰し、</span>
<span class="synComment">// 次のforkで親になった側が右からi+1番目のコマンドを実行</span>
close(pp[<span class="synConstant">0</span>]);
dup2(pp[<span class="synConstant">1</span>], <span class="synConstant">1</span>);
close(pp[<span class="synConstant">1</span>]);
dopipes(i+<span class="synConstant">1</span>);
}
<span class="synStatement">else</span> {
<span class="synComment">// 親プロセスならパイプをstdinにdup2して、</span>
<span class="synComment">// 右からi番目のコマンドを実行</span>
close(pp[<span class="synConstant">1</span>]);
dup2(pp[<span class="synConstant">0</span>], <span class="synConstant">0</span>);
close(pp[<span class="synConstant">0</span>]);
execvp(cmds[cmd_n-i-<span class="synConstant">1</span>][<span class="synConstant">0</span>], cmds[cmd_n-i-<span class="synConstant">1</span>]);
}
}
}
<span class="synType">int</span> main(<span class="synType">void</span>) {
pid_t ret;
ret = fork();
<span class="synStatement">if</span> (ret == <span class="synConstant">0</span>)
dopipes(<span class="synConstant">0</span>);
<span class="synStatement">else</span>
wait(<span class="synConstant">NULL</span>);
<span class="synStatement">return</span> <span class="synConstant">0</span>;
}
</pre><p> コンパイルして実行すると(実行ファイルはソースコードと同一ディレクトリに置いてください)、</p>
<pre class="code" data-lang="" data-unlink>char *cmd1[] = {"cat", "test.c", NULL};
char *cmd2[] = {"head", NULL};
char *cmd3[] = {"grep", "char", NULL};
char **cmds[] = {cmd1, cmd2, cmd3};</pre><p> と最初のshellから打ち込んだパイプコマンドと同じ結果が出力されます。</p>
</div>
<div class="section">
<h3 id="改良した方が良い点">改良した方が良い点</h3>
<p> とりあえず、システムコールは失敗することもあり得るので、ちゃんとエラー処理しましょう。この記事ではわかりやすさを重視してすべて端折っていますが、</p><p> あとはdup2に関してですが、</p>
<pre class="code lang-c" data-lang="c" data-unlink><span class="synComment">// stdoutにdup2</span>
close(pp[<span class="synConstant">0</span>]);
dup2(pp[<span class="synConstant">1</span>], <span class="synConstant">1</span>);
close(pp[<span class="synConstant">1</span>]);
<span class="synComment">// ------</span>
<span class="synComment">// stdinにdup2</span>
close(pp[<span class="synConstant">1</span>]);
dup2(pp[<span class="synConstant">0</span>], <span class="synConstant">0</span>);
close(pp[<span class="synConstant">0</span>]);
</pre><p> dup2の際にnewfdが開いていれば勝手に閉じられます。これに失敗する可能性があり、その場合エラー情報は握りつぶされます。なので、stdinとstdoutも明示的に閉じてエラー処理をした方が良いとされます。</p>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> これでパイプを実装しないといけなくなっても大丈夫!</p>
</div>
<div class="section">
<h3 id="参考にしたサイト">参考にしたサイト</h3>
<p><a href="https://keiorogiken.wordpress.com/2017/12/15/%E3%82%B7%E3%82%A7%E3%83%AB%E3%81%AE%E5%A4%9A%E6%AE%B5%E3%83%91%E3%82%A4%E3%83%97%E3%82%92%E8%87%AA%E4%BD%9C%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B/">シェルの多段パイプを自作してみる | 慶應義塾大学ロボット技術研究会</a><br />
こちらは配列で管理する方法でパイプを実装しています。</p><p><a href="https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1451844474">linux上で動くシェルを自作しています。多段階のパイプを実装方法を教... - Yahoo!知恵袋</a><br />
結構ヒントになりました。ここの回答をコードに起こしたようなものでした。</p>
</div>
hayataka2049
pythonのスコープは静的に決まる。だから・・・
hatenablog://entry/10257846132662823837
2018-11-01T05:30:22+09:00
2018-11-28T19:07:09+09:00 概要 少し疑問に思うことがあったので、書き留めておきます。 目次 概要 前提 確認したかったことと結果 まとめ 前提 まず以下のようなコードについて考えます。 >>> def f(): ... print(a) ... >>> a = "hoge" >>> f() hoge ここでf()の中のprint()でaを参照しています。aはローカルスコープで定義されていないため、外のスコープ(この場合はグローバルスコープ)にあるのだろうとpythonインタプリタは判断します。 そのため、f()を呼ぶとグローバルスコープで定義したaがprint(a)で出てきます。 ここまでは特に疑問はないと思います。次…
<div class="section">
<h3 id="概要">概要</h3>
<p> 少し疑問に思うことがあったので、書き留めておきます。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#概要">概要</a></li>
<li><a href="#前提">前提</a></li>
<li><a href="#確認したかったことと結果">確認したかったことと結果</a></li>
<li><a href="#まとめ">まとめ</a></li>
</ul>
</div>
<div class="section">
<h3 id="前提">前提</h3>
<p> まず以下のようなコードについて考えます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">f</span>():
... <span class="synIdentifier">print</span>(a)
...
>>> a = <span class="synConstant">"hoge"</span>
>>> f()
hoge
</pre><p> ここでf()の中のprint()でaを参照しています。aはローカルスコープで定義されていないため、外のスコープ(この場合はグローバルスコープ)にあるのだろうとpythonインタプリタは判断します。</p><p> そのため、f()を呼ぶとグローバルスコープで定義したaがprint(a)で出てきます。</p><p> ここまでは特に疑問はないと思います。次にこれについて考えます(上から続けて実行します)。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">f</span>():
... <span class="synIdentifier">print</span>(a)
... a = <span class="synConstant">"fuga"</span>
... <span class="synIdentifier">print</span>(a)
...
>>> f()
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">2</span>, <span class="synStatement">in</span> f
<span class="synType">UnboundLocalError</span>: local variable <span class="synConstant">'a'</span> referenced before assignment
</pre><p> f()の中でaに対する代入を行うと、aはローカル変数とみなされます。位置は関係なく、スコープは定義時に静的に確定します。なので、UnboundLocalErrorというエラーが発生します。</p><p> これは有名な話で、公式ドキュメントのFAQにも載っています。pythonプログラマなら知っていないといけないことです。</p><p><a href="https://docs.python.jp/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value">プログラミング FAQ — Python 3.6.5 ドキュメント</a></p><p> ここまでが前提です。</p>
</div>
<div class="section">
<h3 id="確認したかったことと結果">確認したかったことと結果</h3>
<p> こんな関数定義ではどうなるのか。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">f</span>():
... <span class="synIdentifier">print</span>(a)
... <span class="synStatement">if</span> <span class="synIdentifier">False</span>:
... a = <span class="synConstant">"fuga"</span>
... <span class="synIdentifier">print</span>(a)
...
</pre><p> 原則どおりならスコープは静的に確定しますが、なんとなく違う結果になるという期待も抱かせます。</p><p> 結果。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> f()
Traceback (most recent call last):
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">1</span>, <span class="synStatement">in</span> <module>
File <span class="synConstant">"<stdin>"</span>, line <span class="synConstant">2</span>, <span class="synStatement">in</span> f
<span class="synType">UnboundLocalError</span>: local variable <span class="synConstant">'a'</span> referenced before assignment
</pre><p> 変わらないのだった。<br />
<br />
</p>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> 「とにかく関数の中で代入されていればローカルスコープ」という原則が何よりも優先される、ということを再確認できました。</p>
</div>
hayataka2049
アドレス変更のおしらせ
hatenablog://entry/10257846132654500991
2018-10-16T15:34:37+09:00
2019-07-10T20:57:26+09:00 本日、本ブログを独自ドメイン化しました。それに伴い、アドレスが変更になりました。 旧URL https://hayataka2049.hatenablog.jp/ 新URL https://www.haya-programming.com/ 旧URLからも301リダイレクトされますが、ブックマーク登録等はお早めの更新をおねがいします。 今後共よろしくおねがいします。
<p> 本日、本ブログを独自ドメイン化しました。それに伴い、アドレスが変更になりました。</p>
<ul>
<li>旧URL</li>
</ul><p> <a href="https://hayataka2049.hatenablog.jp/">https://hayataka2049.hatenablog.jp/</a><br />
</p>
<ul>
<li>新URL</li>
</ul><p> <a href="https://www.haya-programming.com/">https://www.haya-programming.com/</a></p><p> 旧URLからも301リダイレクトされますが、ブックマーク登録等はお早めの更新をおねがいします。</p><p> 今後共よろしくおねがいします。</p><p> </p>
hayataka2049
pythonで変数のswap(入れ替え)について考えて検討してみた
hatenablog://entry/10257846132634905061
2018-09-19T19:58:28+09:00
2018-11-28T19:01:25+09:00 はじめに 変数の入れ替えは、C言語の教科書などにも書いてある古典的な話題です。 一番古典的な方法では、こうやります。 >>> a = 10 >>> b = 20 >>> a 10 >>> b 20 >>> tmp = a >>> a = b >>> b = tmp >>> a 20 >>> b 10 ただ、このコードは……あまり書きたくないですね。 pythonではエレガントに書ける pythonの代入文にはイカれた機能があり、こういうものを綺麗に書けます。 >>> a = 10 >>> b = 20 >>> b,a = a,b >>> a 20 >>> b 10 参考: 7. 単純文 (si…
<div class="section">
<h3>はじめに</h3>
<p> 変数の入れ替えは、C言語の教科書などにも書いてある古典的な話題です。</p><p> 一番古典的な方法では、こうやります。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> a = <span class="synConstant">10</span>
>>> b = <span class="synConstant">20</span>
>>> a
<span class="synConstant">10</span>
>>> b
<span class="synConstant">20</span>
>>> tmp = a
>>> a = b
>>> b = tmp
>>> a
<span class="synConstant">20</span>
>>> b
<span class="synConstant">10</span>
</pre><p> ただ、このコードは……あまり書きたくないですね。</p>
</div>
<div class="section">
<h3>pythonではエレガントに書ける</h3>
<p> pythonの代入文にはイカれた機能があり、こういうものを綺麗に書けます。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> a = <span class="synConstant">10</span>
>>> b = <span class="synConstant">20</span>
>>> b,a = a,b
>>> a
<span class="synConstant">20</span>
>>> b
<span class="synConstant">10</span>
</pre><p> 参考:</p>
<ul>
<li><a href="https://docs.python.jp/3.6/reference/simple_stmts.html#assignment-statements">7. 単純文 (simple statement) — Python 3.6.5 ドキュメント</a></li>
<li><a href="https://qiita.com/marsbarmania/items/2b5e21e95b3ceac85781">Python: Tips - 値の入れ替え - Qiita</a></li>
</ul>
</div>
<div class="section">
<h3>タプル+シーケンスアンパックとして解釈できるか?</h3>
<p> この記事の本題なのですが、これはタプル+シーケンスアンパックとして解釈できるのでしょうか?</p><p> 構文的に考えると、まず右辺はtupleを作っているはずです。</p>
<blockquote>
<p>なお、タプルを作るのはカンマであり、丸括弧ではありません。丸括弧は省略可能ですが、空のタプルの場合や構文上の曖昧さを避けるのに必要な時は例外です。例えば、 f(a, b, c) は三引数の関数呼び出しですが、f( (a, b, c) ) は 3-タプルを唯一の引数とする関数の呼び出しです。<br />
<a href="https://docs.python.jp/3/library/stdtypes.html#tuple">4. 組み込み型 — Python 3.6.5 ドキュメント</a></p>
</blockquote>
<p> 左辺はシーケンスアンパックとして解釈できそうです。</p><p> ということで、これはtuple+sequence unpackなはずなので、バイトコードを読んでみましょう。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">f</span>():
... a,b = b,a
...
>>> <span class="synPreProc">import</span> dis
>>> dis.dis(f)
<span class="synConstant">2</span> <span class="synConstant">0</span> LOAD_FAST <span class="synConstant">0</span> (b)
<span class="synConstant">3</span> LOAD_FAST <span class="synConstant">1</span> (a)
<span class="synConstant">6</span> ROT_TWO
<span class="synConstant">7</span> STORE_FAST <span class="synConstant">1</span> (a)
<span class="synConstant">10</span> STORE_FAST <span class="synConstant">0</span> (b)
<span class="synConstant">13</span> LOAD_CONST <span class="synConstant">0</span> (<span class="synIdentifier">None</span>)
<span class="synConstant">16</span> RETURN_VALUE
</pre><p> 解説はここに。なお、言うまでもなくCPython前提です。また、私が2018年9月現在使っている処理系はpython3.5.1です(いい加減更新しろよ・・・)。</p><p><a href="https://docs.python.jp/3.6/library/dis.html">32.12. dis — Python バイトコードの逆アセンブラ — Python 3.6.5 ドキュメント</a></p><p> 関係あるものだけ引用します。</p>
<ul>
<li>LOAD_FAST</li>
</ul><p> ローカルな co_varnames[var_num] への参照をスタックにプッシュします。</p>
<ul>
<li>STORE_FAST</li>
</ul><p> TOS をローカルな co_varnames[var_num] の中に保存します</p>
<ul>
<li>ROT_TWO</li>
</ul><p> スタックの先頭の 2 つの要素を入れ替えます。</p><p> あれ、もしかしてtuple+sequence unpackではない?</p>
</div>
<div class="section">
<h3>検証</h3>
<p> まず、こうしてみる。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">f</span>():
... a,b = (b,a)
...
>>> dis.dis(f)
<span class="synConstant">2</span> <span class="synConstant">0</span> LOAD_FAST <span class="synConstant">0</span> (b)
<span class="synConstant">3</span> LOAD_FAST <span class="synConstant">1</span> (a)
<span class="synConstant">6</span> ROT_TWO
<span class="synConstant">7</span> STORE_FAST <span class="synConstant">1</span> (a)
<span class="synConstant">10</span> STORE_FAST <span class="synConstant">0</span> (b)
<span class="synConstant">13</span> LOAD_CONST <span class="synConstant">0</span> (<span class="synIdentifier">None</span>)
<span class="synConstant">16</span> RETURN_VALUE
</pre><p> あまり関係なさそう。</p><p> 入れ替える個数を3つにしてみる。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">f</span>():
... a,b,c = c,b,a
...
>>> dis.dis(f)
<span class="synConstant">2</span> <span class="synConstant">0</span> LOAD_FAST <span class="synConstant">0</span> (c)
<span class="synConstant">3</span> LOAD_FAST <span class="synConstant">1</span> (b)
<span class="synConstant">6</span> LOAD_FAST <span class="synConstant">2</span> (a)
<span class="synConstant">9</span> ROT_THREE
<span class="synConstant">10</span> ROT_TWO
<span class="synConstant">11</span> STORE_FAST <span class="synConstant">2</span> (a)
<span class="synConstant">14</span> STORE_FAST <span class="synConstant">1</span> (b)
<span class="synConstant">17</span> STORE_FAST <span class="synConstant">0</span> (c)
<span class="synConstant">20</span> LOAD_CONST <span class="synConstant">0</span> (<span class="synIdentifier">None</span>)
<span class="synConstant">23</span> RETURN_VALUE
</pre><p> なんかROT_THREEまで出てきて凄まじいけど、タプル生成→シーケンスアンパックされている様子はない。</p><p> 4つに。</p>
<pre class="code lang-python" data-lang="python" data-unlink>>>> <span class="synStatement">def</span> <span class="synIdentifier">f</span>():
... a,b,c,d = d,c,b,a
...
>>> dis.dis(f)
<span class="synConstant">2</span> <span class="synConstant">0</span> LOAD_FAST <span class="synConstant">0</span> (d)
<span class="synConstant">3</span> LOAD_FAST <span class="synConstant">1</span> (c)
<span class="synConstant">6</span> LOAD_FAST <span class="synConstant">2</span> (b)
<span class="synConstant">9</span> LOAD_FAST <span class="synConstant">3</span> (a)
<span class="synConstant">12</span> BUILD_TUPLE <span class="synConstant">4</span>
<span class="synConstant">15</span> UNPACK_SEQUENCE <span class="synConstant">4</span>
<span class="synConstant">18</span> STORE_FAST <span class="synConstant">3</span> (a)
<span class="synConstant">21</span> STORE_FAST <span class="synConstant">2</span> (b)
<span class="synConstant">24</span> STORE_FAST <span class="synConstant">1</span> (c)
<span class="synConstant">27</span> STORE_FAST <span class="synConstant">0</span> (d)
<span class="synConstant">30</span> LOAD_CONST <span class="synConstant">0</span> (<span class="synIdentifier">None</span>)
<span class="synConstant">33</span> RETURN_VALUE
</pre><p> やっと狙ったものが出てきました。BUILD_TUPLE, UNPACK_SEQUENCEが該当する命令です。</p>
</div>
<div class="section">
<h3>考察</h3>
<p> tupleオブジェクトの生成はそれなりにオーバーヘッドを伴うはずである。</p><p> CPythonインタプリタはこのようなswap代入に対して、3つまではスタックを用いた高速な処理を行うよう最適化されている。</p><p> 4つ以上ある場合は(たぶん最適化を実装するのが面倒くさいので)tupleにしてシーケンスアンパックで処理する。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> うっかり「シーケンスアンパックと考えることができます」とか言えない。まあ、どのみち結果は変わらないのだが。</p><p> ちょっとすっきりしないけど、最適化してくれてるんだね、みたいな話。</p>
</div>
hayataka2049
オブジェクト指向の教育にPythonが向いていると思うこれだけの理由
hatenablog://entry/17391345971658093243
2018-06-27T06:12:49+09:00
2019-02-01T02:39:50+09:00 はじめに オブジェクト指向は今となっては常識である。 常識であるがゆえに、いかに初心者にわかりやすく教えるかが課題になる。 世の中でオブジェクト指向の「教材」として使われている言語は、 Java Ruby の二択くらいだと思う。が、あえて僕はPythonを推してみるよ、という記事。ぶっちゃけポエム。 内容は、Javaでオブジェクト指向を理解するのはしんどいし、RubyとPythonだと僅差でPythonが勝つんじゃないかなぁ、という主張。以下で理由を書いていくよ。 目次 はじめに Pythonが向いていると思う理由 理由1:すべてがオブジェクト 理由2:仕様がスリムで綺麗。書きやすい 理由3:…
<div class="section">
<h3 id="はじめに">はじめに</h3>
<p> オブジェクト指向は今となっては常識である。</p><p> 常識であるがゆえに、いかに初心者にわかりやすく教えるかが課題になる。</p><p> 世の中でオブジェクト指向の「教材」として使われている言語は、</p>
<ul>
<li>Java</li>
<li>Ruby</li>
</ul><p> の二択くらいだと思う。が、あえて僕はPythonを推してみるよ、という記事。ぶっちゃけポエム。</p><p> 内容は、Javaでオブジェクト指向を理解するのはしんどいし、RubyとPythonだと僅差でPythonが勝つんじゃないかなぁ、という主張。以下で理由を書いていくよ。</p><p> 目次</p>
<ul class="table-of-contents">
<li><a href="#はじめに">はじめに</a></li>
<li><a href="#Pythonが向いていると思う理由">Pythonが向いていると思う理由</a><ul>
<li><a href="#理由1すべてがオブジェクト">理由1:すべてがオブジェクト</a></li>
<li><a href="#理由2仕様がスリムで綺麗書きやすい">理由2:仕様がスリムで綺麗。書きやすい</a></li>
<li><a href="#理由3self">理由3:self</a></li>
<li><a href="#理由4普通にプログラミングしているだけでオブジェクト指向への理解が深まる">理由4:普通にプログラミングしているだけでオブジェクト指向への理解が深まる</a></li>
<li><a href="#理由5書いてて楽しい">理由5:書いてて楽しい</a></li>
</ul>
</li>
<li><a href="#向いていない理由も一応書く">向いていない理由も一応書く</a><ul>
<li><a href="#罠が多い">罠が多い</a></li>
<li><a href="#そういうコンセプトの解説記事とかが少ないあっても古い">そういうコンセプトの解説記事とかが少ない。あっても古い</a></li>
<li><a href="#しょせんスクリプト言語">しょせんスクリプト言語</a></li>
<li><a href="#独自の風習">独自の風習</a></li>
<li><a href="#windowsとそんなに相性がよくない">windowsとそんなに相性がよくない</a></li>
<li><a href="#でもまあ">でもまあ、</a></li>
</ul>
</li>
<li><a href="#まとめ">まとめ</a></li>
</ul><p><span style="font-size: 80%">スポンサーリンク</span><br />
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script></p>
<p><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-6261827798827777"
data-ad-slot="1744230936"
data-ad-format="auto"
data-full-width-responsive="true"></ins><br />
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p><br />
<p></p>
</div>
<div class="section">
<h3 id="Pythonが向いていると思う理由">Pythonが向いていると思う理由</h3>
<div class="section">
<h4 id="理由1すべてがオブジェクト">理由1:すべてがオブジェクト</h4>
<p> すべてがオブジェクト。これは重要なことである。</p><p> オブジェクトとオブジェクト以外で異なる扱いをしなければならない、プリミティブ型のある言語でオブジェクト指向の教育をするなんて、正気の沙汰ではない。初心者はintと配列ばっかり使う訳だしさ。</p><p> なので、Javaはぶっちゃけ論外だと思う。Ruby使いの人は「ならPythonとRubyは互角だ」と言いたくなるかもしれないけど、Rubyには関数が第一級オブジェクトではないという弱点があり、「すべてがオブジェクト」ははっきり言って誇大広告である。</p><p> 関数オブジェクトが自然に使えないと困るのかって? まあ、そんなに困らないかもしれない。でも「関数オブジェクト」は理解しておいた方が、オブジェクト指向がよくわかるようになると思わない?(上級者向けすぎるか)</p>
</div>
<div class="section">
<h4 id="理由2仕様がスリムで綺麗書きやすい">理由2:仕様がスリムで綺麗。書きやすい</h4>
<p> Javaにはまず、publicやらprivateやらある。interfaceというわかりづらい概念もある。静的型付けなのも相まって、メソッドの宣言なんかカオス。<b>public static void main</b>はどう考えても初心者向けではない<a href="#f-ea6979d8" name="fn-ea6979d8" title="「そんなのIDEが補完してくれるから良いんだよ!」という意見が当然あると思うが、それをやると馬鹿の一つ覚えのようにIDEの補完と修正任せでコードを書こうとする奴が続出するのでダメだ">*1</a>。</p><p> Rubyは、なんかブロックとかいうよくわからないものがあるね。あと、メソッド呼び出しのカッコを省略できるとか。教育上あんまりよくないと思います。</p><p> Pythonにはそういう問題はない。</p>
</div>
<div class="section">
<h4 id="理由3self">理由3:self</h4>
<p> Pythonのselfはよく批判されるけど、なんだかんだでわかりやすい。</p>
<pre class="code lang-python" data-lang="python" data-unlink>a.hoge(<span class="synConstant">"fuga"</span>)
</pre><p> は</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synIdentifier">type</span>(a).hoge(a, <span class="synConstant">"fuga"</span>)
</pre><p> と実質的に等価というルールがあることを理解すれば、後は不自然な点はなにもない。インスタンスの外側ではaとして見えているものは、内側ではselfとして見えていると考えれば良いということで、自然な発想でコードを書いていくことができる。</p><p> selfを省略する言語はこれがないので、クラス変数とインスタンス変数の区別を付けるだけでも一苦労だし、ローカル変数まで混ざってくると本格的に訳がわからなくなる(から、EclipseでJavaを書くとぜんぶ違う色で見せてくれる)。</p>
</div>
<div class="section">
<h4 id="理由4普通にプログラミングしているだけでオブジェクト指向への理解が深まる">理由4:普通にプログラミングしているだけでオブジェクト指向への理解が深まる</h4>
<p> Python初心者はlistをよく使う。そうするとappendやextendが出てくる。これはもうメソッドだ。</p><p> 関数の引数に渡したリストにappendするとリストの中身が変わるけど、intだと足し算しても変わらない。mutableなオブジェクトとimmutableなオブジェクトの違いを理解するだろうし、オブジェクトは変数に束縛されているだけというオブジェクト指向の基本的なモデル<a href="#f-baad4e34" name="fn-baad4e34" title="異論はあるだろうけど">*2</a>への理解も深まる。</p><p> list.sort()とsorted(list)の違いを理解すれば、破壊的なメソッドには注意しないといけないこともわかる。</p><p> だから、「オブジェクト指向の勉強のためにJavaを半年学んだ人」と「ただ単にプログラミングの勉強として半年Pythonを学んだ人」だと、オブジェクト指向に対する理解度は同程度か、ヘタしたら後者のほうが勝るくらいになっているかもしれない。</p><p> まあ、これに関してはたぶんRubyも互角。</p>
</div>
<div class="section">
<h4 id="理由5書いてて楽しい">理由5:書いてて楽しい</h4>
<p> タイプ数も少ないし、なんかPythonはパズルみたいな技巧的な面があるし、書いてて楽しい。</p>
</div>
</div>
<div class="section">
<h3 id="向いていない理由も一応書く">向いていない理由も一応書く</h3>
<p> ダメな理由もなんか色々あるといえばあるような気もする。</p>
<div class="section">
<h4 id="罠が多い">罠が多い</h4>
<p> Pythonはシンプルなクセに罠が多い言語だと思う(「文字コード」とか「test.py作っただけでまともに動かない」とか「IndentationError」とか)。</p><p> エラーメッセージも、わからないときはとことんわからないのが出るし。</p><p> 初心者のうちは、よくわからないところで詰む。そして初心者は自己解決できない。</p><p> 罠は回避するように教育していくとかで軽減は可能。ただ、本質的じゃない問題で初心者を悩ませるのもなんだかなぁという気がする。</p>
</div>
<div class="section">
<h4 id="そういうコンセプトの解説記事とかが少ないあっても古い">そういうコンセプトの解説記事とかが少ない。あっても古い</h4>
<p> 困るよね。</p>
</div>
<div class="section">
<h4 id="しょせんスクリプト言語">しょせんスクリプト言語</h4>
<p> カプセル化はないし、ポリモーフィズムの実現方法もすごく簡単(メソッド作るだけ!)。ので、Pythonやってから他の言語のオブジェクト指向を理解しようとすると、追加の学習コストがかかる。</p>
</div>
<div class="section">
<h4 id="独自の風習">独自の風習</h4>
<p> 避けては通れないけど避けなかったところで得るものの少ないデコレータとか、</p><p> 初心者を惑わす内包表記とかジェネレータとか、</p><p> やればやるほど実感するtuple周りのキモさとか<a href="#f-bfeba7b9" name="fn-bfeba7b9" title="tupleは丸括弧によって作られるのではない、カンマによって作られるのである">*3</a>、</p><p> これどうなんだ、と思う側面はたくさんあります。</p>
</div>
<div class="section">
<h4 id="windowsとそんなに相性がよくない">windowsとそんなに相性がよくない</h4>
<p> 最近はマシにはなりましたが、まだまだハマると思います。linux環境でやれとなるといきなり敷居が高くなります。</p>
</div>
<div class="section">
<h4 id="でもまあ">でもまあ、</h4>
<p> なんだかんだで学習コストの低さ、とっつきやすさでは、総合的には初心者向けのわかりやすい言語と言っても別に構わないくらいだとは思うよ(震え声)。</p>
</div>
</div>
<div class="section">
<h3 id="まとめ">まとめ</h3>
<p> Pythonのオブジェクト指向はわかりやすいよね、最初からこれで教えてもらえたらなぁ。Python良いよね! って気持ちの記事です。</p><p> 特に内容に責任は持たないが、意見等はご自由にどうぞ。</p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-ea6979d8" name="f-ea6979d8" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">「そんなのIDEが補完してくれるから良いんだよ!」という意見が当然あると思うが、それをやると馬鹿の一つ覚えのようにIDEの補完と修正任せでコードを書こうとする奴が続出するのでダメだ</span></p>
<p class="footnote"><a href="#fn-baad4e34" name="f-baad4e34" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">異論はあるだろうけど</span></p>
<p class="footnote"><a href="#fn-bfeba7b9" name="f-bfeba7b9" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">tupleは丸括弧によって作られるのではない、カンマによって作られるのである</span></p>
</div>
hayataka2049
共有渡しと参照の値渡しと
hatenablog://entry/17391345971655649848
2018-06-19T18:16:57+09:00
2019-06-18T19:05:17+09:00 はじめに 関数やメソッドに引数を渡す方法は、一般的には 値渡し 参照渡し の2通りがあると認知されている。 ところで、『参照の値渡し』という言葉も(ほぼ日本語Web圏限定で)存在する。これは「いわゆる『参照渡し』は参照自体を書き換えるんじゃなくて、参照する対象を変えるだけだから、そう呼んだ方が適当だよ!」という思想に基づくもの、だと思う。 このページを見るとわかりやすい。キミの言語は参照渡しできる? - Qiita つまり、こういうことができたら『参照渡し』で a = "hoge" b = "fuga" swap(a, b) print(a, b) # => fuga, hoge できなかった…
<div class="section">
<h3>はじめに</h3>
<p> 関数やメソッドに引数を渡す方法は、一般的には</p>
<ul>
<li>値渡し</li>
<li>参照渡し</li>
</ul><p> の2通りがあると認知されている。</p><p> ところで、『参照の値渡し』という言葉も(ほぼ日本語Web圏限定で)存在する。これは「いわゆる『参照渡し』は参照自体を書き換えるんじゃなくて、参照する対象を変えるだけだから、そう呼んだ方が適当だよ!」という思想に基づくもの、だと思う。</p><p> このページを見るとわかりやすい。</p><p><a href="https://qiita.com/tadsan/items/e02d881259a525f7a2bb">キミの言語は参照渡しできる? - Qiita</a></p><p> つまり、こういうことができたら『参照渡し』で</p>
<pre class="code lang-python" data-lang="python" data-unlink>a = <span class="synConstant">"hoge"</span>
b = <span class="synConstant">"fuga"</span>
swap(a, b)
<span class="synIdentifier">print</span>(a, b) <span class="synComment"># => fuga, hoge</span>
</pre><p> できなかったら「キミの言語は『参照渡し』できないよ、キミが『参照渡し』だと思っているのは『参照の値渡し』だよ!」ということか。言いたいことはわかる。</p><p> 上のリンクにはC言語で「参照渡し」をやる方法としてこういう例が載っている。</p>
<pre class="code lang-c" data-lang="c" data-unlink><span class="synPreProc">#include </span><span class="synConstant"><stdio.h></span>
<span class="synType">void</span> swap(<span class="synType">char</span> *a, <span class="synType">char</span> *b){
<span class="synType">char</span> tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
<span class="synType">int</span> main(<span class="synType">void</span>){
<span class="synType">char</span> x = <span class="synConstant">'A'</span>, y = <span class="synConstant">'B'</span>;
swap(&x, &y);
printf(<span class="synConstant">"</span><span class="synSpecial">%c\n</span><span class="synConstant">"</span>, x);
printf(<span class="synConstant">"</span><span class="synSpecial">%c\n</span><span class="synConstant">"</span>, y);
<span class="synStatement">return</span> <span class="synConstant">0</span>;
}
</pre><p> ちなみに、こっちの「参照渡し」は歴史が古く、少なくともFORTRANからあるっぽい。というか、FORTRANはデフォルトですべて参照渡し。</p>
<pre class="code lang-fortran" data-lang="fortran" data-unlink><span class="synPreProc">subroutine</span> f(x)
<span class="synType">integer</span> x
x <span class="synStatement">=</span> <span class="synConstant">42</span>
<span class="synPreProc">end subroutine</span>
<span class="synPreProc">program</span> main
<span class="synType">integer</span> a
a <span class="synStatement">=</span> <span class="synConstant">3</span>
<span class="synStatement">print</span> <span class="synStatement">*</span>, a
<span class="synIdentifier">call</span> f(a)
<span class="synStatement">print</span> <span class="synStatement">*</span>, a
<span class="synPreProc">end program</span>
<span class="synComment">! 3</span>
<span class="synComment">! 42</span>
</pre><p> C言語とかに慣れた目には奇異に映るけど、よくよく考えてみるとメモリ番地だけ渡せばいいので効率的だし(まあ実際にどういう実装なのかまでは確認していないけど)、多少注意していればプログラムも書きやすいので、これはこれで合理的だと思う。</p><p> 話が逸れた。参照の値渡しでは、こういう「参照渡し」チックな動作はできない。pythonの例。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synStatement">def</span> <span class="synIdentifier">swap</span>(a, b):
a, b = b, a
a = <span class="synConstant">10</span>
b = <span class="synConstant">20</span>
swap(a, b)
</pre><p> pythonの変数はすべてJavaなどでいうところの参照型ではあるのだけど、swapの中のa,bは単なるswap関数のローカル変数であって、呼び出し元のa, bの参照するものを書き換えたりはしない。受け取っているのは「参照の値」であって、「参照の値を格納している変数への参照」ではない。</p><p> 参照型の「真の」参照渡しについては、以下のCの例を考えてみるとわかりやすい。</p>
<pre class="code lang-python" data-lang="python" data-unlink><span class="synComment">#include <stdio.h></span>
void swap(char **a, char **b){
char *tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
<span class="synIdentifier">int</span> main(void){
char x = <span class="synConstant">'A'</span>, y = <span class="synConstant">'B'</span>;
char *xptr, *yptr;
xptr = &x;
yptr = &y;
swap(&xptr, &yptr);
printf(<span class="synConstant">"%c</span><span class="synSpecial">\n</span><span class="synConstant">"</span>, *xptr);
printf(<span class="synConstant">"%c</span><span class="synSpecial">\n</span><span class="synConstant">"</span>, *yptr);
<span class="synStatement">return</span> <span class="synConstant">0</span>;
}
</pre><p> xptr, yptrのアドレスを渡す訳ですね。pythonではこれはできない(というか、そもそも変数の概念そのものが違うけど)。で、こういうものを称して参照の値渡し、とする。</p>
</div>
<div class="section">
<h3>共有渡しについて考える</h3>
<p> さて、『参照の値渡し』とよく似た概念として、『共有渡し』がある。</p><p> ちなみに、日本語wikipediaの「引数」ページには『共有渡し』は存在しない代わり参照の値渡しがあり、英語版wikipediaの「Evaluation strategy」ページには『Call by sharing』<a href="#f-30334d63" name="fn-30334d63" title="念のため書いておくと、「渡し」に対応するのは「Pass by」、「Call by」は「呼び出し」に対応するのだが、どちらにせよ意味は大して変わらないのでどちらで訳しても問題はない。この記事では日本語圏で一般的な「渡し」で統一している">*1</a>はあって参照の値渡しはない。なんだかなぁ。</p><p><a href="https://ja.wikipedia.org/wiki/%E5%BC%95%E6%95%B0#%E5%8F%82%E7%85%A7%E3%81%AE%E5%80%A4%E6%B8%A1%E3%81%97">引数 - Wikipedia</a><br />
<a href="https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing">Evaluation strategy - Wikipedia</a></p><p> 『共有渡し』が何者かというと、これは英語版wikipediaのページを読むのがわかりやすいのだが、一行引用してくると</p>
<blockquote>
<p>also referred to as call by object or call by object-sharing</p>
</blockquote>
<p> ということであり、つまりは関数(メソッド)の呼び出し元と呼び出し先で同じオブジェクトを「共有」する方法である。</p><p> 僕のようなpython使いにとっては「それ普通じゃね?」なのだが、確かに値渡しとも『参照渡し』とも(何を示す言葉かは不問として)異なる概念と言われればそんな気はする。この言葉は、1974年、CLUという初期のオブジェクト指向言語とともに生み出された言葉だそうな。</p><p> これに関連して、こんな議論もある。<a href="https://wiki.python.org/moin/CompLangPython">comp.lang.python</a> <a href="#f-f0510b30" name="fn-f0510b30" title="筆者はこれが何なのかはよくわからないが">*2</a>の昔の議論らしい。pythonの呼び出しモデルは『Call by sharing』だと結論が着いている感じ。</p><p><a href="http://effbot.org/zone/call-by-object.htm">Call By Object</a></p><p> なんか、同じものを呼ぶ名前がいっぱいある。</p>
<blockquote>
<p>The most accurate description is CLU’s “call by object” or “call by sharing“. Or, if you prefer, “call by object reference“.</p>
</blockquote>
<p> こんなに呼び方が多いのはちょっと酷いんだが、“call by object reference“あたりだと言いたいことはよく伝わってくる。</p>
</div>
<div class="section">
<h3>どっちが良いのか</h3>
<p> べつに『参照の値渡し』≒『共有渡し』とみなしても良いのだが、言葉のニュアンスは違うし、他にも考えるべきことがあって「どっちを使うか、あるいはどっちでも良いのか」という問題には答えを出しづらいと思うのだ・・・。</p>
<ul>
<li>使える言語と使えない言語がそれぞれ違う</li>
</ul><p> 『参照の値渡し』は『参照の値』が定義されない言語では使うべきではないと思う。また逆に、C言語に対して『共有渡し』を使うのにはなんとなく躊躇する。メモリ領域を共有しているには違いないけど、なんかもう少し低レイヤな感じなので。</p>
<ul>
<li>あくまでも値渡し+参照渡し的な世界観で説明しようとする『参照の値渡し』と、オブジェクトが呼び出し元・先で「共有」されるという現象を重視する『共有渡し』</li>
</ul><p> 同じ現象でも見方が違うのだと思う。</p><p> この違いは意外と効いてきて、前者の立場を取るとJavaは「基本的に値渡し。プリミティブ型はそのまま値で渡るが、それ以外はアドレスの値が渡る」と値渡し的な世界観で説明できるが、後者の立場を取ると「プリミティブ型の値渡し、配列の『参照の値渡し』、オブジェクトの『共有渡し』の折衷」という苦しい説明にせざるを得ないと思う(配列に対して『共有渡し』の言葉を使うことを許すなら、真ん中は削れるけど)。Java使いの人たちが「Javaは値渡し!」と主張したがるのは、つまるところそういうことだろう<a href="#f-db032549" name="fn-db032549" title="個人的には「Cみたいに明示的にアドレス渡す訳でもないのに値渡しって呼ぶのは逆説的でわかりづらいよ」と思うのだが、そのコストに勝るメリットがあるとする考えなのだろう">*3</a>。</p><p> 逆にpythonやrubyのような「すべてがオブジェクト」な言語では、プリミティブ型やら何やらのことは考える必要はなく、また言語仕様の表面で参照の値(要するにアドレス)が見えてくる訳でもないので、『共有渡し』の方がすっきりすると思う。</p>
<ul>
<li>認知度とか言葉としての良し悪し</li>
</ul><p> なんか、どっちもどっちという気がする。<br />
単純な好みの問題だと思うけど強いて選ぶとすれば、国際的に(一応は)通用するであろうこと、言葉の良し悪しについて議論の余地が少ない<a href="#f-79bd00d0" name="fn-79bd00d0" title="というか議論になっていない程度に流行っていないだけかも・・・">*4</a>ことから、共有渡しの方が筋は良さそう</p><p> まあ、個人的には『共有渡し』の方がスッキリするし、好きです。でも、『参照の値渡し』が絶対に駄目かというと・・・難しいです。呼び方の問題は厄介。</p>
</div>
<div class="section">
<h3>まとめ</h3>
<p> ややこしくない(動作としてはよくわかる)けど、ややこしい(名前がうまく決められない)話だよね。</p>
</div>
<div class="section">
<h3>続き</h3>
<p> 某所でこの問題が再燃していたので、続きを書いた。</p><p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.haya-programming.com%2Fentry%2F2019%2F04%2F26%2F053359" title="もう参照の値渡しとは(無条件では)言わせない - 静かなる名辞" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://www.haya-programming.com/entry/2019/04/26/053359">www.haya-programming.com</a></cite></p>
</div><div class="footnote">
<p class="footnote"><a href="#fn-30334d63" name="f-30334d63" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">念のため書いておくと、「渡し」に対応するのは「Pass by」、「Call by」は「呼び出し」に対応するのだが、どちらにせよ意味は大して変わらないのでどちらで訳しても問題はない。この記事では日本語圏で一般的な「渡し」で統一している</span></p>
<p class="footnote"><a href="#fn-f0510b30" name="f-f0510b30" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">筆者はこれが何なのかはよくわからないが</span></p>
<p class="footnote"><a href="#fn-db032549" name="f-db032549" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">個人的には「Cみたいに明示的にアドレス渡す訳でもないのに値渡しって呼ぶのは逆説的でわかりづらいよ」と思うのだが、そのコストに勝るメリットがあるとする考えなのだろう</span></p>
<p class="footnote"><a href="#fn-79bd00d0" name="f-79bd00d0" class="footnote-number">*4</a><span class="footnote-delimiter">:</span><span class="footnote-text">というか議論になっていない程度に流行っていないだけかも・・・</span></p>
</div>
hayataka2049
VMware Playerでキャッシュを削除して仮想ディスクの容量を空ける(linux)
hatenablog://entry/17391345971649185671
2018-05-29T21:54:52+09:00
2018-11-28T01:44:42+09:00 VMware Playerはホストとゲスト間で、ドラッグ・アンド・ドロップやコピ・アンド・ペーストによってファイルを移動できる。 便利な機能なのでつい頻繁に使ってしまうが、これは腹立たしいことにゲストの仮想ディスク上にキャッシュを生成する。 そしてこのキャッシュはなぜか勝手に消えてくれないので、気がつくとかなりディスク容量を圧迫してたりする。 その消し方を備忘録としてメモ。 ~/.cache/vmware/drag_and_drop/をまるごと消す 以上。他にやることは特にない。 僕が使っているのはubuntuだけど、たぶんlinux系なら何でも同じ場所にあるんだと思う(未確認)。もしかしたら…
<p> VMware Playerはホストとゲスト間で、ドラッグ・アンド・ドロップやコピ・アンド・ペーストによってファイルを移動できる。</p><p> 便利な機能なのでつい頻繁に使ってしまうが、これは腹立たしいことにゲストの仮想ディスク上にキャッシュを生成する。</p><p> そしてこのキャッシュはなぜか勝手に消えてくれないので、気がつくとかなりディスク容量を圧迫してたりする。</p><p> その消し方を備忘録としてメモ。</p>
<ol>
<li>~/.cache/vmware/drag_and_drop/をまるごと消す</li>
</ol><p> 以上。他にやることは特にない。</p><p> 僕が使っているのはubuntuだけど、たぶんlinux系なら何でも同じ場所にあるんだと思う(未確認)。もしかしたらVMware Playerのバージョンによっては場所が違うとかあるかもしれないけど、そのときはvmwareって名前の付いたディレクトリを検索すれば出てくると思う。</p><p> 放って置くとどんどん大きくなるので、たまに消してあげよう。これは仮想ディスクがいっぱいになっちゃった! というとき、とりあえず容量を空ける方法としても役に立つ。</p>
hayataka2049
有意水準5%の論文が100本あったら
hatenablog://entry/17391345971643822977
2018-05-12T17:49:59+09:00
2018-11-28T01:34:10+09:00 この記事は思いついたままに書いたポエム。 有意水準5%とは、その判断(主張)の妥当性が95%である、ということを意味する。 よって、有意水準5%で検定したら、100回に5回は第1種の過誤を犯す。 有意水準5%の論文が100本あったら、(いちおうすべての論文が正しいプロセスを踏んでいると仮定しても)うち5本は間違っている。 恐らく現実の論文はそんなに酷いことにはなっていないと思う(ただし、100本あったらそもそもプロセスが正しくないものは一定数入ってくるだろうけど)。これがどういうことなのかというと、 そもそも5%なんて甘い有意水準は使っていない(これはあると思うけど、とりあえず無視することにす…
<p> この記事は思いついたままに書いたポエム。</p><p><hr></p><p> 有意水準5%とは、その判断(主張)の妥当性が95%である、ということを意味する。</p><p> よって、有意水準5%で検定したら、100回に5回は第1種の過誤を犯す。</p><p> 有意水準5%の論文が100本あったら、(いちおうすべての論文が正しいプロセスを踏んでいると仮定しても)うち5本は間違っている。</p><p><hr></p><p> 恐らく現実の論文はそんなに酷いことにはなっていないと思う(ただし、100本あったらそもそもプロセスが正しくないものは一定数入ってくるだろうけど)。これがどういうことなのかというと、</p>
<ul>
<li>そもそも5%なんて甘い有意水準は使っていない(これはあると思うけど、とりあえず無視することにする)</li>
<li>最初からある程度有力な仮説を立てて検証しているので、95%に「仮説の妥当性」がかかってくると考えられる(ちょっと異論もあるかもしれないが、「ある仮説を妥当だと思って検証し、けっきょく妥当ではなかったという事象の可能性」を考えるとけっきょく効いてくると思われる)</li>
<li>論文に発表した以外にも色々実験をしたりして、妥当性を判断している。一回検定しただけ、というのは考えづらい(逆に言えば、再現が難しい話(世の中から取ってきた統計量をそのまま使うような奴)だと5%は割とそのまま5%かもしれないので、注意が必要)</li>
</ul><p> 恐らくこのような事情が絡んでくるので、有意水準5%の妥当性は実際には98%とか99%とか、それぐらいには信頼できるように(個人的には)思える<a href="#f-69710a25" name="fn-69710a25" title="だからって98%とか99%でも割ときつい水準だと思うので、これ以上緩める理由はないと思うが">*1</a>。</p><p> </p>
<div class="footnote">
<p class="footnote"><a href="#fn-69710a25" name="f-69710a25" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">だからって98%とか99%でも割ときつい水準だと思うので、これ以上緩める理由はないと思うが</span></p>
</div>
hayataka2049
【python】# coding: utf-8はもうやめる
hatenablog://entry/17391345971637684780
2018-04-23T16:31:59+09:00
2018-11-27T23:38:34+09:00 pythonのプログラムは先頭行(あるいはシェバンの次の二行目)でファイルの文字コードを指定することができます。エンコーディング宣言といいます。 こんなのとか # coding: UTF-8 こういうのもありますね。これはemacsに自動認識させるための書式らしい*1。 # -*- coding: utf-8 -*- これをずっと書いてたんだけど、PEP8を読んでいたらこんな記述に気づきました。 ASCII (Python 2) や UTF-8 (Python 3) を使用しているファイルにはエンコーディング宣言を入れるべきではありません。 はじめに — pep8-ja 1.0 ドキュメント …
<p> pythonのプログラムは先頭行(あるいはシェバンの次の二行目)でファイルの文字コードを指定することができます。エンコーディング宣言といいます。</p><p> こんなのとか</p>
<pre class="code" data-lang="" data-unlink># coding: UTF-8</pre><p> こういうのもありますね。これはemacsに自動認識させるための書式らしい<a href="#f-053a4619" name="fn-053a4619" title="そのくせemacs使いの僕は面倒くさくて上ので済ませてきたんだけど">*1</a>。</p>
<pre class="code" data-lang="" data-unlink># -*- coding: utf-8 -*-</pre><p> これをずっと書いてたんだけど、PEP8を読んでいたらこんな記述に気づきました。</p>
<blockquote>
<p>ASCII (Python 2) や UTF-8 (Python 3) を使用しているファイルにはエンコーディング宣言を入れるべきではありません。</p>
</blockquote>
<p><a href="http://pep8-ja.readthedocs.io/ja/latest/#id12">はじめに — pep8-ja 1.0 ドキュメント</a></p><p> えぇぇぇぇ!? と思ったんだけど、何回読み直しても「デフォルトエンコーディング使うならエンコーディング宣言は書くなよ!」と書いてあるようにしか読めない。</p><p> デフォルトエンコーディングを使うなら不要なのは知っていたけど、コーディング規約で非推奨にされてたのですね・・・。</p><p> ということで、「PEP8に準拠しろよ!」というのはpython使いの常識なので(本当か?)、そして私はpython3しか書かないので、個人的には今後コーディング宣言は使わないことにしました。シェバンも必要に迫られない限りは書かない人間なので、今後私のプログラムは一行目からimportで始まることに。・・・ちょっと寂しい気もするけど、すっきりはする。</p><p> 「入れるべきではない」とまで言い切っているのは少し不思議な感じはするけど、不要なものをわざわざ書けというよりは良いのかもしれませんね。</p>
<div class="footnote">
<p class="footnote"><a href="#fn-053a4619" name="f-053a4619" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">そのくせemacs使いの僕は面倒くさくて上ので済ませてきたんだけど</span></p>
</div>
hayataka2049