【问题标题】:Why use to_frame before reset_index?为什么在 reset_index 之前使用 to_frame?
【发布时间】:2019-11-17 02:08:35
【问题描述】:

使用这样的数据集

df = pd.DataFrame(np.random.randint(0,5,size=(20, 3)), columns=['user_id','module_id','week'])

我们经常看到这种模式:

df.groupby(['user_id'])['module_id'].count().to_frame().reset_index().rename({'module_id':'count'}, axis='columns')

但是我们从

得到完全相同的结果
df.groupby(['user_id'])['module_id'].count().reset_index(name='count')

(注意,我们需要在前者中添加额外的rename,因为Series (here) 上的reset_index 包含name 参数并返回一个数据帧,而DataFrame (here) 上的reset_index 包含不包括name 参数。)

先用to_frame有什么好处吗?

(我想知道它是否可能是熊猫早期版本的人工制品,但这看起来不太可能:

  • Series.reset_index 于 2012 年 1 月 27 日添加到 this commit
  • Series.to_frame 于 2013 年 10 月 13 日添加到 this commit

所以Series.reset_indexSeries.to_frame 之前一年多可用。)

【问题讨论】:

  • 我总是采用第二种方法。以前从未见过第一个模式...您要使用 to_frame() 的唯一原因是在获取数据帧时保持 seires 索引。在reset_index之前使用没有意义
  • 我认为不需要第一种方法。 .to_frame() 通常用于将系列转换为数据帧,这里 reset_index() 已经为您完成了。但是我更喜欢 groupby().size() 而不是计数(它更快的 IMO)

标签: pandas


【解决方案1】:

使用to_frame() 没有明显优势。这两种方法都可以用来实现相同的结果。在 pandas 中,使用多种方法来解决问题是很常见的。我能想到的唯一优点是,对于较大的数据集,在重置索引之前先有一个数据框视图可能更方便。如果我们以您的数据框为例,您会发现to_frame() 显示了一个数据框视图,该视图可能有助于以整洁的数据框表和count 系列的形式理解数据。此外,to_frame() 的使用使第一次查看您的代码的新用户更清楚其意图。

示例数据框:

In [7]: df = pd.DataFrame(np.random.randint(0,5,size=(20, 3)), columns=['user_i
   ...: d','module_id','week'])

In [8]: df.head()
Out[8]:
   user_id  module_id  week
0        3          4     4
1        1          3     4
2        1          2     2
3        1          3     4
4        1          2     2

count() 函数返回一个系列:

In [18]: test1 = df.groupby(['user_id'])['module_id'].count()

In [19]: type(test1)
Out[19]: pandas.core.series.Series

In [20]: test1
Out[20]:
user_id
0    2
1    7
2    4
3    6
4    1
Name: module_id, dtype: int64

In [21]: test1.index
Out[21]: Int64Index([0, 1, 2, 3, 4], dtype='int64', name='user_id')

使用to_frame 明确表明您打算将系列转换为数据框。这里的索引是user_id

In [22]: test1.to_frame()
Out[22]:
         module_id
user_id
0                2
1                7
2                4
3                6
4                1

现在我们使用 Dataframe.rename 重置索引并重命名列。正如您正确指出的那样,Dataframe.reset_index() 没有 name 参数,因此,我们必须明确地重命名该列。

In [24]: testdf1 = test1.to_frame().reset_index().rename({'module_id':'count'}, axis='columns')

In [25]: testdf1
Out[25]:
   user_id  count
0        0      2
1        1      7
2        2      4
3        3      6
4        4      1

现在让我们看看另一种情况。我们将使用相同的count() 系列test1,但将其重命名为test2 以区分这两种方法。换句话说,test1 等于 test2

In [26]: test2 = df.groupby(['user_id'])['module_id'].count()

In [27]: test2
Out[27]:
user_id
0    2
1    7
2    4
3    6
4    1
Name: module_id, dtype: int64

In [28]: test2.reset_index()
Out[28]:
   user_id  module_id
0        0          2
1        1          7
2        2          4
3        3          6
4        4          1

In [30]: testdf2 = test2.reset_index(name='count')

In [31]: testdf1 == testdf2
Out[31]:
   user_id  count
0     True   True
1     True   True
2     True   True
3     True   True
4     True   True

如您所见,两个数据帧是等效的,在第二种方法中,我们只需要使用 reset_index(name='count') 来重置索引和重命名列名,因为 Series.reset_index() 确实有一个 name 参数。

第二种情况的代码较少,但对新人来说可读性较差,我更喜欢使用to_frame() 的第一种方法,因为它使意图明确:“将此计数系列转换为数据框并将列重命名为'module_id '到'计数'”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 2020-05-04
    • 1970-01-01
    • 2011-03-20
    • 2018-10-19
    • 1970-01-01
    相关资源
    最近更新 更多