2017-06-20 140 views
2

我有一个经常更新(每天2-3次)的excel电子表格。此更新需要运行索引匹配来从另一个电子表格中的表中提取值,并将它们写入第一个表中的列。这些值覆盖旧的值,而不是创建新的列。使用Pandas在Python中复制Excel的IndexMatch

我想使用pandas(和xlwings将数据写入电子表格,但我没有与该部分有关的问题)自动执行此过程。第一步是复制excel的INDEXMATCH()和熊猫。总体而言,功能应:

  • 带参数将被索引的列的串头,要写入的列上,并包含正在使用的值相匹配的列读&写列

  • 迭代写入列;在每次迭代时,如果没有匹配值,则在搜索列中搜索其对应的匹配列值与写入列的匹配列值匹配的值,如果没有匹配值,则将NaN或'#N/A'写入数据帧(重要的0和不匹配)

我希望那里是大熊猫原生VLOOKUP/indexmatch功能,但唯一的东西我能找到的是如何加入或合并dataframes,这ISN”来区分我想要做什么 - 我想覆盖数据框中的各个值,并以任意索引顺序执行此操作。

我已经设法使用一个非常丑陋的特定于脚本的函数来工作,但是我认为尝试将函数泛化为其他用途会很有用。一些清洁和重写后,我有以下几点:

##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将采取一系列作为参数,将它像它将如果供给的字典的索引作为键。

这里应用,看起来像

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 

给予相同的输出到

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 

以匹配的dfRead索引,跳过步骤.set_index(...)。为了匹配的dfWrite指数,与dfWrite.index.to_series().map

+0

太棒了!干净,简单,最重要的是它可以让你匹配一个索引到另一个df的列。完全是我正在寻找的内置解决方案,谢谢。 –

0

更换dfWrite['Match Column'].map可以使用merge功能以及:

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

dfWrite.rename(columns={'Read Column':'Write Column'}, inplace=True)