为啥在我遍历 pandas DataFrame 后这个函数不“接受”?
Posted
技术标签:
【中文标题】为啥在我遍历 pandas DataFrame 后这个函数不“接受”?【英文标题】:Why doesn't this function "take" after I iterrows over a pandas DataFrame?为什么在我遍历 pandas DataFrame 后这个函数不“接受”? 【发布时间】:2013-04-05 00:49:14 【问题描述】:我有一个带有时间戳的温度和风速值的 DataFrame,以及一个将这些值转换为“风寒”的函数。我正在使用 iterrows 在每一行上运行该函数,并希望得到一个带有漂亮“Wind Chill”列的 DataFrame。
但是,虽然它似乎可以正常工作,并且实际上至少“工作”了一次,但我似乎无法始终如一地复制它。一般来说,我觉得这是我对 DataFrames 结构的遗漏,但我希望有人能提供帮助。
In [28]: bigdf.head()
Out[28]:
Day Temperature Wind Speed Year
2003-03-01 06:00:00-05:00 1 30.27 5.27 2003
2003-03-01 07:00:00-05:00 1 30.21 4.83 2003
2003-03-01 08:00:00-05:00 1 31.81 6.09 2003
2003-03-01 09:00:00-05:00 1 34.04 6.61 2003
2003-03-01 10:00:00-05:00 1 35.31 6.97 2003
所以我在bigdf
中添加了一个“Wind Chill”列,并预填充了NaN
。
In [29]: bigdf['Wind Chill'] = NaN
然后我尝试遍历行,以添加实际的 Wind Chills。
In [30]: for row_index, row in bigdf[:5].iterrows():
...: row['Wind Chill'] = windchill(row['Temperature'], row['Wind Speed'])
...: print row['Wind Chill']
...:
24.7945889994
25.1365267133
25.934114012
28.2194307516
29.5051046953
正如您所说,新值出现将应用于“Wind Chill”列。这是windchill
函数,以防万一:
def windchill(temp, wind):
if temp>50 or wind<=3:
return temp
else:
return 35.74 + 0.6215*temp - 35.75*wind**0.16 + 0.4275*temp*wind**0.16
但是,当我再次查看 DataFrame 时,NaN 仍然存在:
In [31]: bigdf.head()
Out[31]:
Day Temperature Wind Speed Year Wind Chill
2003-03-01 06:00:00-05:00 1 30.27 5.27 2003 NaN
2003-03-01 07:00:00-05:00 1 30.21 4.83 2003 NaN
2003-03-01 08:00:00-05:00 1 31.81 6.09 2003 NaN
2003-03-01 09:00:00-05:00 1 34.04 6.61 2003 NaN
2003-03-01 10:00:00-05:00 1 35.31 6.97 2003 NaN
更奇怪的是它已经工作了一两次,我不知道我做了什么不同。
我必须承认我对 pandas 的内部工作方式不是特别熟悉,并且对索引等感到困惑,所以我觉得我可能在这里遗漏了一些非常基本的东西(或者很难做到这一点)。
谢谢!
【问题讨论】:
【参考方案1】:您可以使用apply
来执行此操作:
In [11]: df.apply(lambda row: windchill(row['Temperature'], row['Wind Speed']),
axis=1)
Out[11]:
2003-03-01 06:00:00-05:00 24.794589
2003-03-01 07:00:00-05:00 25.136527
2003-03-01 08:00:00-05:00 25.934114
2003-03-01 09:00:00-05:00 28.219431
2003-03-01 10:00:00-05:00 29.505105
In [12]: df['Wind Chill'] = df.apply(lambda row: windchill(row['Temperature'], row['Wind Speed']),
axis=1)
In [13]: df
Out[13]:
Day Temperature Wind Speed Year Wind Chill
2003-03-01 06:00:00-05:00 1 30.27 5.27 2003 24.794589
2003-03-01 07:00:00-05:00 1 30.21 4.83 2003 25.136527
2003-03-01 08:00:00-05:00 1 31.81 6.09 2003 25.934114
2003-03-01 09:00:00-05:00 1 34.04 6.61 2003 28.219431
2003-03-01 10:00:00-05:00 1 35.31 6.97 2003 29.505105
.
为了详细说明您感到困惑的原因,我认为这是因为行变量是 copies rather than views 的 df,因此更改不会传播:
In [21]: for _, row in df.iterrows(): row['Day'] = 2
我们看到它正在成功地对副本进行更改,row
变量:
In [22]: row
Out[22]:
Day 2.00
Temperature 35.31
Wind Speed 6.97
Year 2003.00
Name: 2003-03-01 10:00:00-05:00
但他们不会更新到 DataFrame:
In [23]: df
Out[23]:
Day Temperature Wind Speed Year
2003-03-01 06:00:00-05:00 1 30.27 5.27 2003
2003-03-01 07:00:00-05:00 1 30.21 4.83 2003
2003-03-01 08:00:00-05:00 1 31.81 6.09 2003
2003-03-01 09:00:00-05:00 1 34.04 6.61 2003
2003-03-01 10:00:00-05:00 1 35.31 6.97 2003
以下内容也使df
保持不变:
In [24]: row = df.ix[0] # also a copy
In [25]: row['Day'] = 2
如果我们确实采取观点:(我们会看到一个变化df
。)
In [26]: row = df.ix[2:3] # this one's a view
In [27]: row['Day'] = 3
见Returning a view versus a copy (in the docs)。
【讨论】:
我怀疑它与副本与视图有关,但我以相反的方式思考它,真的让自己感到困惑。感谢您的详细回答! 我遇到了类似的问题,使用了类似的解决方案,但奇怪的是:它以某种方式在较旧的安装上工作,但不适用于其他机器上较新版本的 Pandas。这真的让我发疯了。因此,如果其他人开始为类似的问题拉扯头发,我想我会传递这个 @ViennaMike 你是说上面的方法适用于新的或旧的熊猫吗? pandas 的应用中有一些边缘案例在最近几个版本中进行了调整,所以这可能就是其中之一! @AndyHayden,是的,我使用的是旧版本的 Anaconda,我相信它的版本是 11,Pandas 版本,并且正在使用 iterrows,而且我的编码方式运行良好,与通过行引用原始数据框中的更新。但是当我尝试两个更高版本时,这不起作用(显然行引用了副本,而不是原始版本)。在我的代码中使用对原始数据框的直接 .loc 引用来修复它。【参考方案2】:试试看:
bigdf['Wind Chill'] = bigdf.apply(lambda x: windchill(x['Temperature'], x['Wind Speed']), axis=1)
使用您的简单 windchill
函数一次性获取整个 DataFrame。
【讨论】:
【参考方案3】:我会说你不需要任何显式循环。以下希望能做到你想要的
bigdf = pd.DataFrame('Temperature': [30.27, 30.21, 31.81], 'Wind Speed': [5.27, 4.83, 6.09])
def windchill(temp, wind):
"compute the wind chill given two pandas series temp and wind"
tomodify = (temp<=50) & (wind>3) #check which values need to be modified
t = temp.copy() #create a new series
# change only the values that need modification
t[tomodify] = 35.74 + 0.6215*temp[tomodify] - 35.75*wind[tomodify]**0.16 +
0.4275*temp[tomodify]*wind[tomodify]**0.16
return t
bigdf['Wind Chill'] = windchill(bigdf['Temperature'], bigdf['Wind Speed'])
bigdf
Temperature Wind Speed Wind Chill
0 30.27 5.27 24.794589
1 30.21 4.83 25.136527
2 31.81 6.09 25.934114
ps:windchill
的这种实现也适用于 numpy 数组。
【讨论】:
谢谢。我的谷歌搜索显示,重新设计 windchill 是另一种选择,但我真的想弄清楚我做错了什么。 :) 明白了。很好,你找到了解释 我遇到了类似的问题,使用了类似的解决方案,但奇怪的是:它以某种方式在较旧的安装上工作,但不适用于其他机器上较新版本的 Pandas。这真的让我发疯了。因此,如果其他人开始为类似的问题拉扯头发,我想我会传递这个。以上是关于为啥在我遍历 pandas DataFrame 后这个函数不“接受”?的主要内容,如果未能解决你的问题,请参考以下文章
pandas.DataFrame.loc好慢,怎么遍历访问DataFrame比较快
pandas.DataFrame.loc好慢,怎么遍历访问DataFrame比较快