【问题标题】:Right way to reverse a pandas DataFrame?反转熊猫数据框的正确方法?
【发布时间】:2013-12-24 23:54:12
【问题描述】:

这是我的代码:

import pandas as pd

data = pd.DataFrame({'Odd':[1,3,5,6,7,9], 'Even':[0,2,4,6,8,10]})

for i in reversed(data):
    print(data['Odd'], data['Even'])

当我运行此代码时,我收到以下错误:

Traceback (most recent call last):
  File "C:\Python33\lib\site-packages\pandas\core\generic.py", line 665, in _get_item_cache
    return cache[item]
KeyError: 5

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\*****\Documents\******\********\****.py", line 5, in <module>
    for i in reversed(data):
  File "C:\Python33\lib\site-packages\pandas\core\frame.py", line 2003, in __getitem__
    return self._get_item_cache(key)
  File "C:\Python33\lib\site-packages\pandas\core\generic.py", line 667, in _get_item_cache
    values = self._data.get(item)
  File "C:\Python33\lib\site-packages\pandas\core\internals.py", line 1656, in get
    _, block = self._find_block(item)
  File "C:\Python33\lib\site-packages\pandas\core\internals.py", line 1936, in _find_block
    self._check_have(item)
  File "C:\Python33\lib\site-packages\pandas\core\internals.py", line 1943, in _check_have
    raise KeyError('no item named %s' % com.pprint_thing(item))
KeyError: 'no item named 5'

为什么会出现此错误?
我该如何解决这个问题?
反转pandas.DataFrame的正确方法是什么?

【问题讨论】:

  • 您在寻找什么输出? "One" 不是data 中的列,我不知道Two 是变量还是"Two" 的错字,这也不是列。您只是想颠倒列顺序吗?
  • 您的意思是data[["Odd", "Even"]],或者更笼统地说,data[data.columns[::-1]]?
  • 你还没有给出你想要的输出示例。我知道如何解决 reversed(data) 不起作用的事实,但我不知道您为什么要为框架中的每一列打印整个 Odd 和 Even 列,这就是您的如果你使用reversed(list(data)),代码就可以了。
  • 我想从我的dataFrame末尾开始for循环
  • 那么我认为你的问题是this one 的重复,你想要for i, row in data[::-1].iterrows(): print row["Odd"], row["Even"] 之类的东西。请始终在您的问题中举例说明您期望的输出;它让每个人的生活都变得更轻松。

标签: python pandas reverse


【解决方案1】:
data.reindex(index=data.index[::-1])

或者简单地说:

data.iloc[::-1]

如果你想有一个从下到上的for循环,你可以反转你的数据框:

for idx in reversed(data.index):
    print(idx, data.loc[idx, 'Even'], data.loc[idx, 'Odd'])

或

for idx in reversed(data.index):
    print(idx, data.Even[idx], data.Odd[idx])

您收到错误是因为reversed 首先调用data.__len__(),它返回6。然后它尝试在range(6, 0, -1) 中为j 调用data[j - 1],第一个调用将是data[5];但在 pandas 数据框中data[5] 表示第 5 列,并且没有第 5 列,所以它会抛出异常。 (见docs)

【讨论】:

  • 有什么方法就地?相当于假设的data.reindex(index=data.index[::-1], inplace=True)
  • 可以做data = data.reindex(index=data.index[::-1])然后data.reset_index(inplace=True, drop=True),它将被重置到位。
  • df = df[::-1] 是 Python 式且有效的解决方案吗?
  • @tommy.carstensen 是的,应该是最佳答案
  • @tommy.carstensen 是的,它比这个解决方案更重要,而且速度也更快。请参阅基本原理和基准here。
【解决方案2】:

您可以以更简单的方式反转行:

df[::-1]

【讨论】:

  • 我喜欢用pd.Series.reverse = pd.DataFrame.reverse = lambda self: self[::-1] 定义我自己的reverse() 方法,因为它在链接方法时看起来更好,例如df.reverse().iterrows().
  • @BenMares 很棒,但 iterrows() 让它看起来不太好看:-(
  • iterrows() 通常不是必需的。这只是一个例子,如果你想做for row in ... 单独做df.reverse() 就可以得到反向的数据帧。
  • 这个方法叫什么?我想详细了解它的工作原理(当然,除非有人想在这里写!)
【解决方案3】:

反转 pandas DataFrame 的正确方法是什么?

TL;DR:df[::-1]

这是反转 DataFrame 的最佳方法,因为 1) 它是恒定运行时间,即 O(1) 2) 它是单个操作,以及 3) 简洁/可读(假设熟悉 slice notation)。


加长版

我发现 ol' 切片技巧 df[::-1](或等效的 df.loc[::-1]1)是反转 DataFrame 的最简洁和惯用的方法.这反映了 python 列表反转语法lst[::-1] 并且其意图很明确。使用loc 语法,您还可以根据需要对列进行切片,因此更加灵活。

处理索引时需要考虑的几点:

  • “如果我也想反转索引怎么办?”

    • 你已经完成了。 df[::-1] 反转索引和值。
  • “如果我想从结果中删除索引怎么办?”

  • “如果我想保持索引不变(IOW,只反转数据,而不是索引)怎么办?”

    • 这有点不合常规,因为它暗示索引与数据并不真正相关。也许考虑完全删除它?尽管从技术上讲,您所要求的可以使用 df[:] = df[::-1] 来实现,它会创建对 df 的就地更新,或者 df.loc[::-1].set_index(df.index) 会返回一个副本。

1:df.loc[::-1] 和 df.iloc[::-1] 是等价的,因为无论是按位置 (iloc) 还是按标签 (loc) 反转,切片语法都保持不变。


证据就在布丁里

X 轴代表数据集大小。 Y 轴表示反转所用的时间。没有任何方法可以像切片技巧那样缩放,它一直在图表的底部。 Benchmarking code 供参考,使用perfplot 生成的绘图。


对其他解决方案的评论

  • df.reindex(index=df.index[::-1]) 显然是一种流行的解决方案,但乍一看,对于不熟悉的读者来说,这段代码“反转 DataFrame”有多明显?此外,这是反转索引,然后使用该中间结果到 reindex,所以这本质上是一个 两步 操作(当它可能只是一个时)。

  • df.sort_index(ascending=False) 可能适用于您拥有简单范围索引的大多数情况,但这假设您的索引是按升序排序的,因此不能很好地概括。

  • 请不要使用iterrows。我看到一些选项建议反向迭代。无论您的用例如何,都可能有可用的矢量化方法,但如果没有,那么您可以使用更合理的方法,例如列表推导。请参阅 How to iterate over rows in a DataFrame in Pandas 了解有关为什么 iterrows 是反模式的更多详细信息。

【讨论】:

  • 一个警告:切片返回的是 NDFrame 而不是 DataFrame,这会让类型检查器不满意。
  • @knite 我很惊讶一个没有继承另一个,很奇怪!
【解决方案4】:

在反转数据帧后,现有答案都不会重置索引。

为此,请执行以下操作:

 data[::-1].reset_index()

根据@Tim 的评论,这是一个实用程序函数,它还删除了旧的索引列:

def reset_my_index(df):
  res = df[::-1].reset_index(drop=True)
  return(res)

只需将您的数据框传递给函数

【讨论】:

  • 你可能想要drop=True,即:data[::-1].reset_index(drop=True),否则旧索引将作为列添加到DataFrame中。
  • 你为什么要这样做?
  • @endolith 一些库希望数据框被索引。例如,一些时间序列预测库期望索引帧作为输入,以便它可以对时间序列进行建模,同时保持与时间步长(日、月、年等)无关。因此,您可能正在使用数据框,对其进行转换,这会弄乱索引。因此重新索引框架是很常见的。
【解决方案5】:

如果处理排序范围索引,一种方法是:

data = data.sort_index(ascending=False)

这种方法的优点是 (1) 是单行,(2) 不需要实用函数,最重要的是 (3) 实际上不会更改数据框中的任何数据。

警告:这是通过按降序对索引进行排序来实现的,因此对于任何给定的 Dataframe 可能并不总是合适或概括。

【讨论】:

  • 如果您尝试反转数据框(这将反转索引),这将起作用。如果你想通过某个列反转,比如说Odd,你可以做data.sort_values(by=['Odd'])
  • 仅当索引已经按升序排序开始时才有效,因此这不能很好地概括。
【解决方案6】:

这行得通:

    for i,r in data[::-1].iterrows():
        print(r['Odd'], r['Even'])

【讨论】:

  • 这行得通,但与第二个答案相同,加上可怕的iterrows。没必要,拜托!
猜你喜欢
  • 1970-01-01
  • 2018-06-29
  • 2014-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-06
  • 2018-01-07
  • 1970-01-01
相关资源
最近更新 更多