Pandas df.itertuples 在打印时重命名数据框列

Posted

技术标签:

【中文标题】Pandas df.itertuples 在打印时重命名数据框列【英文标题】:Pandas df.itertuples renaming dataframe columns when printing 【发布时间】:2017-12-31 14:53:45 【问题描述】:

我知道通常 pandas 的 itertuples() 会返回每个值,包括列名,如下所示:

ab=pd.DataFrame(np.random.random([3,3]),columns=['hi','low','med'])
for i in ab.itertuples():
    print(i)

输出如下:

Pandas(Index=0, hi=0.05421443, low=0.2456833, med=0.491185)
Pandas(Index=1, hi=0.28670429, low=0.5828551, med=0.279305)
Pandas(Index=2, hi=0.53869406, low=0.3427290, med=0.750075)

但是,我不知道为什么它没有按照我对另一组代码的预期显示列,如下所示:

            us qqq equity  us spy equity
date                                    
2017-06-19            0.0            1.0
2017-06-20            0.0           -1.0
2017-06-21            0.0            0.0
2017-06-22            0.0            0.0
2017-06-23            1.0            0.0
2017-06-26            0.0            0.0
2017-06-27           -1.0            0.0
2017-06-28            1.0            0.0
2017-06-29           -1.0            0.0
2017-06-30            0.0            0.0

上面是一个 Pandas Dataframe,以 Timestamp 为索引,float64 为列表中的值,以字符串 ['us qqqEquity','us spyEquity'] 为列的列表。

当我这样做时:

for row in data.itertuples():
    print (row)

将列显示为 _1 和 _2,如下所示:

Pandas(Index=Timestamp('2017-06-19 00:00:00'), _1=0.0, _2=1.0)
Pandas(Index=Timestamp('2017-06-20 00:00:00'), _1=0.0, _2=-1.0)
Pandas(Index=Timestamp('2017-06-21 00:00:00'), _1=0.0, _2=0.0)
Pandas(Index=Timestamp('2017-06-22 00:00:00'), _1=0.0, _2=0.0)
Pandas(Index=Timestamp('2017-06-23 00:00:00'), _1=1.0, _2=0.0)
Pandas(Index=Timestamp('2017-06-26 00:00:00'), _1=0.0, _2=0.0)
Pandas(Index=Timestamp('2017-06-27 00:00:00'), _1=-1.0, _2=0.0)
Pandas(Index=Timestamp('2017-06-28 00:00:00'), _1=1.0, _2=0.0)
Pandas(Index=Timestamp('2017-06-29 00:00:00'), _1=-1.0, _2=0.0)
Pandas(Index=Timestamp('2017-06-30 00:00:00'), _1=0.0, _2=0.0)

有人知道我做错了什么吗?创建原始数据框时是否与某些变量引用问题有关? (另外,作为一个附带问题,我从社区了解到,从 itertuples() 生成的数据类型应该是元组,但似乎(如上所示),返回类型是我从 type 语句中验证的?)

感谢大家的耐心等待,我还在努力掌握 DataFrame 的应用。

【问题讨论】:

data.columns 说什么? @Willem Van Onsem 上面写着Index(['us qqq equity', 'us spy equity'], dtype='object') 【参考方案1】:

这似乎是处理包含空格的列名的问题。如果将列名替换为不带空格的不同列名,它将起作用:

df.columns = ['us_qqq_equity', 'us_spy_equity'] 
# df.columns = df.columns.str.replace(r'\s+', '_')  # Courtesy @MaxU  
for r in df.head().itertuples():
    print(r)

# Pandas(Index='2017-06-19', us_qqq_equity=0.0, us_spy_equity=1.0)
# Pandas(Index='2017-06-20', us_qqq_equity=0.0, us_spy_equity=-1.0)
# ...

带空格的列名不能在命名元组中有效地表示,因此在打印时会自动重命名。

【讨论】:

我们可以使用更灵活的方式来重命名列:df.columns = df.columns.str.replace(r'\s+', '_') @COLDSPEED 这太神奇了。我自己几乎想不通。我的后续问题是这是一个错误还是正常行为?基本上 itertuples() 返回的数据类型是什么?它显示<class 'pandas.core.frame.Pandas'> 但这里的每个人都说元组(或我不熟悉的命名元组)。谁能向我解释一下这种数据是什么类型的数据以及为什么这种类型的数据不占用空间? @user7786493 我不是 100% 它是什么类型,但我几乎可以肯定它是 collections.namedtuple 的味道,这是它们的固有限制。【参考方案2】:

有趣的观察:在DataFrame.iterrows()DataFrame.iteritems()DataFrame.itertuples() 中,只有最后一个重命名了列,包含空格:

In [140]: df = df.head(3)

In [141]: list(df.iterrows())
Out[141]:
[(Timestamp('2017-06-19 00:00:00'), us qqq equity    0.0
  us spy equity    1.0
  Name: 2017-06-19 00:00:00, dtype: float64),
 (Timestamp('2017-06-20 00:00:00'), us qqq equity    0.0
  us spy equity   -1.0
  Name: 2017-06-20 00:00:00, dtype: float64),
 (Timestamp('2017-06-21 00:00:00'), us qqq equity    0.0
  us spy equity    0.0
  Name: 2017-06-21 00:00:00, dtype: float64)]

In [142]: list(df.iteritems())
Out[142]:
[('us qqq equity', date
  2017-06-19    0.0
  2017-06-20    0.0
  2017-06-21    0.0
  Name: us qqq equity, dtype: float64), ('us spy equity', date
  2017-06-19    1.0
  2017-06-20   -1.0
  2017-06-21    0.0
  Name: us spy equity, dtype: float64)]

In [143]: list(df.itertuples())
Out[143]:
[Pandas(Index=Timestamp('2017-06-19 00:00:00'), _1=0.0, _2=1.0),
 Pandas(Index=Timestamp('2017-06-20 00:00:00'), _1=0.0, _2=-1.0),
 Pandas(Index=Timestamp('2017-06-21 00:00:00'), _1=0.0, _2=0.0)]

【讨论】:

同意。感谢@MaxU 指出。我专注于 itertuples() 的原因(如果我错了,请纠正我)是因为如果我们试图迭代数据帧的行,循环时间应该是 3 个选项中最短的。除非有其他更快的选择? @user7786493,不客气。在 Pandas 中处理数据最快的方法是使用 vectorized 方法/函数并避免使用 for loops.apply().applymap() 等。 不错的一个。另外,@user7786493 我同意 Max 的观点。如果你对所有元素应用操作,我建议你使用 apply/transform/map。 同意。我完全了解 df 提供的矢量化函数/方法。但是,矢量化函数/方法并不总是可以实现我的目标,尤其是在生成一组新值时需要多个条件/逻辑时。例如,如果一个新列必须依赖于数据帧的现有列(可在此阶段通过矢量化操作实现)并且还取决于该新列的最后一行的值。 hi hi low low med med 0 0.836905 0.744606 0.413051 1 0.045912 0.442163 0.393753 2 0.806727 0.742776 0.794056 使用此示例,如果我想添加一个新列 ('answer'),该列显示 (每行的低低和 med 之和)> 的布尔值,该怎么办?新列 ('answer') 的行,假设 answer 的第一个值以 0 开头?

以上是关于Pandas df.itertuples 在打印时重命名数据框列的主要内容,如果未能解决你的问题,请参考以下文章

使用 Pandas 时如何打印多达 3,000 行数据框 [重复]

当使用另一个字符串打印时,打印 Pandas Series 垂直对齐

解决pandas中打印DataFrame行列显示不全的问题

Python学习解决pandas中打印DataFrame行列显示不全的问题

Python Pandas to_html 无法打印 utf-8 字符

ipython notebook pandas max 允许的列数