Python 使用“创建新数据帧”;“VLOOKUP”;在两个数据帧之间
有点类似于Excel的VLOOKUP函数,我想在一个数据帧(Python 使用“创建新数据帧”;“VLOOKUP”;在两个数据帧之间,python,python-3.x,pandas,Python,Python 3.x,Pandas,有点类似于Excel的VLOOKUP函数,我想在一个数据帧(下面的公文包)中使用一个值来查找第二个数据帧(下面的返回值)中的关联值,并用这些返回值填充第三个数据帧(现在我们称之为dataframe3)。我发现了一些基于左合并和映射的帖子,但是我最初的两个数据帧的结构不同,所以这些方法似乎不适合(至少对我来说) 我没有取得多大进展,但以下是我的代码: 代码 import pandas as pd portfolios = pd.read_csv('portstst5_1.csv') return
下面的公文包
)中使用一个值来查找第二个数据帧(下面的返回值
)中的关联值,并用这些返回值填充第三个数据帧(现在我们称之为dataframe3)。我发现了一些基于左合并和映射的帖子,但是我最初的两个数据帧的结构不同,所以这些方法似乎不适合(至少对我来说)
我没有取得多大进展,但以下是我的代码:
代码
import pandas as pd
portfolios = pd.read_csv('portstst5_1.csv')
returns = pd.read_csv('Example_Returns.csv')
total_cols = len(portfolios.columns)
headers = list(portfolios)
concat = returns['PERMNO'].map(str) + returns['FROMDATE'].map(str)
idx = 2
returns.insert(loc=idx, column="concat", value=concat)
for i in range(total_cols):
col_len = portfolios.iloc[:,i].count()
for j in range(col_len):
print(portfolios.iat[j,i].astype('int').astype('str') + headers[i])
数据
如果我首先描述我的数据,这段代码将更有意义:
公文包
是一个具有13列不同长度的数据帧。列标题是YYYYMMDD格式的日期。每个日期标题下都有五位数字代码的标识符。公文包的一段代码如下所示(某些列中的某些元素包含NaN):
中的数据返回
数据最初由三列和799行组成,如下所示(所有元素都填充有值):
所需输出
我想制作第三个数据帧,其结构与公文包
相同。也就是说,它将具有与公文包
相同的列标题日期和每列中相同的行数,但它将包含相应标识符/日期组合的MORET
,而不是标识符。这就是我在上面代码中进行连接的原因-我正在尝试(可能是不必要的)创建唯一的查找值,以便我可以在公文包
和返回
之间进行通信。例如,为了填充dataframe3[0,0]
,我将在返回['concat']
中查找组合[0,0]
和头[0]
(即9304420131231),并在返回['MORET']
中返回关联值(即-0.022304)。我被困在这里,不知道如何使用连接的值来返回所需的数据
非常感谢您的任何想法。在python中执行vlookup的典型方法是使用索引中的左列创建一个序列,然后根据查找值对该序列进行切片。南部的情况有点复杂。我们将使用set_index
方法从returns
生成一个系列,将PERMNO
设置为数据帧的索引,然后按列名切片以将MORET
列作为一个系列隔离
lookupseries = returns.set_index('PERMNO')['MORET']
def lookup(x):
try:
return lookupseries[x]
except:
return np.nan
newdf = portfolios.copy()
for c in newdf.columns:
newdf[c] = newdf[c].apply(lookup)
你想做的比你想做的要简单得多。您可以首先熔化公文包
,将其翻转并将所有日期列收集为单个列中的行,然后将其与返回值
连接,最后旋转以获得所需的结果。这基本上就是@djk47463在一个复合行中所做的,我编辑的答案作为他的逐步细分
让我们创建您的数据帧,以使答案重现
import pandas as pd
import sys
if sys.version_info[0] < 3:
from StringIO import StringIO
else:
from io import StringIO
# Create df
rawText = StringIO("""
PERMNO FROMDATE MORET
0 93044 20131231 -0.022304
1 79702 20131231 0.012283
2 85751 20131231 -0.016453
3 85576 20131231 0.038766
4 93044 20131010 -0.02
5 79702 20131010 0.01
6 85751 20131010 -0.01
7 85576 20131010 0.03
""")
returns = pd.read_csv(rawText, sep = "\s+")
portfolios = pd.DataFrame({'20131010':[93044, 85751],
'20131231':[85576, 79702]})
让我们从melt
ing(即unpivot)portfolions
开始解决方案:
portfolios = portfolios.melt(var_name=['FROMDATE'],value_name='PERMNO')
# portfolios:
FROMDATE PERMNO
0 20131010 93044
1 20131010 85751
2 20131231 85576
3 20131231 79702
final = merged.pivot(index='PERMNO', columns='FROMDATE', values='MORET').reset_index()
# final:
FROMDATE PERMNO 20131010 20131231
0 79702 NaN 0.012283
1 85576 NaN 0.038766
2 85751 -0.01 NaN
3 93044 -0.02 NaN
现在,您希望保持此pm
常量,并在其PERMNO
s和FROMDATE
s匹配时,将合并到其行中:
merged = pm.merge(df, how='left', on=['PERMNO', 'FROMDATE'])
# merged:
FROMDATE PERMNO MORET
0 20131010 93044 -0.020000
1 20131010 85751 -0.010000
2 20131231 85576 0.038766
3 20131231 79702 0.012283
还记得我们一开始就对投资组合进行了melt
ed(unpivoted)吗?我们应该pivot
这个结果,使其成为投资组合的形状
:
portfolios = portfolios.melt(var_name=['FROMDATE'],value_name='PERMNO')
# portfolios:
FROMDATE PERMNO
0 20131010 93044
1 20131010 85751
2 20131231 85576
3 20131231 79702
final = merged.pivot(index='PERMNO', columns='FROMDATE', values='MORET').reset_index()
# final:
FROMDATE PERMNO 20131010 20131231
0 79702 NaN 0.012283
1 85576 NaN 0.038766
2 85751 -0.01 NaN
3 93044 -0.02 NaN
IIUC:
使用的组合,以便我们可以使用中的值按所需列返回
。然后使用将数据重新整形,如下所示
portfolios.columns = portfolios.columns.astype(int)
newdf = portfolios.reset_index().melt(id_vars='index',var_name=['FROMDATE'],value_name='PERMNO').merge(returns,on=['FROMDATE','PERMNO'],how='left').pivot(index='index',columns='FROMDATE',values='MORET')
返回下面的数据框
FROMDATE 20130630 20130731 20130831 20130930 20131031 20131130 20131231
index
0 NaN NaN NaN NaN NaN NaN -0.022304
1 NaN NaN NaN NaN NaN NaN 0.012283
2 NaN NaN NaN NaN NaN NaN -0.016453
排序列
newdf.loc[:,newdf.columns.sort_values(ascending=False)]
谢谢大家,;透视表非常有用。但是,当我进行交叉时,new_df
是一个空数据帧。关于为什么它是空的,我有一个想法:portfolions
中的列标题按降序排列(20131231、20131130等),但是new_df
中的列标题(在交叉点之前)按升序排列。但是,我不知道如何在透视表中反转列顺序。这可能是空数据框的原因吗?不是这样,但可能是其中一个的列名是字符串,而另一个是数字。将与修复公用
一样简单。你能告诉我投资组合栏目和新栏目的结果吗?如果他们是大的,请给我每个5个。很确定这就是原因。你能告诉我这是否能解决问题吗:common=[e代表e在new_df.columns如果str(e)在portfolio.columns]
然后你会再次这样做:new_df=new_df[common]
。是的-这就是原因<代码>公文包.列
包含字符串:索引(['20131231','20131130','20131031','20130930','20130831',和新的_df.列
包含int:Int64Index([20120131、20120229、20120331、20120430、20120531,……代码现在返回具有正确列数的new_df
,但列包含MORET
,每个PERMNO
都包含MORET
,无论PERMNO
在投资组合的相关月份中是否存在返回中的每个PERMNO
在每个FROMDATE
中都有一个MORET
,并不是每个PERMNO
都存在于公文包的每一列中。我明白你的意思。我忽略了最后一步,如果你不立即将返回的,而是首先将portfo融化lios
,然后加入返回
,然后pivot;这基本上就是djk47463所做的。我将编辑我的答案,将整个过程分成小块,作为细分和逐步解释
newdf.loc[:,newdf.columns.sort_values(ascending=False)]