Quibako Note

Questions unveiled invite brilliant and keen observation

自然言語処理100本ノック2020(Rev 2)の記録 Chapter 2

自然言語処理100本ノック2020(Rev 2)の記録(Python 3.11)

Chapter 2 UNIXコマンド

popular-names.txtは,アメリカで生まれた赤ちゃんの「名前」「性別」「人数」「年」をタブ区切り形式で格納したファイルである.以下の処理を行うプログラムを作成し,popular-names.txtを入力ファイルとして実行せよ. さらに,同様の処理をUNIXコマンドでも実行し,プログラムの実行結果を確認せよ.

メモ

Jupyterの(IPythonの)シェルコマンド!を使用。Pythonの変数に結果を代入もできる。

後々のため、次の関数を作っておく

  • head_n:イテレータの先頭N個(N行)をprintする
  • tail_n:イテレータの末尾N個(N行)をprintする
  • check:2つの結果(pythonとbash)をリストに入れて、差があった行をタプルで返す
from itertools import islice

def head_n(itr, n):
  for line in islice(itr, n):
    print(line)


def tail_n(itr, n):
  for line in reversed(list(islice(reversed(list(itr)), n))):
    print(line)


def check(rst_py, rst_sh):
  d = []  
  for line, rst in enumerate(zip(rst_py, rst_sh), start=1):
    py, sh = rst
    if py != sh:
      d.append((line,py,sh))

  print(f"- Number of different lines: {len(d)}")
  if d:
    for line, py, sh in d:
      print(f"  - (line {line:03}): {py} | {sh}")

  print("- rst_py (first 5/last 5 lines):")
  head_n(rst_py, 5)
  print(" ---")
  tail_n(rst_py, 5)

10. 行数のカウント

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

メモ

wcコマンド:ファイル内の行数、ワード数、バイト数を出力する。

print("- python:")
with open("popular-names.txt") as f:
  print(len(f.readlines()))

# shell command
!echo "- ${SHELL}:"
!wc popular-names.txt
- python:
2780
- /bin/bash:
 2780 11120 55026 popular-names.txt

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

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

メモ

sedコマンド:ストリームエディタ。スクリプトs/hoge/fuga/gは、hogeをfugaに置換、gは繰り返しマッチ。

import re

re_TAB = re.compile(r"\t")

def substitute_tab(file):
  rst = []
  with open(file) as f:
    for line in f.readlines():
      rst.append(re_TAB.sub(' ', line.rstrip()))
  return rst

# python
rst_py = substitute_tab('popular-names.txt')

# shell
rst_sh = !sed 's/\t/ /g' popular-names.txt

# check
check(rst_py, rst_sh)
- Number of different lines: 0
- rst_py (first 5/last 5 lines):
Mary F 7065 1880
Anna F 2604 1880
Emma F 2003 1880
Elizabeth F 1939 1880
Minnie F 1746 1880
 ---
Benjamin M 13381 2018
Elijah M 12886 2018
Lucas M 12585 2018
Mason M 12435 2018
Logan M 12352 2018

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

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

メモ

cutコマンド:ファイルの各行からバイト、文字、フィールドをカットして出力。-f nオプションで、カットする単位をn番目のフィールド(n列目)に設定。

with open("popular-names.txt") as f0, \
     open('col1.txt', mode='w') as f1, \
     open('col2.txt', mode='w') as f2 :
  for line in f0:
    c1, c2 = line.split()[:2]
    f1.write(c1 + "\n")
    f2.write(c2 + "\n")

# python
rst_py_1 = !cat col1.txt
rst_py_2 = !cat col2.txt

# shell
rst_sh_1 = !cut -f 1 popular-names.txt
rst_sh_2 = !cut -f 2 popular-names.txt

# check
print('(col1.txt)')
check(rst_py_1, rst_sh_1)

print('(col2.txt)')
check(rst_py_2, rst_sh_2)
(col1.txt)
- Number of different lines: 0
- rst_py (first 5/last 5 lines):
Mary
Anna
Emma
Elizabeth
Minnie
 ---
Benjamin
Elijah
Lucas
Mason
Logan
(col2.txt)
- Number of different lines: 0
- rst_py (first 5/last 5 lines):
F
F
F
F
F
 ---
M
M
M
M
M

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

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

メモ

pasteコマンド:複数ファイルの各行を結合。

merged.txtに出力。

with open('col1.txt') as f1, \
     open('col2.txt') as f2, \
     open('merged.txt', mode='w') as fw :
  for l1,l2 in zip(f1, f2):
    fw.write(f"{l1.strip()}\t{l2.strip()}\n")

# python
rst_py = !cat merged.txt

# shell
rst_sh = !paste col1.txt col2.txt

# check
check(rst_py, rst_sh)
- Number of different lines: 0
- rst_py (first 5/last 5 lines):
Mary    F
Anna    F
Emma    F
Elizabeth   F
Minnie  F
 ---
Benjamin    M
Elijah  M
Lucas   M
Mason   M
Logan   M

14. 先頭からN行を出力

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

メモ

headコマンド:ファイルの先頭を表示。-nオプションで行数指定。

コマンドライン引数ありの関数はJupyterでうまく動かせなかったので、実行は別のターミナルで行った。

# knock14.py
from itertools import islice

def head_n(itr, n):
  for line in islice(itr, n):
    print(line)

if __name__ == "__main__":
  import argparse

  parser = argparse.ArgumentParser()
  parser.add_argument("file")
  parser.add_argument("num", type=int)
  args = parser.parse_args()

  with open(args.file) as f:
    head_n(map(lambda l: l.rstrip(), f.readlines()), args.num)
$ python knock14.py popular-names.txt 10
Mary    F       7065    1880
Anna    F       2604    1880
Emma    F       2003    1880
Elizabeth       F       1939    1880
Minnie  F       1746    1880
Margaret        F       1578    1880
Ida     F       1472    1880
Alice   F       1414    1880
Bertha  F       1320    1880
Sarah   F       1288    1880
$ head popular-names.txt -n 10
Mary    F       7065    1880
Anna    F       2604    1880
Emma    F       2003    1880
Elizabeth       F       1939    1880
Minnie  F       1746    1880
Margaret        F       1578    1880
Ida     F       1472    1880
Alice   F       1414    1880
Bertha  F       1320    1880
Sarah   F       1288    1880

15. 末尾のN行を出力

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

メモ

headコマンド:ファイルの先頭を表示。-nオプションで行数指定。

コマンドライン引数ありの関数はJupyterでうまく動かせなかったので、実行は別のターミナルで行った。 リストにして逆順にしてリストにして逆順にして、と泥臭い感じ。。

# knock15.py
from itertools import islice

def tail_n(itr, n):
  for line in reversed(list(islice(reversed(list(itr)), n))):
    print(line)

if __name__ == "__main__":
  import argparse

  parser = argparse.ArgumentParser()
  parser.add_argument("file")
  parser.add_argument("num", type=int)
  args = parser.parse_args()

  with open(args.file) as f:
    tail_n(map(lambda l: l.rstrip(), f.readlines()), args.num)
$ python knock15.py popular-names.txt 10
Liam    M       19837   2018
Noah    M       18267   2018
William M       14516   2018
James   M       13525   2018
Oliver  M       13389   2018
Benjamin        M       13381   2018
Elijah  M       12886   2018
Lucas   M       12585   2018
Mason   M       12435   2018
Logan   M       12352   2018
$ tail popular-names.txt -n 10
Liam    M       19837   2018
Noah    M       18267   2018
William M       14516   2018
James   M       13525   2018
Oliver  M       13389   2018
Benjamin        M       13381   2018
Elijah  M       12886   2018
Lucas   M       12585   2018
Mason   M       12435   2018
Logan   M       12352   2018

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

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

メモ

splitコマンド:ファイルを複数に分割。オプションなし引数でファイル名のprefixを指定できる。-nオプションで分割数を指定。-n l/3で「行単位で3つに分割」になる。-dでファイル名のsuffix(連番)をアルファベットでなく数字にする。

splitの挙動を見ると、バイト単位(文字単位)で等分したサイズまで1つのファイルに入れて、行の切れ目で切っている様子。なので、それを再現するようなものにしてみた。

# knock16.py
def split_n(lines, n):
  chars = list(map(len, lines)) # list of character number of each lines
  limit = sum(chars)/n # limit of characters for each files

  count = 0 # file counter
  accum = 0 # accumulator of character number in each file

  chunk = 'chunk_python_{0:02}.txt' # filename template
  fw = open(chunk.format(count), mode='w')
  for line, char in zip(lines, chars):
    if accum >= limit:
      count += 1 # increment file counter
      accum = 0 # reset accumulator

      # swich chunk file
      fw.close()
      fw = open(chunk.format(count), mode='w')
    fw.write(line)
    accum += char
  fw.close()


if __name__ == "__main__":
  import argparse

  parser = argparse.ArgumentParser()
  parser.add_argument("file")
  parser.add_argument("num", type=int)
  args = parser.parse_args()

  with open(args.file) as f:
    split_n(f.readlines(), args.num)
$ python knock16.py popular-names.txt 3
$ split popular-names.txt chunk_command_ -n l/3 -d --additional-suffix=.txt
$ head -n 4 chunk*
==> chunk_command_00.txt <==
Mary    F       7065    1880
Anna    F       2604    1880
Emma    F       2003    1880
Elizabeth       F       1939    1880

==> chunk_command_01.txt <==
Donald  M       23840   1927
Joseph  M       23506   1927
Edward  M       19113   1927
Mary    F       66872   1928

==> chunk_command_02.txt <==
Jennifer        F       63114   1974
Amy     F       29565   1974
Michelle        F       25828   1974
Heather F       23181   1974

==> chunk_python_00.txt <==
Mary    F       7065    1880
Anna    F       2604    1880
Emma    F       2003    1880
Elizabeth       F       1939    1880

==> chunk_python_01.txt <==
Donald  M       23840   1927
Joseph  M       23506   1927
Edward  M       19113   1927
Mary    F       66872   1928

==> chunk_python_02.txt <==
Jennifer        F       63114   1974
Amy     F       29565   1974
Michelle        F       25828   1974
Heather F       23181   1974
$ wc chunk*
   957   3828  18343 chunk_command_00.txt
   923   3692  18351 chunk_command_01.txt
   900   3600  18332 chunk_command_02.txt
   957   3828  18343 chunk_python_00.txt
   923   3692  18351 chunk_python_01.txt
   900   3600  18332 chunk_python_02.txt
  5560  22240 110052 total

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

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

メモ

uniqmanには下記noteの記載あり。事前にsortなどの処理が必要。cutで1列目を切り出して、sortで並べ替えて、uniqで重複をまとめる、をパイプでつなげる。

Note: 'uniq' does not detect repeated lines unless they are adjacent. You may want to sort the input first, or use 'sort -u' without 'uniq'.
with open('popular-names.txt') as f :
  s = set()
  for line in f:
    s.add(line.split()[0])

# python
rst_py = sorted(list(s))

# shell
rst_sh = !cut -f 1 popular-names.txt | sort | uniq

# check
check(rst_py, rst_sh)
- Number of different lines: 0
- rst_py (first 5/last 5 lines):
Abigail
Aiden
Alexander
Alexis
Alice
 ---
Tracy
Tyler
Virginia
Walter
William

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

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

メモ

3コラム目が同じ行のうちで順番が違うものがある。 26-27行目のElizabeth, Claraなど。

# python
with open('popular-names.txt') as f:
  rst_py = sorted(
    map(lambda l:l.strip(), f.readlines()),
    key = lambda l: int(l.split()[2])
  )

# shell
rst_sh = !sort popular-names.txt -k 3 -n

# check
check(rst_py, rst_sh)
- Number of different lines: 92
  - (line 026): Elizabeth   F   1852    1881 | Clara    F   1852    1884
  - (line 027): Clara   F   1852    1884 | Elizabeth    F   1852    1881
  - (line 050): Ida F   2049    1886 | Henry    M   2049    1891
  - (line 051): Henry   M   2049    1891 | Ida  F   2049    1886
  - (line 092): Robert  M   2334    1883 | Edward   M   2334    1904
  - (line 093): Edward  M   2334    1904 | Robert   M   2334    1883
  - (line 094): Thomas  M   2337    1886 | Edward   M   2337    1898
  - (line 095): Edward  M   2337    1898 | Thomas   M   2337    1886
  - (line 102): Minnie  F   2372    1886 | Bertha   F   2372    1891
  - (line 103): Bertha  F   2372    1891 | Minnie   F   2372    1886
  - (line 116): Henry   M   2444    1880 | Florence F   2444    1888
  - (line 117): Florence    F   2444    1888 | Henry    M   2444    1880
  - (line 141): Thomas  M   2572    1884 | Joseph   M   2572    1891
  - (line 142): Joseph  M   2572    1891 | Thomas   M   2572    1884
  - (line 175): Joseph  M   2707    1884 | Edward   M   2707    1908
  - (line 176): Edward  M   2707    1908 | Joseph   M   2707    1884
  - (line 204): Margaret    F   2917    1889 | Frank    M   2917    1893
  - (line 205): Frank   M   2917    1893 | Margaret F   2917    1889
  - (line 233): Frank   M   3067    1885 | Ethel    F   3067    1901
  - (line 234): Ethel   F   3067    1901 | Frank    M   3067    1885
  - (line 270): Ethel   F   3287    1894 | Elizabeth    F   3287    1899
  - (line 271): Elizabeth   F   3287    1899 | Ethel    F   3287    1894
  - (line 300): Florence    F   3471    1895 | Elizabeth    F   3471    1896
  - (line 301): Elizabeth   F   3471    1896 | Florence F   3471    1895
  - (line 302): Frank   M   3477    1900 | Dorothy  F   3477    1904
  - (line 303): Dorothy F   3477    1904 | Frank    M   3477    1900
  - (line 381): Ruth    F   4249    1898 | Margaret F   4249    1899
  - (line 382): Margaret    F   4249    1899 | Ruth F   4249    1898
  - (line 417): George  M   4671    1886 | Alice    F   4671    1910
  - (line 418): Alice   F   4671    1910 | George   M   4671    1886
  - (line 479): James   M   5441    1881 | George   M   5441    1910
  - (line 480): George  M   5441    1910 | James    M   5441    1881
  - (line 661): Mary    F   11754   1888 | Chloe    F   11754   2010
  - (line 662): Chloe   F   11754   2010 | Mary F   11754   1888
  - (line 726): Mary    F   13446   1895 | John M   13446   1911
  - (line 727): John    M   13446   1911 | Mary F   13446   1895
  - (line 783): Mary    F   14486   1902 | Margaret F   14486   1913
  - (line 784): Margaret    F   14486   1913 | Mary F   14486   1902
  - (line 791): Nancy   F   14544   1935 | Hannah   F   14544   2006
  - (line 792): Hannah  F   14544   2006 | Nancy    F   14544   1935
  - (line 848): Margaret    F   15239   1933 | Madison  F   15239   2009
  - (line 849): Madison F   15239   2009 | Margaret F   15239   1933
  - (line 855): Frank   M   15291   1916 | Daniel   M   15291   2011
  - (line 856): Daniel  M   15291   2011 | Frank    M   15291   1916
  - (line 885): Virginia    F   15636   1919 | Alexis   F   15636   2002
  - (line 886): Alexis  F   15636   2002 | Virginia F   15636   1919
  - (line 891): Frank   M   15702   1919 | Alexander    M   15702   2011
  - (line 892): Alexander   M   15702   2011 | Frank    M   15702   1919
  - (line 948): Richard M   16376   1921 | Helen    F   16376   1932
  - (line 949): Helen   F   16376   1932 | Richard  M   16376   1921
  - (line 977): Nancy   F   16756   1936 | Alexander    M   16756   2010
  - (line 978): Alexander   M   16756   2010 | Nancy    F   16756   1936
  - (line 1071): Heather    F   17947   1981 | Christopher  M   17947   2008
  - (line 1072): Christopher    M   17947   2008 | Heather  F   17947   1981
  - (line 1091): Kelly  F   18235   1977 | Jessica  F   18235   1998
  - (line 1092): Jessica    F   18235   1998 | Kelly    F   18235   1977
  - (line 1194): Dorothy    F   19404   1935 | Anthony  M   19404   2006
  - (line 1195): Anthony    M   19404   2006 | Dorothy  F   19404   1935
  - (line 1231): Ronald M   19835   1939 | Amy  F   19835   1980
  - (line 1232): Amy    F   19835   1980 | Ronald   M   19835   1939
  - (line 1273): Margaret   F   20295   1928 | Elizabeth    F   20295   1989
  - (line 1274): Elizabeth  F   20295   1989 | Margaret F   20295   1928
  - (line 1311): Ronald M   20730   1940 | Andrew   M   20730   2005
  - (line 1312): Andrew M   20730   2005 | Ronald   M   20730   1940
  - (line 1472): Nancy  F   23212   1944 | Amy  F   23212   1978
  - (line 1473): Amy    F   23212   1978 | Nancy    F   23212   1944
  - (line 1499): Betty  F   23641   1939 | Andrew   M   23641   2000
  - (line 1500): Andrew M   23641   2000 | Betty    F   23641   1939
  - (line 1579): Melissa    F   25095   1976 | Joshua   M   25095   2003
  - (line 1580): Joshua M   25095   2003 | Melissa  F   25095   1976
  - (line 1590): Judith F   25209   1943 | Amy  F   25209   1970
  - (line 1591): Amy    F   25209   1970 | Judith   F   25209   1943
  - (line 1615): Lisa   F   25691   1959 | Emily    F   25691   2003
  - (line 1616): Emily  F   25691   2003 | Lisa F   25691   1959
  - (line 1648): Ruth   F   26102   1920 | Jessica  F   26102   1978
  - (line 1649): Jessica    F   26102   1978 | Ruth F   26102   1920
  - (line 1655): Margaret   F   26237   1919 | Amy  F   26237   1971
  - (line 1656): Amy    F   26237   1971 | Margaret F   26237   1919
  - (line 1849): Dorothy    F   30409   1930 | Donald   M   30409   1934
  - (line 1850): Donald M   30409   1934 | Dorothy  F   30409   1930
  - (line 1902): Mark   M   31492   1970 | Justin   M   31492   1987
  - (line 1903): Justin M   31492   1987 | Mark M   31492   1970
  - (line 1965): Jennifer   F   32703   1987 | James    M   32703   1989
  - (line 1966): James  M   32703   1989 | Jennifer F   32703   1987
  - (line 2000): Lisa   F   33702   1960 | Jennifer F   33702   1969
  - (line 2001): Jennifer   F   33702   1969 | Lisa F   33702   1960
  - (line 2070): Robert M   35220   1917 | Patricia F   35220   1959
  - (line 2071): Patricia   F   35220   1959 | Robert   M   35220   1917
  - (line 2244): Robert M   40620   1918 | Barbara  F   40620   1951
  - (line 2245): Barbara    F   40620   1951 | Robert   M   40620   1918
  - (line 2400): William    M   49350   1960 | Mark M   49350   1963
  - (line 2401): Mark   M   49350   1963 | William  M   49350   1960
- rst_py (first 5/last 5 lines):
Sarah   F   1288    1880
Alice   F   1308    1881
Bertha  F   1320    1880
Bertha  F   1324    1881
Annie   F   1326    1881
 ---
Robert  M   91640   1947
Michael M   92704   1957
James   M   94757   1947
Linda   F   96211   1948
Linda   F   99689   1947

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

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

メモ

cutで1カラム目の名前を切り出して、sortで並べて重複する名前を一か所に集めて、uniq -cで重複をカウントして各行の先頭に追加して、sortで追加したカウントを数値として比較して(-d)逆順に並べる(-r)、をパイプラインで処理。

出願頻度が同じ行同士で順番が違うものがある。 3-4行目のJohn, Robertなど。

with open('popular-names.txt') as f:
  d = dict() # empty dictionary
  for line in f:
    name = line.split()[0]
    if name in d:
      d[name] += 1
    else:
      d[name] = 1
# python
rst_py = [f"{count:7} {name}" for name, count in sorted(d.items(), key=lambda x: x[1], reverse=True)]

# shell
rst_sh = !cut -f 1 popular-names.txt | sort | uniq -c | sort -k 1 -d -r

# check
check(rst_py, rst_sh)
- Number of different lines: 86
  - (line 003):     108 John |     108 Robert
  - (line 004):     108 Robert |     108 John
  - (line 011):      58 George |      58 Thomas
  - (line 012):      58 Thomas |      58 George
  - (line 026):      31 Daniel |      31 Joshua
  - (line 027):      31 Joshua |      31 Daniel
  - (line 034):      24 Mildred |      24 Susan
  - (line 035):      24 Betty |      24 Mildred
  - (line 036):      24 Susan |      24 Betty
  - (line 041):      20 Florence |      20 Marie
  - (line 042):      20 Marie |      20 Florence
  - (line 046):      18 Karen |      18 Olivia
  - (line 047):      18 Lisa |      18 Melissa
  - (line 048):      18 Melissa |      18 Madison
  - (line 049):      18 Madison |      18 Lisa
  - (line 050):      18 Olivia |      18 Karen
  - (line 053):      16 Ethel |      16 Sandra
  - (line 054):      16 Sandra |      16 Mark
  - (line 055):      16 Mark |      16 Ethel
  - (line 056):      15 Frances |      15 Michelle
  - (line 057):      15 Carol |      15 Isabella
  - (line 058):      15 Angela |      15 Heather
  - (line 059):      15 Michelle |      15 Frances
  - (line 060):      15 Heather |      15 Ethan
  - (line 061):      15 Ethan |      15 Carol
  - (line 062):      15 Isabella |      15 Angela
  - (line 065):      14 Amy |      14 Ava
  - (line 066):      14 Ava |      14 Amy
  - (line 068):      13 Deborah |      13 Sophia
  - (line 069):      13 Brian |      13 Nicole
  - (line 071):      13 Nicole |      13 Hannah
  - (line 072):      13 Hannah |      13 Deborah
  - (line 073):      13 Sophia |      13 Brian
  - (line 075):      12 Bertha |      12 Donna
  - (line 076):      12 Donna |      12 Bertha
  - (line 078):      10 Alice |      10 Ronald
  - (line 079):      10 Doris |      10 Noah
  - (line 080):      10 Ronald |      10 Nicholas
  - (line 081):      10 Brittany |      10 Mia
  - (line 082):      10 Nicholas |      10 Doris
  - (line 083):      10 Mia |      10 Brittany
  - (line 084):      10 Noah |      10 Alice
  - (line 085):       9 Joan |       9 Tyler
  - (line 086):       9 Debra |       9 Joan
  - (line 087):       9 Tyler |       9 Debra
  - (line 088):       8 Ida |       8 Taylor
  - (line 089):       8 Clara |       8 Mason
  - (line 091):       8 Taylor |       8 Ida
  - (line 092):       8 Alexis |       8 Clara
  - (line 093):       8 Alexander |       8 Alexis
  - (line 094):       8 Mason |       8 Alexander
  - (line 095):       7 Harry |       7 Tammy
  - (line 096):       7 Sharon |       7 Steven
  - (line 097):       7 Steven |       7 Sharon
  - (line 098):       7 Tammy |       7 Liam
  - (line 099):       7 Brandon |       7 Harry
  - (line 100):       7 Liam |       7 Brandon
  - (line 102):       5 Annie |       5 Jeffrey
  - (line 103):       5 Gary |       5 Jayden
  - (line 104):       5 Jeffrey |       5 Gary
  - (line 105):       5 Jayden |       5 Charlotte
  - (line 106):       5 Charlotte |       5 Annie
  - (line 110):       4 Austin |       4 Chloe
  - (line 111):       4 Chloe |       4 Benjamin
  - (line 112):       4 Benjamin |       4 Austin
  - (line 113):       3 Evelyn |       3 Megan
  - (line 114):       3 Megan |       3 Harper
  - (line 115):       3 Aiden |       3 Evelyn
  - (line 116):       3 Harper |       3 Elijah
  - (line 117):       3 Elijah |       3 Aiden
  - (line 118):       2 Bessie |       2 Rebecca
  - (line 119):       2 Larry |       2 Oliver
  - (line 120):       2 Rebecca |       2 Logan
  - (line 122):       2 Amelia |       2 Larry
  - (line 123):       2 Logan |       2 Bessie
  - (line 124):       2 Oliver |       2 Amelia
  - (line 126):       1 Carolyn |       1 Tracy
  - (line 127):       1 Pamela |       1 Scott
  - (line 128):       1 Lori |       1 Rachel
  - (line 129):       1 Laura |       1 Pamela
  - (line 130):       1 Tracy |       1 Lucas
  - (line 131):       1 Julie |       1 Lori
  - (line 132):       1 Scott |       1 Laura
  - (line 134):       1 Crystal |       1 Julie
  - (line 135):       1 Rachel |       1 Crystal
  - (line 136):       1 Lucas |       1 Carolyn
- rst_py (first 5/last 5 lines):
    118 James
    111 William
    108 John
    108 Robert
     92 Mary
 ---
      1 Scott
      1 Kelly
      1 Crystal
      1 Rachel
      1 Lucas