2017-04-22 3 views
0

2つのデータフレームAとBがあります。Aは500行で小さく、Bは20000行で大きくなります。 Aの列は以下のとおりです。1つのデータフレームの行から別のデータフレームの行への複数の文字列の一致

A.columns = ['name','company','model','family'] 

とBの列は以下のとおりです。Bで

B.columns = ["title", "price"] 

タイトル欄には、大規模な汚い文字列ですが、それはつまり、会社、モデルや家族に3列から文字列を含んでいます(Aの名前自体が会社、モデル、家族の組み合わせなので、「名前」の列は忘れてください)。私はこのBの一つの行にから各行を一致させる必要が は私のソリューションです:

out=pd.DataFrame(columns={0,1,2,3,4,5}) 
out.columns=["name", 'company', 'model', 'family', 'title', 'price'] 

for index, row in A.iterrows(): 
    lst=[A.loc[index,'family'], A.loc[index,'model'], A.loc[index,'company']] 
    for i, r in B.iterrows(): 
     if all(w in B.loc[i,'title'] for w in lst):   
      out.loc[index,'name']=A.loc[index,'name'] 
      out.loc[index,'company']=A.loc[index,'company'] 
      out.loc[index,'model']=A.loc[index,'model'] 
      out.loc[index,'family']=A.loc[index,'family'] 

      out.loc[index,'title']=B.loc[i,'title'] 
      out.loc[index,'price']=B.loc[i,'price'] 
      break 

これは非常に非効率的に仕事をしていませんし、長い時間を要します。私はこれが「レコードリンケージ」の問題であり、人々はその正確さとスピードを研究していますが、パンダでこれを行うためのより効率的な方法がありますか?タイトルの最初から1つまたは2つの項目だけをチェックした場合、それは速くなりますが、私の懸念は正確さを低下させることです...

私はむしろ間違ったマッチ。

title   object 
price   object 
dtype: object 

私は任意のコメントに感謝:

はまた、A.dtypesとB.dtypesは、両方のデータフレームの列がオブジェクトであることを示しています。

*********** おかげ

********* UPDATE二つのファイルの一部がで見つけることができます:私は A B

import pandas as pd 
import numpy as np 
from scipy import stats 
import matplotlib.colors as mcol 
import matplotlib.cm as cm 
import matplotlib.pyplot as plt 
import math 

A = pd.read_csv('A.txt', delimiter=',', header=None) 
A.columns = ['product name','manufacturer','model','family','announced date'] 

for index, row in A.iterrows():  
    A.loc[index, "product name"] = A.loc[index, "product name"].split('"')[3] 
    A.loc[index, "manufacturer"] = A.loc[index, "manufacturer"].split('"')[1] 
    A.loc[index, "model"] = A.loc[index, "model"].split('"')[1] 
    if 'family' in A.loc[index, "family"]: 
     A.loc[index, "family"] = A.loc[index, "family"].split('"')[1] 
    if 'announced' in A.loc[index, "family"]: 
     A.loc[index, "announced date"] = A.loc[index, "family"] 
     A.loc[index, "family"] = '' 
    A.loc[index, "announced date"] = A.loc[index, "announced date"].split('"')[1] 

A.columns=['product name','manufacturer','model','family','announced date'] 
A.reset_index() 

B = pd.read_csv('B.txt', error_bad_lines=False, warn_bad_lines=False, header=None) 

B.columns = ["title", "manufacturer", "currency", "price"] 
pd.options.display.max_colwidth=200 

for index, row in B.iterrows(): 
    B.loc[index,'manufacturer']=B.loc[index,'manufacturer'].split('"')[1] 
    B.loc[index,'currency']=B.loc[index,'currency'].split('"')[1] 
    B.loc[index,'price']=B.loc[index,'price'].split('"')[1] 
    B.loc[index,'title']=B.loc[index,'title'].split('"')[3] 

、その後の答えで提案されているようにアンドリューのアプローチ:

として、それらの上にいくつかのクリーニングを行います

などと言ったように、私は理解できない複雑な問題が発生しています。あなたの助け

答えて

1

のための多くのおかげでここで動作するようにいくつかのサンプルデータです:

import numpy as np 
import pandas as pd 

# make A df 
manufacturer = ['A','B','C'] 
model = ['foo','bar','baz'] 
family = ['X','Y','Z'] 
name = ['{}_{}_{}'.format(manufacturer[i],model[i],family[i]) for i in range(len(company))] 
A = pd.DataFrame({'name':name,'manufacturer': manufacturer,'model':model,'family':family}) 

# A 
    manufacturer family model  name 
    0  A  X foo A_foo_X 
    1  B  Y bar B_bar_Y 
    2  C  Z baz C_baz_Z 

# make B df 
title = ['blahblahblah'] 
title.extend(['{}_{}'.format(n, 'blahblahblah') for n in name]) 
B = pd.DataFrame({'title':title,'price':np.random.randint(1,100,4)}) 

# B 
    price     title 
0  62   blahblahblah 
1  7 A_foo_X_blahblahblah 
2  92 B_bar_Y_blahblahblah 
3  24 C_baz_Z_blahblahblah 

私たちはあなたの一致基準に基づいて、ABに行インデックスに一致する機能を作り、そして新しいに保存することができますコラム:

def match_strs(row): 
    match_result = (np.where(B.title.str.contains(row['manufacturer']) & \ 
          B.title.str.contains(row['family']) & \ 
          B.title.str.contains(row['model']))) 
    if not len(match_result[0]): 
     return None 
    return match_result[0][0] 

A['merge_idx'] = A.apply(match_strs, axis='columns') 

次にマージAB

(A.merge(B, left_on='merge_idx', right_on='index', right_index=True, how='right') 
    .drop('merge_idx', 1) 
    .dropna()) 

出力:

manufacturer family model  name price     title 
    0  A  X foo A_foo_X  23 A_foo_X_blahblahblah 
    1  B  Y bar B_bar_Y  14 B_bar_Y_blahblahblah 
    2  C  Z baz C_baz_Z  19 C_baz_Z_blahblahblah 

あなたが探しているものということですか?

Bで行を維持したい場合は、Aで一致しない場合でも、mergeの末尾にある.dropna()を削除してください。

+0

ありがとうございます。 IndexError:( 'インデックス0は0番の軸で範囲外です'、 'インデックス0で発生しました') もし私がそうしていれば、私は[0] [0]使用しない[0] [0]、私のmerge_idxは次のようになります。 merge_idx ([]) ([]) ([]) ([]) ([6327、6328、6343 、7106]) ([497、3195、3196、3197、8966、11324]、) ([]) ([]) ...というように。私はいくつかのエントリのために複数の試合があったことを意味すると思いますか? そして、私はあなたのマージメソッドを試してみると、私は得ます: TypeError:unhashableタイプ: 'numpy.ndarray' – user3709260

+1

コードは私が提供したサンプルデータで動作することを確認できますか?それがうまくいくならば、作成したサンプルデータとは異なる、あなたの実際のデータに関するものがあります。実際のデータを使用して投稿を更新したり、実際のユースケースに類似したデータを生成するコードを使用して、自分の投稿を更新することができれば助かります。 –

+0

コードはサンプルデータで正常に動作します。確かに。アップデートと私の完全なコードを見てください。アップロードする場所がわからないため、リモートサーバーにあります。私は本当にあなたの助けに感謝します。 – user3709260

関連する問題