2017-06-13 17 views
3

私は「DESCRIPTION」と呼ばれるデータフレーム内のテキスト列を持っているの単語の特定の数の範囲内であれば、文字列のいずれかの単語を交換してください。私は、 "タイル"または "タイル"という言葉が "屋根"という言葉の6語以内にあるすべてのインスタンスを見つけて、単に "タイル/ s"という単語を "rooftiles"に変更する必要があります。私は同じことを "床"と "タイル"( "タイル"を "フロルティール"に変更)する必要があります。これは、特定の言葉が他の言葉と一緒に使用されているときに我々が見ている建物取引を区別するのに役立ちます。その単語が別の単語

s1=pd.Series(["After the storm the roof was damaged and some of the tiles are missing"]) 
s2=pd.Series(["I dropped the saw and it fell on the floor and damaged some of the tiles"]) 
s3=pd.Series(["the roof was leaking and when I checked I saw that some of the tiles were cracked"]) 
df=pd.DataFrame([list(s1), list(s2), list(s3)], columns = ["DESCRIPTION"]) 
df 

私は後の午前ソリューションは、(データフレーム形式で)次のようになります:

1.After the storm the roof was damaged and some of the rooftiles are missing  
2.I dropped the saw and it fell on the floor and damaged some of the floortiles 
3.the roof was leaking and when I checked I saw that some of the tiles were cracked 
データと私の最新の不正確な試みの例があり、私が何を意味するか表示するには

は、ここで私は、「タイル」の単語を置き換えるためにREGEXパターンを使用して一致させることを試みたが、それは私がやろうとしています何をすべきかの方法でもあります...完全に間違っているのですか?私は、Pythonに新しいです...

regex=r"(roof)\b\s+([^\s]+\s+){0,6}\b(.*tiles)" 
replacedString=re.sub(regex, r"(roof)\b\s+([^\s]+\s+){0,6}\b(.*rooftiles)", df['DESCRIPTION']) 

UPDATE:SOLUTIONすべての助けを

ありがとう! Janのコードを使っていくつかの追加/修正を加えて動作させることができました。最終的な作業コード(本当のではなく、たとえば、ファイルやデータを使用して)以下である:

claims_file = pd.read_csv(project_path + claims_filename) # Read input file 
claims_file["LOSS_DESCRIPTION"] = claims_file["LOSS_DESCRIPTION"].fillna('NA') #get rid of encoding errors generated because some text was just 'NA' and it was read in as NaN 
#create the REGEX  
rx = re.compile(r''' 
     (      # outer group 
      \b(floor|roof)  # floor or roof 
      (?:\W+\w+){0,6}\s* # any six "words" 
     ) 
     \b(tiles?)\b   # tile or tiles 
     ''', re.VERBOSE) 

#create the reverse REGEX 
rx2 = re.compile(r''' 
     (      # outer group 
      \b(tiles?)  # tile or tiles 
      (?:\W+\w+){0,6}\s* # any six "words" 
     ) 
     \b(floor|roof)\b   # roof or floor 
     ''', re.VERBOSE) 
#apply it to every row of Loss Description: 
claims_file["LOSS_DESCRIPTION"] = claims_file["LOSS_DESCRIPTION"].apply(lambda x: rx.sub(r'\1\2\3', x)) 

#apply the reverse regex: 
claims_file["LOSS_DESCRIPTION"] = claims_file["LOSS_DESCRIPTION"].apply(lambda x: rx2.sub(r'\3\1\2', x)) 

# Write results into CSV file and check results 
claims_file.to_csv(project_path + output_filename, index = False 
         , encoding = 'utf-8') 
+1

出力として希望のものを投稿できますか? – void

答えて

2

でそれを置き換えることによって、それを削除することができます

(      # outer group 
    \b(floor|roof)  # floor or roof 
    (?:\W+\w+){1,6}\s* # any six "words" 
) 
\b(tiles?)\b   # tile or tiles 

a demo for the regex on regex101.comを参照してください。その後


、次のコードを持つ終わるように、ちょうど撮影し部品を組み合わせて、 rx.sub()で再びそれらを一緒に入れて、 DESCRIPTION列の全ての項目にこれを適用します。

import pandas as pd, re 

s1 = pd.Series(["After the storm the roof was damaged and some of the tiles are missing"]) 
s2 = pd.Series(["I dropped the saw and it fell on the floor and damaged some of the tiles"]) 
s3 = pd.Series(["the roof was leaking and when I checked I saw that some of the tiles were cracked"]) 

df = pd.DataFrame([list(s1), list(s2), list(s3)], columns = ["DESCRIPTION"]) 

rx = re.compile(r''' 
      (      # outer group 
       \b(floor|roof)  # floor or roof 
       (?:\W+\w+){1,6}\s* # any six "words" 
      ) 
      \b(tiles?)\b   # tile or tiles 
      ''', re.VERBOSE) 

# apply it to every row of "DESCRIPTION" 
df["DESCRIPTION"] = df["DESCRIPTION"].apply(lambda x: rx.sub(r'\1\2\3', x)) 
print(df["DESCRIPTION"]) 


に注意してください。この解決策は、 tileまたは tiles の後に roofの後にのみ、 Can you give me the tile for the roof, please?のような文が一致しないことを意味する(ただし、 tileという語は実行中ですが1234の単語は、 roofからです)。

+0

ありがとうJan!これは完全に機能しました!私はREGEXが両方の方法で動作していないということが何であるかを見ています...コードを2回実行するだけでこれを回避する方法が見つかりました...これが最善の方法かどうかはわかりませんが、私は更新として使用した最終コードを掲載しました – KMM

2

私はあなたに迅速かつ汚い不完全な実装を紹介します。あなたは確かにそれをより堅牢かつ有用にすることができます。さんはsがあなたの記述の一つであるとしましょう:単語に

s = "I dropped the saw and it fell on the roof and damaged roof " +\ 
    "and some of the tiles" 

てみましょう最初のブレークこと(トークン化、あなたがしたい場合は、句読点を排除することができます):

​​

を今、関心のトークンを選択してソート彼らはアルファベット順に、しかしsに元の位置を覚えている:

my_tokens = sorted((w.lower(), i) for i,w in enumerate(tokens) 
        if w.lower() in ("roof", "tiles")) 
#[('roof', 6), ('roof', 12), ('tiles', 17)] 

、同じトークンを組み合わせると、トークンが鍵である辞書を作成しますその位置のリストは値です。 tiles位置のリストを

token_dict = {name: [p0 for _, p0 in pos] 
       for name,pos 
       in itertools.groupby(my_tokens, key=lambda a:a[0])} 
#{'roof': [9, 12], 'tiles': [17]} 

ゴー、もしあれば、近くroofがあるかどうか、もしそうであれば、単語に変更:辞書内包表記を使用してください。最後

for i in token_dict['tiles']: 
    for j in token_dict['roof']: 
     if abs(i-j) <= 6: 
      tokens[i] = 'rooftiles' 

を置きます再び一緒に言葉:

' '.join(tokens) 
#'I dropped the saw and it fell on the roof and damaged roof '+\ 
#' and some of the rooftiles' 
+0

ありがとうDYZ!私はこれをテストセット上で動作させましたが、CSVファイルを実行しようとしたときに少し問題がありました...私はJanのソリューションが少し実装しやすくなったことを発見しました – KMM

0

大きな問題はあなたの正規表現のタイルの前に。*です。それで、任意の数のキャラクタがそこに行け、それでも一致するようになります。とにかく空白と非空白の境界にあるので、\ bは不要です。グループ分けも使われていなかったので削除しました。

r "(屋根\ s + [^ \ s] + \ s +){0,6}タイル"はタイルの6個の "単語"(空白ではない文字を空白で区切ったグループ)内の屋根にのみ一致します。それを置き換えるには、一致した文字列の最後の5文字を​​除くすべてを正規表現から取り出し、 "rooftiles"を追加して、一致した文字列を更新された文字列で置き換えます。または、正規表現内の()を使ってタイル以外のすべてをグループ化し、そのグループを自分自身と "屋根"で置き換えることができます。この複雑なものにre.subを使うことはできません。これは、タイルだけでなく、屋根からタイルまでのマッチ全体を置き換えるためです。

1

私は「屋根」と「床」以上のサブストリングにこれを一般化することができますが、これは単純なコードを思わ:これはまた、(「」)fullstopのチェックが含まれていることを

for idx,r in enumerate(df.loc[:,'DESCRIPTION']): 
    if "roof" in r and "tile" in r: 
     fill=r[r.find("roof")+4:] 
     fill = fill[0:fill.replace(' ','_',7).find(' ')] 
     sixWords = fill if fill.find('.') == -1 else '' 
     df.loc[idx,'DESCRIPTION'] = r.replace(sixWords,sixWords.replace("tile", "rooftile")) 
    elif "floor" in r and "tile" in r: 
     fill=r[r.find("floor")+5:] 
     fill = fill[0:fill.replace(' ','_',7).find(' ')] 
     sixWords = fill if fill.find('.') == -1 else '' 
     df.loc[idx,'DESCRIPTION'] = r.replace(sixWords,sixWords.replace("tile", "floortile")) 

注意を。あなたは、あなたがここに正規表現で解決策を使用することができsixWords変数を削除し、fill

+0

あなたの助けをありがとう!しかし、私はこのコードでエラーが発生します:TypeError: 'float'型の引数は反復不可能です – KMM

関連する問題