微忘録

好奇心に記憶力がついていかない人のブログ

pandasでtimezoneを含むstringレコードをdatetimeに型変換する方法

pandasのto_datetime()関数はtimezoneフォーマットの%zに対応していなかったので、解決策を備忘録。

t.co

github.com

解決策

今回はnginxログで23/Apr/2018:14:21:43 +0000 形式の文字列を例として用います。 解決方法は要は、datetime.strptime()関数で推論できる状態に整えてから、to_datetime()関数に与えてあげます。

import pandas as pd
from datetime import datetime

df = pd.DataFrame({'datetime_like_column' : pd.Series(['23/Apr/2018:14:21:43 +0000', '29/Dec/2018:03:36:27 +0000'])})

f = lambda x: datetime.strptime(x, '%d/%b/%Y:%H:%M:%S %z')

#datetimeもしくはdate型かつタイムゾーンはutc指定
df['datetime_like_column_as_datetime'] = pd.to_datetime(df['datetime_like_column'].apply(f), utc=True)
df['datetime_like_column_as_date'] = pd.to_datetime(df['datetime_like_column'].apply(f), utc=True).dt.date
df
datetime_like_column datetime_like_column_as_datetime datetime_like_column_as_date
0 23/Apr/2018:14:21:43 +0000 2018-04-23 14:21:43+00:00 2018-04-23
1 29/Dec/2018:03:36:27 +0000 2018-12-29 03:36:27+00:00 2018-12-29

終わりに

今回扱った問題はpandas の major release 0.24.0 で修正されるようです。 f:id:wtnVenga:20190107005004p:plain

また、同一カラムに複数のtimezoneがある場合の変換方法については、以下をご参照ください。 (indexカラムとして扱うことで攻略できるらしいです)

note.nkmk.me

numpyオブジェクトをjson.dumpできるようにエンコーダーを拡張する方法

最近、友人の運営する大学講義の検索サイトを、機械学習で良い感じにしてます。

地味に悩んだのが「JSON形式でのデータ入出力」の部分。具体的には、「JSON形式で渡されたデータに、推定結果の一部numpyオブジェクトを加えたJSONデータを返す」作業。

Pythonなど動的言語はデータ型をよしなに判断してくれますが、少し例外に触れた時には指定してあげる必要があります。
今回はその例外のためにクラスを自作して指定する方法を備忘録。

問題

何も引数に指定せず、ただ以下の様にjson.dumps()メソッドにnumpy.int64などを渡すと、以下の様なエラーに遭遇する。

json.dumps(numpy.int64(111))
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-12-c21d581d4bed> in <module>()
----> 1 json.dumps(np.int64(111))


/usr/local/var/pyenv/versions/anaconda3-5.0.0/lib/python3.6/json/__init__.py in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, default, sort_keys, **kw)
    229         cls is None and indent is None and separators is None and
    230         default is None and not sort_keys and not kw):
--> 231         return _default_encoder.encode(obj)
    232     if cls is None:
    233         cls = JSONEncoder


/usr/local/var/pyenv/versions/anaconda3-5.0.0/lib/python3.6/json/encoder.py in encode(self, o)
    197         # exceptions aren't as detailed.  The list call should be roughly
    198         # equivalent to the PySequence_Fast that ''.join() would do.
--> 199         chunks = self.iterencode(o, _one_shot=True)
    200         if not isinstance(chunks, (list, tuple)):
    201             chunks = list(chunks)


~~~

TypeError: Object of type 'int64' is not JSON serializable

この一文は「JSONモジュールの既存エンコーダーに対応している型じゃないから変換無理です」という話

TypeError: Object of type 'int64' is not JSON serializable

なので既存エンコーダーに、自前のエンコード用クラスを与えて拡張する必要があります。

解決策

以下のような、型の種類ごとに変換を行うクラスを作成して、JSONモジュールに対応する型にします。

  • isinstance(object, class)で、一致する場合はreturn以下で変換して返す。
  • numpy.integerint型へ
  • numpy.floatingfloat型へ
  • numpy.ndarraylist型へ

(今回はint型の変換だけで良いのですが、オマケでその他も加えておきます。)

import numpy
import json

class MyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, numpy.integer):
            return int(obj)
        elif isinstance(obj, numpy.floating):
            return float(obj)
        elif isinstance(obj, numpy.ndarray):
            return obj.tolist()
        else:
            return super(MyEncoder, self).default(obj)

そしてjson.dump()cls引数にクラスを渡してあげます。

json.dumps(numpy.int64(111),cls = MyEncoder)
'111'

解決!

最後に

JSON形式で数値を扱うこと自体ナンセンスかもしれませんが、遭遇しやすい問題かなと思うので載せておきました。 良き分析ライフを御過ごしください。

参考記事

以下記事を参考にしております。先人の知恵に感謝です。

GitHubのセキュリティ設定でやるべきこと

GitHub周りのセキュリティ設定、何回忘れたのかさえ忘れました。 公開鍵でSSH接続して、EmailをPrivateするだけの備忘録です。

※厳密なセキュリティ設定は記述しないので、他の猛者の方々の記事を参考にして下さい。


アカウントと公開鍵の設定

鍵セットの作成

rsa指定で鍵セットを作成。既存がある際は重複削除しないよう注意。

$ cd ~/.ssh #移動して
$ ssh-keygen -t rsa -C mymail@example.com #鍵作成。-C以下任意で自分のメールアドレス

SSH連携

ssh/configに記入し、GitHubとのssh接続を楽にする。

$ vim ~/.ssh/config 

#以下をインサート
Host github.com
  HostName github.com
  IdentityFile ~/.ssh/id_rsa
  User git

公開鍵をクリップボードにコピーして、GitHubアカウントのSSH keysでコピペして登録。

$ pbcopy < ~/.ssh/id_rsa.pub

接続成功したか確認。成功したら以下のような文が出てくる

$ ssh -T git@github.com
Hi wtnVenga! You've successfully authenticated, but GitHub does not provide shell access.

ローカルリポジトリのconfig設定

ローカルリポジトリに移動。config設定を開いて、https://~git@~に変更。

$ cd [local repository]
$ vim .git/config

#'url = https://github.com/[user_name]/[repository_name].git' の部分を以下形式に変更。
url = git@github.com:[user_name]/[repository_name].git

PrivateEmailの利用

GithubのEmail設定をPrivate化するとEmail情報を守れる。
(※リモートリポジトリをcloneされた時にcommitログから漏れない。)

GitHubアカウントの設定

まずはEmail設定の Keep my email address privateBlock command line pushes that expose my email にチェック。 表示される[userid]+[username]@users.noreply.github.com をコピペ。

git configの設定

git configのemail設定を書き換える(--global--local かはお好みで)

$ git config --global user.email [userid]+[username]@users.noreply.github.com

(commitログ書き換え)

最新コミットログの変更。(開いたら:ZZで保存するだけ)

git commit --amend --reset-author

過去コミットログの変更。自分のSHA(コミットハッシュ値から)を指定

git rebase -i [my_SHA] -x "git commit --amend --reset-author -CHEAD"

参考元

git - Meaning of the GitHub message: push declined due to email privacy restrictions - Stack Overflow

How to amend several commits in Git to change author - Stack Overflow

gensimのmodels.TfidfModel()で、引数にSMART notationが使えるようになっていた話

つい先日こんなツイートをしたところ、爆速で公式からリプライが来ました。

「2018年1月2日のgensim3.3.0のリリースに際して、TfidfModelにSMART notation機能が追加されたから宜しくな!」という話で、つまり「models.TfidfModel()コーパスの重み付け手法の選択が、簡単な記法でできるsmartirs引数を新たに用意したよ」という要旨です。今回はこの機能について宣伝と備忘録。

gensimとTF-IDF法

gensimについて

gensimはLSIやLDAなどのトピック分析を行う際に便利なPythonモジュールです。トピック分析の発端である自然言語処理での活用と主しており、文書ごと単語リスト*1(配列)を用意すれば、gensimモジュールの関数を用いて、辞書とコーパスの作成からトピック推定と評価まで可能です。

TF-IDFについて

そして今回備忘録をするmodels.TfidfModel()は、コーパス作成時に単語にTF-IDF法を用いた重み付けをする関数です。

TFは"Term Frequency"つまり文書内単語頻度、IDFは"Inverse Document Frequency"つまり逆文書頻度、そしてTF-IDFはそれら2種の重み付けの積で、「全文書内での出現頻度は低いが、特定文書にて頻繁に用いられる特定単語に、強い重み付けができる」方法です。

そしてgensim3.3.0以前までのmodels.TfidfModel()ではTF-IDF法のみしか指定できず、「TF法だけ」もしくは「IDF法だけ」は自作する必要がありました。*2 この面倒くささを改善したのが、今回のSMART notation機能の導入です。

SMART notationを試す

SMART notationとは

SMART (System for the Mechanical Analysis and Retrieval of Text) notationとは、「文書検索システムにおける重み付けの簡便表記法」になります。

伝統的なベクトル空間モデルを用いた文書検索では、クエリ内容(文書名)に対して、各文書の単語群(Bag-of-Words)の出現頻度にコサイン類似度を用いた計算により、類似性の高い文書を検索結果として表示します。この時の検索結果を左右するのが、TF-IDF法などによる文書内単語群それぞれ対する重み付けです。*3

そしてこの文書内単語群に行われる重み付けを簡便的に表記法する方法が"SMART notation"であり、以下一覧のような表記になります。*4 f:id:wtnVenga:20180208115703p:plain

ここから"単語""文書""正規化"の順に記号を3つ重ねるだけで、どのような重み付けがされるのかが一目瞭然になります。

gensim3.3.0でサンプルコード

そしてmodels.TfidfModel()に"smartirs"引数が追加されたことでSMART notationが利用可能になりました。以下のように重み付けを指定することができます。

from gensim.corpora import Dictionary
from gensim.models import TfidfModel

documents = ["Human machine interface for lab abc computer applications",
              "A survey of user opinion of computer system response time",
              "The EPS user interface management system",
              "System and human system engineering testing of EPS",
              "Relation of user perceived response time to error measurement",
              "The generation of random binary unordered trees",
              "The intersection graph of paths in trees",
              "Graph minors IV Widths of trees and well quasi ordering",
              "Graph minors A survey"]

# 以下の7語をストップワードとして定義
stop_words = set('for a of the and to in'.split())

# 文を単語に分割し、ストップワードを除去した配列を作成
texts = [[word for word in document.lower().split() if word not in stop_words] for document in documents]

#辞書とコーパスの作成
dictionary = Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]

#"n"(tf法)と、"t"(idf法)で、"c"(コサイン正規化)した重み付け
model = TfidfModel(corpus, id2word=dictionary, smartirs="ntc")
vectorized_corpus = list(model[corpus])

最後に

gensim3.3.0は最新版のAnaconda3-5.0.0では未だ対応していないので、別途"pip install"する必要があります。早く追加されて欲しいところ。

*1:厳密化すると「単語(Term)」よりも、字句解析における「トークン(token)」のことです。形態素解析などを用いても必ずしも意味ある単語にすることは難しく、あくまでも文字のカタマリとして「トークン」と呼ばれます。

*2:L2正規化するか否かの"normalise"引数は既存

*3:https://nlp.stanford.edu/IR-book/html/htmledition/queries-as-vectors-1.html#eqn:cosinescore

*4:https://nlp.stanford.edu/IR-book/html/htmledition/document-and-query-weighting-schemes-1.html

MALLETラッパーを用いた、gensimでの"Gibbs sampler"によるトピック推定を試す

LSIやLDAなどのトピック分析をPythonで実行するなら、gensimモジュールの利用が一般的です。しかしgensimでは変分ベイズ法による推定しか基本的に対応しておらず、その他のギブスサンプリングなどを用いるには少し工夫が必要です。

そこで今回はgensimにあるgensim.models.wrappers.LdaMallet()という、java製のオープンソースソフトであるMALLETのラッパー機能を用いて、Pythonかつgensimの環境でギブスサンプリングによるトピック推定をざっくりと流れだけ試します。

崩壊型ギブスサンプリングはldaモジュールで可能です。現行のscikit-learnモジュールのLDAは変分ベイズのみです。ご注意を。

なお以下の環境で準備します。詳細については適宜ググってください。

MALLETの準備

MALLETをダウンロードして、Apach antでディレクトリをビルドするだけ

  1. MALLETのダウンロード(こちらから Downloading MALLET
  2. MALLETのディレクトリにてantコマンドでビルド
  3. "BUILD SUCCESSFUL"が表示されたらビルド成功
  4. ディレクトリのパスを"Users/~.../mallet-2.0.8/bin/mallet"まで記憶

Pythonの実行

文書ごと単語リストの用意

トピック分析したい文書群(documents)リストを用意し、ストップワード除去を行う。
gensimチュートリアルを引用

documents = ["Human machine interface for lab abc computer applications",
              "A survey of user opinion of computer system response time",
              "The EPS user interface management system",
              "System and human system engineering testing of EPS",
              "Relation of user perceived response time to error measurement",
              "The generation of random binary unordered trees",
              "The intersection graph of paths in trees",
              "Graph minors IV Widths of trees and well quasi ordering",
              "Graph minors A survey"]

# 以下の7語をストップワードとして定義
stop_words = set('for a of the and to in'.split())

# 文を単語に分割し、ストップワードを除去した配列を作成
texts = [[word for word in document.lower().split() if word not in stop_words] for document in documents]

以下のような中身の単語リスト(texts)に格納されました。

    [['human', 'machine', 'interface', 'lab', 'abc', 'computer', 'applications'], ['survey', 'user', 'opinion', 'computer', 'system', 'response', 'time']]

辞書とコーパスの作成

gensimモジュールを呼び出し、文書ごと単語リストを元に辞書とコーパスを作成します。

from gensim import corpora, models
import gensim

#辞書とコーパスを作成
dictionary = corpora.Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]

#コーパスをMALLET用の形式に変換します。
corpora.malletcorpus.MalletCorpus.serialize("./corpus.mallet", corpus)
mallet_corpus = corpora.malletcorpus.MalletCorpus("./corpus.mallet")

ギブスサンプリングによるトピックモデル推定

ビルドされたMALLETのパス(mallet_path)を指定し、用意した辞書とコーパスで3つのトピックを推定。

mallet_path = "Users/~.../mallet-2.0.8/bin/mallet"
lda = models.wrappers.LdaMallet(mallet_path, mallet_corpus, num_topics=3, id2word=dictionary)

推定されたトピックを確認。各トピック内容の解釈は割愛。

lda.print_topics()
 [(0,
  '0.182*"random" + 0.091*"user" + 0.091*"machine" + 0.091*"binary" + 0.091*"engineering" + 0.091*"paths" + 0.091*"human" + 0.091*"opinion" + 0.091*"minors" + 0.091*"lab"'),
 (1,
  '0.136*"perceived" + 0.136*"interface" + 0.136*"measurement" + 0.045*"survey" + 0.045*"graph" + 0.045*"eps" + 0.045*"time" + 0.045*"trees" + 0.045*"ordering" + 0.045*"testing"'),
 (2,
  '0.176*"quasi" + 0.118*"iv" + 0.118*"computer" + 0.059*"system" + 0.059*"relation" + 0.059*"generation" + 0.059*"management" + 0.059*"time" + 0.059*"response" + 0.059*"human"')]

最後に

今のところ「やってみた」系の記事では変分ベイズでの実装しか見当たらないので備忘録してみました。

gensimには他にも、Biei先生のフォーマットや、GibbsLDA++のフォーマットなどがあります(gensim: Corpora and Vector Spaces)。 そのため「gensimでデータ整形だけして他で実行するぜ!」な強者の方々は、その他の選択肢も是非ご検討ください。

※記事内容の改善点にお気付きの方は、コメントにてご一報いただけますと幸甚です。

2015年度版NLP100本ノック第2章をPython3で解く

前回(2015年度版NLP100本ノック第1章をPython3で解く - 微忘録)の続き。 bashとPython3で。各コードの実行結果は、こちらのリポジトリにて公開しています。

第2章: UNIXコマンドの基礎

hightemp.txtは,日本の最高気温の記録を「都道府県」「地点」「℃」「日」のタブ区切り形式で格納したファイルである.以下の処理を行うプログラムを作成し,hightemp.txtを入力ファイルとして実行せよ.さらに,同様の処理をUNIXコマンドでも実行し,プログラムの実行結果を確認せよ.

10. 行数のカウント

行数をカウントせよ.確認にはwcコマンドを用いよ.

%%bash
wc -l ./datasets/hightemp.txt
with open("./datasets/hightemp.txt","r") as hightemp:
    print(len(hightemp.readlines()))

11. タブをスペースに置換

タブ1文字につきスペース1文字に置換せよ.確認にはsedコマンド,trコマンド,もしくはexpandコマンドを用いよ.

%%bash
sed -e "s/\t/| /g" ./datasets/hightemp.txt
import re
with open("./datasets/hightemp.txt","r") as hightemp:
    lines = hightemp.readlines()
    print(lines,'\n')
    
    print([re.sub(r'\t'," ",hightemp)for hightemp in lines])

12. 1列目をcol1.txtに,2列目をcol2.txtに保存

各行の1列目だけを抜き出したものをcol1.txtに,2列目だけを抜き出したものをcol2.txtとしてファイルに保存せよ.確認にはcutコマンドを用いよ.

%%bash
cut -f 1 ./datasets/hightemp.txt > ./datasets/col1.txt
cut -f 2 ./datasets/hightemp.txt > ./datasets/col2.txt
with open("./datasets/hightemp.txt") as hightemp:
    lines = hightemp.readlines()
    
    #col1.txt
    col1 = []
    for line in lines:
        col1.append(line.split()[0] + "\n") #"\n"で単語ごとに改行
        
    with open("./datasets/col1py.txt" , "w") as split:
            split.writelines(col1)
    
    #col2.txt
    col2 = []
    for line in lines:
        col2.append(line.split()[1] + "\n")
        
    with open("./datasets/col2py.txt" , "w") as split:
            split.writelines(col2)
            
    hightemp.close()

13. col1.txtとcol2.txtをマージ

12で作ったcol1.txtとcol2.txtを結合し,元のファイルの1列目と2列目をタブ区切りで並べたテキストファイルを作成せよ.確認にはpasteコマンドを用いよ

%%bash
paste -d"\t" ./datasets/col1.txt ./datasets/col2.txt
with open("./datasets/col1.txt") as col1_file, open("./datasets/col2.txt") as col2_file:
    col1, col2 = col1_file.readlines(), col2_file.readlines()

with open("./datasets/merged.txt", "w") as writer:
    for a, b in zip(col1, col2):
        writer.write("\t".join([a.rstrip(),b]))
        
for i in open("./datasets/merged.txt"):
    print(i)

14. 先頭からN行を出力

自然数Nをコマンドライン引数などの手段で受け取り,入力のうち先頭のN行だけを表示せよ.確認にはheadコマンドを用いよ.

%%bash
head -n 5 ./datasets/hightemp.txt
def head(n,file):
    with open(file,'r') as hightemp:
        lines = hightemp.readlines()
        for lineNumber in range(n):
            print(lines[lineNumber])
            
head(5, "./datasets/hightemp.txt")

15. 末尾のN行を出力

自然数Nをコマンドライン引数などの手段で受け取り,入力のうち末尾のN行だけを表示せよ.確認にはtailコマンドを用いよ

%%bash
tail -n 5 ./datasets/hightemp.txt
def tail(n,file):
    with open(file,'r') as hightemp:
        lines = hightemp.readlines()
        stopline = len(lines) - n
        for lineNumber in range(stopline,len(lines),1):
            print(lines[lineNumber])
            
tail(5, "./datasets/hightemp.txt")

16. ファイルをN分割する

自然数Nをコマンドライン引数などの手段で受け取り,入力のファイルを行単位でN分割せよ.同様の処理をsplitコマンドで実現せよ.

%%bash
split -l 5 ./datasets/hightemp.txt ./datasets/n-split_
def splitfunc(file,n):
    with open(file) as filed:
        lines = filed.readlines()
    
    for i in range(n):
        with open("./datasets/splitblock%s.txt" % str(i), "w") as split:
            split.writelines(lines[n*i : n*(i +1)])
            
splitfunc("./datasets/hightemp.txt",3)

with open("./datasets/splitblock2.txt","r") as check:
    print(check.readlines())

17. 1列目の文字列の異なり

1列目の文字列の種類(異なる文字列の集合)を求めよ.確認にはsort, uniqコマンドを用いよ.

%%bash
cut -f 1 ./datasets/hightemp.txt |sort | uniq
with open("./datasets/hightemp.txt","r") as hightemp:
    lines = hightemp.readlines()
    
    col1 = []
    for line in lines:
        col1.append(line.split()[0] + "\n") #"\n"で単語ごとに改行

    li = set(col1)
    print(sorted(li))

18. 各行を3コラム目の数値の降順にソート

各行を3コラム目の数値の逆順で整列せよ(注意: 各行の内容は変更せずに並び替えよ).確認にはsortコマンドを用いよ(この問題はコマンドで実行した時の結果と合わなくてもよい).

%%bash
sort -nk3r ./datasets/hightemp.txt
with open("./datasets/hightemp.txt", 'r') as hightemp:
    lines = hightemp.readlines()
    for line in sorted(lines,key=lambda x: x.split()[2], reverse=False):
        print(line)

19. 各行の1コラム目の文字列の出現頻度を求め,出現頻度の高い順に並べる

各行の1列目の文字列の出現頻度を求め,その高い順に並べて表示せよ.確認にはcut, uniq, sortコマンドを用いよ.

%%bash
cut -f 1 ./datasets/hightemp.txt | sort |uniq -c | sort -r
from collections import Counter

with open("./datasets/hightemp.txt","r") as hightemp:
    lines = hightemp.readlines()
    
    li = []
    for line in lines:
        li.append(line.split()[0])
    
    counted = Counter(li)
    print(counted)

2015年度版NLP100本ノック第1章をPython3で解く

Djangoアプリへの導入などを考えて、Pythonでやり直したいと思い挑戦したので備忘録。
各コードの実行結果はこちらのリポジトリにて公開しています。

第1章: 準備運動

00. 文字列の逆順

文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ

word = "stressed"
print(word[::-1])

01. 「パタトクカシーー」

「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

#単純に2飛ばしで
word = "パタトクカシーー"
print(word[::2])

02. 「パトカー」+「タクシー」=「パタトクカシーー」

「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.

#分割する文字列と、格納するリストを作成
word = "パタトクカシーー"
word_li =[]

#特定の順番の文字を分割し、リストに要素として格納する
for i in range(1,len(word),2) :
    word_li.append(word[i])

#リスト内文字をスペース無しで連結する
word_li = "".join(word_li)    
print(word_li)

03. 円周率

"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

#すでに分かち書きされているので、半角スペースごとに分解してリストに格納。
sentence = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
sentence_li =[]
sentence_li = sentence.split(" ")
#リストを各単語の(アルファベットの)文字数を先頭から出現順に並べる
sorted(sentence_li,key=len)

04. 元素記号

"Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭に2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

#単語に分解
sentence = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."
sentence_li = sentence.split(" ")

sentence_dict = {}
topword = [1, 5, 6, 7, 8, 9, 15, 16, 19]

for i in sentence_li:
    if sentence_li.index(i) + 1 in topword:
        sentence_dict[i[:1]] = sentence_li.index(i) + 1
    else:
        sentence_dict[i[:2]] = sentence_li.index(i) + 1
        
print(sentence_dict)

05. n-gram

与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,"I am an NLPer"という文から単語bi-gram,文字bi-gramを得よ.

#n-gram関数作り
def ngram(input, n):
    result = []
    for i in range(0, len(input) - n + 1):
        result.append(input[i:i + n])

    return result

#文章用意
sentence = "I am an NLPer"

#単語n-gram(分かち書き)
sentence_li = sentence.split(" ")
ngram(sentence_li, 2)

#文字n-gram(文字区切り)
ngram(sentence, 2)

06. 集合

"paraparaparadise"と"paragraph"に含まれる文字bi-gramの集合を,それぞれ, XとYとして求め,XとYの和集合,積集合,差集合を求めよ.さらに,'se'というbi-gramがXおよびYに含まれるかどうかを調べよ.

sentence1 = "paraparaparadise"
sentence2 = "paragraph"

#bi-gram結果をset型で重複無し
X = set(ngram(sentence1,2))
Y = set(ngram(sentence2,2))

#和集合
X | Y

#積集合
X & Y

#差集合
X - Y

#seを含むか確認
'se' in X
'se' in Y

07. テンプレートによる文生成

引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ.さらに,x=12, y="気温", z=22.4として,実行結果を確認せよ.

def xyz_def(x,y,z) :
    print(str(x) + "時の" + str(y) + "は" + str(z))
    
xyz_def(x=12, y="気温", z=22.4)
def xyz_def(x, y, z):
    print( '{hour}時の{subject}は{value}'.format(hour=x, subject=y, value=z))

xyz_def(x=12, y="気温", z=22.4)

08. 暗号文

与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.

英小文字ならば(219 - 文字コード)の文字に置換 その他の文字はそのまま出力 この関数を用い,英語のメッセージを暗号化・復号化せよ.

def cipher(input) :
    result = ''
    for i in input :
        if i.islower() == True:
            result += chr(219 - ord(i))
        else:
            result += i  
    return result

cipher("oh,myパスタ")

09. Typoglycemia

スペースで区切られた単語列に対して,各単語の先頭と末尾の文字は残し,それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ.ただし,長さが4以下の単語は並び替えないこととする.適当な英語の文(例えば"I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind .")を与え,その実行結果を確認せよ.

import random

def sliceRandom(input) :
    text = input.split(" ")
    result = []
    for i in text:
        if len(i) <= 4:
            result.append(i)
        else:
            ramdomed = list(i[1:-1])
            random.shuffle(ramdomed)
            result.append(i[0] + "".join(ramdomed) + i[-1])
    return "".join(result)

sliceRandom("I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind .")