2017-06-20 10 views
2

私はよく更新するスプレッドシートを持っています(1日2〜3回)。このアップデートでは、インデックスマッチを実行して、別のスプレッドシート内のテーブルから値を取り出し、最初のカラムのカラムに値を書き込む必要があります。値は古いものを上書きし、新しい列を作成しません。PandasのPythonでExcelのIndexMatchを複写する

この手順を自動化して、pandas(およびxlwingsを使用してスプレッドシートにデータを書き込んでいますが、その部分に問題はありません)を使用したいと思います。最初のステップは、excelのINDEXMATCH()にパンダを複製することです。合計では、関数はべきである:

  • 列が上書きされるように、列の列ヘッダーが索引付けされる引数を取り、読み取り&書き込みを一致させるために使用されている値を含む列列

  • 書き込み列を反復します。すべての反復で、対応する一致列値が書き込み列の一致列値と一致する値を読み取り列で検索します。一致する値がない場合は、データ・フレームにNaNまたは '#N/A'を書き込みます私はパンダでネイティブVLOOKUP/indexmatch機能があることが予想されるが、私は見つけることができる唯一のものは「にISNれ、参加またはデータフレームをマージについてだった

0と非マッチ)を区別することが重要私は何をしたいのですか?データフレーム内の個々の値を上書きし、任意のインデックス順に並べ替える必要があります。

私はそれが非常に醜いスクリプト固有の機能で動作するように管理してきましたが、私は他の用途のために関数を一般化しようとすると便利だと決めました。いくつかのクリーニングと書き換えた後、私は以下の持っている:

##Index Match in Python with pandas 
#Remember that dataframes start at 0, excel starts at 1 
#This only works if both DFs have the same indices (integers, strings, whatever) 
import numpy as np 
import pandas as pd 

#sample dataframes 
d = {'Match Column' : [0.,1.,2.,3.,4.,7.,'string'], 
    'Read Column' : ['zero','one','two','three','four','seven','string']} 

dfRead = pd.DataFrame(d) 

d2 = {'Match Column' : [0.,1.,2.,3.,4.,5.,6.,7.,'8'], 
     'Write Column' : [0,0,0,0,0,0,0,0,'0']} 

dfWrite = pd.DataFrame(d2) 

#test arguments 
ReadColumn = 'Read Column' 
WriteColumn = 'Write Column' 
ReadMatchColumn = 'Match Column' 
WriteMatchColumn = 'Match Column' 

def indexmatch(dfRead, dfWrite, ReadColumn, WriteColumn, ReadMatchColumn, WriteMatchColumn, skiprows=0): 
#convert the string inputs to a column number for each dataframe 
    RCNum = np.where(dfRead.columns == ReadColumn)[0][0] 
    WCNum = np.where(dfWrite.columns == WriteColumn)[0][0] 
    RMCNum = np.where(dfRead.columns == ReadMatchColumn)[0][0] 
    WMCNum = np.where(dfWrite.columns == WriteMatchColumn)[0][0] 

    for i in range(skiprows,len(dfWrite.index),1): 
     match = dfWrite.loc[dfWrite.index[i]][WMCNum] #the value we're using to match the columns  
     try: 
      matchind = dfRead.index[np.where(dfRead[ReadMatchColumn] == match)[0][0]] 
      value = dfRead.fillna('#N/A').loc[matchind][RCNum] #replaces DF NaN values with excel's #N/A, optional method 
      dfWrite.set_value(dfWrite.index[i],WriteColumn,value) 
     except KeyError: 
      dfWrite.set_value(dfWrite.index[i],WriteColumn,np.nan) #if there is no match, write NaN to the 'cell' 
     except IndexError: 
      dfWrite.set_value(dfWrite.index[i],WriteColumn,np.nan) 

これは動作しますが、それはかなりではない、とあなたが(別のデータフレームのインデックスに列を一致させたいときには考慮されません。例えば、データフレームとピボットテーブルのデータフレームとのマッチング)。

これを行うためのより堅牢で簡潔な方法はありますか?

要求されたとして、期待される入力と出力:

In [2]: dfRead 
Out[2]: 
    Match Column Read Column 
0   0  zero 
1   1   one 
2   2   two 
3   3  three 
4   4  four 
5   7  seven 
6  string  string 

In [3]: dfWrite 
Out[3]: 
    Match Column Write Column 
0   0   0 
1   1   0 
2   2   0 
3   3   0 
4   4   0 
5   5   0 
6   6   0 
7   7   0 
8   8   0 

In [4]: indexmatch(dfRead, dfWrite, 'Read Column', 'Write Column', 'Match Column', 'Match Column') 
In [5]: dfWrite 
Out[7]: 
    Match Column Write Column 
0   0   zero 
1   1   one 
2   2   two 
3   3  three 
4   4   four 
5   5   NaN 
6   6   NaN 
7   7  seven 
8   8   NaN 
+0

あなたが簡単な、再現性の例として、所望の出力を提供することができますか?あなたがしようとしていることによると、 'pandas'はExcelのように使うつもりはないので、あなたが例を挙げた後に説明できるより良い方法があるかもしれません。 –

+0

確かに、もともとやっていないのは悪いです。 –

答えて

1

pd.Series.mapは、それがあればキーとしてインデックスを持つ辞書を与えますようにそれを処理し、引数としてシリーズがかかります。 .set_index(...)ステップをスキップし、dfReadのインデックスに一致させるために

indexmatch(dfRead, dfWrite, 'Read Column', 'Write Column', 'Match Column', 'Match Column') 

dfWrite 
Out[413]: 
    Match Column Write Column 
0   0   zero 
1   1   one 
2   2   two 
3   3  three 
4   4   four 
5   5   NaN 
6   6   NaN 
7   7  seven 
8   8   NaN 

に同一の出力を与える

dfWrite['Write Column'] = dfWrite['Match Column'].map(dfRead.set_index('Match Column')['Read Column']) 

dfWrite 
Out[409]: 
    Match Column Write Column 
0   0   zero 
1   1   one 
2   2   two 
3   3  three 
4   4   four 
5   5   NaN 
6   6   NaN 
7   7  seven 
8   8   NaN 

のように見えますここで適用

、。dfWriteのインデックスに一致させるために、あなたにもmerge機能を使用することができますdfWrite.index.to_series().map

+0

恐ろしい!きれいで、シンプルで、最も重要なのは、インデックスを別のdfの列に一致させることです。私が探していた組み込みのソリューションの種類とまったく同じです、ありがとう。 –

0

dfWrite['Match Column'].mapを置き換える:

dfWrite = pd.merge(left=dfWrite.ix[:,['Match Column']], right=dfRead, on='Match Column', how='left') 

dfWrite.rename(columns={'Read Column':'Write Column'}, inplace=True) 
関連する問題