質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

368閲覧

ジャロウインクラー距離によるデータ抽出 pythonとexcelの連動2

anthony3590

総合スコア16

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2018/10/30 06:57

tiitoiさん、先ほどの質問にご連絡いただきありがとうございます。

また少し目的が変わったので、改めてやりたいことを記載させていただきます。

 〇目的
・2つのデータベース上に記載されている氏名の類似度を計算し、同一人物と思われる者を抽出したい。

 〇データベース
・氏名が記載されたエクセルのデータベースが2つある。(以下では「データ1」、「データ2」と呼びます。)
・それぞれのデータベース内には氏名が記載された列が1列ずつあり、すべてアルファベットで記載されている。
・それぞれのデータベース上の氏名は重複して存在する可能性がある。

 〇問題点
・アルファベットで記載された氏名の順序は両データベースとも、「姓名」の順とは限らず、「名姓」と
なっているこもあり、一定ではない。ただし、語の間には必ずスペースが含まれている。
(例:「YAMADA TARO」の場合も「TARO YAMADA」の場合もある。)  
・氏名のアルファベット表記は一定ではない。
(例:「TANAKA SHOICHI」と「TANAKA SHOUICHI」のように、同一人物であるが表記の違いがある場合。)

 〇やったこと
・氏名の順序が一定でなくても比較ができるよう、それぞれのデータベース上の氏名を、スペースを境に
2つの列に切り分けた。(1つの列に入っていた「YAMADA TARO」を「YAMADA」と「TARO」の2列に、「TARO YAMADA」を
「TARO」と「YAMADA」に。 それぞれのデータベースで切り分けた。)

・それぞれのデータベースから切り分けた氏名(合計4列)を以下のように「test.xlsx」の「テスト」シートにまとめている。
(A・B列はデータ1から、C・D列はデータ2から切り分けたもの。)
A列  B列  C列  D列
TANAKA SHOICHI TARO   YAMADA
YAMADA TARO TAKASHI HARA
HIROBUMI ITO TANAKA SHOUICHI
MASAYOSHI MATSUKATA ODA   NOBUNAGA

・以下のコードをIDLEで記述した。

import openpyxl
import Levenshtein

book = openpyxl.load_workbook('test.xlsx')
sheet = book.get_sheet_by_name('テスト')

for i in range(1,5):
for j in range(1,5):
A列=(sheet.cell(row=j,
column=1
).value)

B列=(sheet.cell(row=j, column=2 ).value) C列=(sheet.cell(row=i, column=3 ).value) D列=(sheet.cell(row=i, column=4 ).value) print (A列,C列,Levenshtein.jaro(A列,C列), B列,C列,Levenshtein.jaro(B列,C列), A列,D列,Levenshtein.jaro(A列,D列), B列,D列,Levenshtein.jaro(B列,D列))

・IDLE上では次のように類似度が表示された。

TANAKA TARO 0.61 SHOICHI TARO 0.46 TANAKA YAMADA 0.66 SHOICHI YAMADA 0.0
★YAMADA TARO 0.47 TARO TARO 1.0 YAMADA YAMADA 1.0 TARO YAMADA 0.47
HIROBUMI TARO 0.58 ITO TARO 0.72 HIROBUMI YAMADA 0.0 ITO YAMADA 0.0
~途中省略
MASAYOSHI TAKASHI 0.68 MATSUKATA TAKASHI 0.58 MASAYOSHI HARA 0.57 MATSUKATA HARA 0.45
★TANAKA TANAKA 1.0 SHOICHI TANAKA 0.0 TANAKA SHOUICHI 0.0 SHOICHI SHOUICHI 0.95
~以下省略

・データ2(C列D列)の氏名を上から順にデータ1の氏名(A列B列)すべてと照合させています。
・切り分けた氏名両方の類似度を算出しています。(「A列とC列」、「B列とC列」、「A列とD列」、「B列とD列」の類似度を算出。)
・「A列とC列」、「B列とC列」のいずれかの類似度が90%以上、かつ、「A列とD列」、「B列とD列」のいずれかの類似度が90%以上となったもの
(上記★印を付けた行の判定結果)を同一人物と判定し、その行だけを、新たなエクセルシートに入力したいと思っています。

イメージとしては、
氏名1  氏名3  類似度1 氏名2  氏名3  類似度2 氏名1   氏名4  類似度3 氏名2  氏名4  類似度4
YAMADA TARO  0.47 TARO TARO 1.0 YAMADA YAMADA 1.0 TARO YAMADA 0.47
TANAKA TANAKA 1.0 SHOICHI TANAKA 0.0 TANAKA SHOUICHI 0.0 SHOICHI SHOUICHI 0.95

長文で非常に分かりにくい説明になってしまいましたが、この類似度をエクセルに入力するためのコード等、お教えいただけましたら幸いです。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

このような感じでしょうか。

python

1import openpyxl 2import Levenshtein 3 4# Excel ファイルを読み込む。 5wb = openpyxl.load_workbook('test.xlsx') 6sheet = wb.active 7 8# データを読み込む。 9data1 = [] 10data2 = [] 11for r in range(1, sheet.max_row + 1): 12 data1.append({'name1': sheet.cell(row=r, column=1).value, 13 'name2': sheet.cell(row=r, column=2).value}) 14 data2.append({'name1': sheet.cell(row=r, column=4).value, 15 'name2': sheet.cell(row=r, column=3).value}) 16print(data1) 17print(data2) 18 19# 一致する行を検索 20matches = [] 21for i, person1 in enumerate(data1): 22 for j, person2 in enumerate(data2): 23 match1 = Levenshtein.jaro(person1['name1'], person2['name1']) 24 match2 = Levenshtein.jaro(person1['name2'], person2['name2']) 25 if match1 > 0.9 and match2 > 0.9: 26 matches.append([i, j]) 27 break 28 29 match1 = Levenshtein.jaro(person1['name1'], person2['name2']) 30 match2 = Levenshtein.jaro(person1['name2'], person2['name1']) 31 if match1 > 0.9 and match2 > 0.9: 32 matches.append([i, j]) 33 break 34 35print(matches) 36 37# 新規ワークシートに一致した情報を書き出し 38out_sheet = wb.create_sheet('matches') 39for row, [i, j] in enumerate(matches, 1): 40 # データベース1の一致した行の情報 41 out_sheet.cell(row=row, column=1).value = i + 1 42 out_sheet.cell(row=row, column=2).value = data1[i]['name1'] 43 out_sheet.cell(row=row, column=3).value = data1[i]['name2'] 44 # データベース2の一致した行の情報 45 out_sheet.cell(row=row, column=4).value = j + 1 46 out_sheet.cell(row=row, column=5).value = data2[j]['name1'] 47 out_sheet.cell(row=row, column=6).value = data2[j]['name2'] 48 49# 保存する。 50wb.save('output.xlsx')

ワークシートに追加された情報

1 TANAKA SHOICHI 3 SHOUICHI TANAKA 2 YAMADA TARO 1 YAMADA TARO

データ1の2行目「YAMADA TARO」とデータ2の1行目「YAMADA TARO」が一致したことを表している。

追記

姓名がどちらかわからないということであれば、次に2パターンを試せば、全パターン試したことになります。
列1 vs 列3 and 列2 vs 列4
列1 vs 列4 and 列2 vs 列3

イメージ説明

丸の中の数字は列数

投稿2018/10/30 08:18

編集2018/10/30 09:36
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

anthony3590

2018/10/30 09:14

ご回答ありがとうございます! 確かにエクセルファイルに出力されました。 ただ、1列目A・B列の「TANAKA SHOICHI」と3列目C・D列の 「TANAKA SHOUICHI」が類似度の条件を満たすものとして、抽出 されていないようなのですが、どうすれば抽出されるのでしょうか。 データ1とデータ2の氏名はそれぞれ2つの列に分けますが、 もともと姓名の順が一定ではないため、分けた2つの列のうちどちらが姓で どちらが名かは一定ではありません。 そのため、データ1とデータ2の氏名から分けた2つの列を、それぞれ たすき掛けをするように類似度を算出したいと考えています。 説明が分かりづらく、すみません。     A列  B列  C列  D列 1列目 TANAKA SHOICHI TARO   YAMADA 2列目 YAMADA TARO TAKASHI HARA 3列目 HIROBUMI ITO TANAKA SHOUICHI 4列目 MASAYOSHI MATSUKATA ODA   NOBUNAGA
tiitoi

2018/10/30 09:35

なるほど、なんで姓と名の順番がバラバラなんだろうと思ったんですが、そういうことだったのですね。 回答を修正しました。
anthony3590

2018/10/30 14:38

ありがとうございました!思ったとおりのことができました。 本当に助かりました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問