新浪博客

Pandas 中两个索引不同的 Dataframe 的运算问题

2017-10-03 22:21阅读:

转载

Pandas 最重要的一个功能是,它可以对不同索引的对象进行算术运算。在将对象相加时,结果的索引取索引对的并集。自动的数据对齐在不重叠的索引处引入空值,默认为 NaN。
In [1]:
import pandas as pd
In [2]:
date1 = pd.date_range('2012-3-1', periods=1) data1 = {'A': 1, 'B': 2, 'C': 3} df1 = pd.DataFrame(dat
a=data1, index=date1)
In [3]:
df1
Out[3]:
A B C
2012-03-01 1 2 3

In [4]:
df1 + df1
Out[4]:
A B C
2012-03-01 2 4 6

In [5]:
df1 * df1
Out[5]:
A B C
2012-03-01 1 4 9

In [6]:
df1 - df1
Out[6]:
A B C
2012-03-01 0 0 0

In [7]:
df1 / df1
Out[7]:
A B C
2012-03-01 1 1 1

如果两个对象的索引或者列不同,pandas 会自动进行数据对齐,不对齐的数据会默认用 NaN 填充。
In [8]:
date2 = pd.date_range('2012-4-1', periods=1) data2 = {'A': 4, 'B': 5, 'C': 6} df2 = pd.DataFrame(data=data2, index=date2)
In [9]:
df2
Out[9]:
A B C
2012-04-01 4 5 6

In [10]:
df1 + df2
Out[10]:
A B C
2012-03-01 NaN NaN NaN
2012-04-01 NaN NaN NaN

这可能不是你希望的结果,你只是想将两个 dataframe 合并在一起,那么可以采用 dataframe 对象的 add() 方法来相加,并指定 fill_value 参数:
In [11]:
df1.add(df2, fill_value=0)
Out[11]:
A B C
2012-03-01 1 2 3
2012-04-01 4 5 6

如果你仅仅只是需要拼接两个 dataframe,那么直接使用 append 方法即可
In [12]:
df1.append(df2)
Out[12]:
A B C
2012-03-01 1 2 3
2012-04-01 4 5 6

也许这也不是某些人想要的结果,他们希望两个 dataframe 对应的行相加,即使索引不同。这就违背了 pandas 数据对齐的特性,这也是 dataframe 行索引和列列索引存在的意义。所以 dataframe 原生不支持这样的运算,为什么是这样呢?想想如果让两个索引不同的 dataframe 的对应列相加,那么加完之后新的对象的索引该用谁的呢。当然,如果非要这么做也并不是不可,我们可以用一些迂回的办法:
  • 1、转化成 series 后进行运算:

In [13]:
pd.DataFrame(df1.values + df2.values, columns=df1.columns)
Out[13]:
A B C
0 5 7 9

  • 2、改变其中一个 dataframe 的行索引,使两个 dataframe 的行索引相同:

In [14]:
df2_bak = df2.copy() # 如果不希望改变原对象的索引就做一份拷贝 df2_bak.index = df1.index
In [15]:
df2_bak
Out[15]:
A B C
2012-03-01 4 5 6

In [16]:
df1 + df2_bak
Out[16]:
A B C
2012-03-01 5 7 9

  • 3、用 reset_index() 方法重置列索引, 该方法返回一个新的 dataframe:

In [17]:
df1.reset_index()
Out[17]:
index A B C
0 2012-03-01 1 2 3

In [18]:
df2.reset_index()
Out[18]:
index A B C
0 2012-04-01 4 5 6

直接 reset 时,我们发现原来的 index 默认被作为 dataframe 的一列,这可能不是我们想要的。我们可以给 reset_index() 方法传递一个参数 drop=True
In [19]:
df1.reset_index(drop=True)
Out[19]:
A B C
0 1 2 3

In [20]:
df2.reset_index(drop=True)
Out[20]:
A B C
0 4 5 6

In [21]:
df1.reset_index(drop=True) + df2.reset_index(drop=True)
Out[21]:
A B C
0 5 7 9

如果仅仅是列索引不同,也可以用同样的方法:
In [22]:
data3 = {'D': 7, 'E': 8, 'F': 9} df3 = pd.DataFrame(data=data3, index=date1)
In [23]:
df3
Out[23]:
D E F
2012-03-01 7 8 9

In [24]:
df1 + df3
Out[24]:
A B C D E F
2012-03-01 NaN NaN NaN NaN NaN NaN

In [25]:
pd.DataFrame(df1.values + df2.values, columns=df3.columns)
Out[25]:
D E F
0 5 7 9

那么到底什么是数据对齐,就是两个 dataframe 的相应位置没有一一对应的数据。
In [26]:
data4 = {'D': 7, 'E': 8, 'F': 9, 'G': 10} df4 = pd.DataFrame(data=data4, index=date1)
In [27]:
df4
Out[27]:
D E F G
2012-03-01 7 8 9 10

In [28]:
df3 + df4
Out[28]:
D E F G
2012-03-01 14 16 18 NaN

这里在相加时,df3 实际上是变成了下面的样子(也就是在没有数据的位置默认用 NaN 填充):
In [29]:
df3 = pd.DataFrame(data=data3, index=date1, columns=list('DEFG'))
In [30]:
df3
Out[30]:
D E F G
2012-03-01 7 8 9 NaN

In [31]:
df3
Out[31]:
D E F G
2012-03-01 7 8 9 NaN

之所两个 df3 + df4 的 ‘G’ 所以对应的值为 NaN, 是因为任何数与 NaN 做运算都等于 NaN。
In [32]:
1 + np.nan
Out[32]:
nan
可以用 fillna 方法来重置填充值:
In [33]:
df3.fillna(0)
Out[33]:
D E F G
2012-03-01 7 8 9 0

In [34]:
df3.fillna(0) + df4
Out[34]:
D E F G
2012-03-01 14 16 18 10

In [35]:
df1
Out[35]:
A B C
2012-03-01 1 2 3

In [36]:
df1.reset_index(drop=True)
Out[36]:
A B C
0 1 2 3

In [37]:
df1
Out[37]:
A B C
2012-03-01 1 2 3

我的更多文章

下载客户端阅读体验更佳

APP专享