如何复制 Pandas DataFrame 的行?

新手上路,请多包涵

我的熊猫数据框如下所示:

    Person  ID   ZipCode   Gender
0  12345   882  38182     Female
1  32917   271  88172     Male
2  18273   552  90291     Female

我想复制每一行 3 次重置索引得到:

    Person  ID   ZipCode   Gender
0  12345   882  38182     Female
1  12345   882  38182     Female
2  12345   882  38182     Female
3  32917   271  88172     Male
4  32917   271  88172     Male
5  32917   271  88172     Male
6  18273   552  90291     Female
7  18273   552  90291     Female
8  18273   552  90291     Female

我尝试了以下解决方案:

 pd.concat([df[:5]]*3, ignore_index=True)

和:

 df.reindex(np.repeat(df.index.values, df['ID']), method='ffill')

但他们都没有工作。

原文由 DasVisual 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.5k
2 个回答

解决方案:

使用 np.repeat

版本 1:

尝试使用 np.repeat

 newdf = pd.DataFrame(np.repeat(df.values, 3, axis=0))
newdf.columns = df.columns
print(newdf)

上面的代码会输出:

   Person   ID ZipCode  Gender
0  12345  882   38182  Female
1  12345  882   38182  Female
2  12345  882   38182  Female
3  32917  271   88172    Male
4  32917  271   88172    Male
5  32917  271   88172    Male
6  18273  552   90291  Female
7  18273  552   90291  Female
8  18273  552   90291  Female

np.repeat 重复值 df3 次。

然后我们通过分配 new_df.columns = df.columns 添加列。

版本 2:

您还可以在第一行分配列名,如下所示:

 newdf = pd.DataFrame(np.repeat(df.values, 3, axis=0), columns=df.columns)
print(newdf)

上面的代码也会输出:

   Person   ID ZipCode  Gender
0  12345  882   38182  Female
1  12345  882   38182  Female
2  12345  882   38182  Female
3  32917  271   88172    Male
4  32917  271   88172    Male
5  32917  271   88172    Male
6  18273  552   90291  Female
7  18273  552   90291  Female
8  18273  552   90291  Female

版本 3:

您可以使用 loc 缩短它,并且只重复索引,如下所示:

 newdf = df.loc[np.repeat(df.index, 3)].reset_index(drop=True)
print(newdf)

上面的代码也会输出:

   Person   ID ZipCode  Gender
0  12345  882   38182  Female
1  12345  882   38182  Female
2  12345  882   38182  Female
3  32917  271   88172    Male
4  32917  271   88172    Male
5  32917  271   88172    Male
6  18273  552   90291  Female
7  18273  552   90291  Female
8  18273  552   90291  Female

我使用 reset_index 将索引替换为单调索引 ( 0, 1, 2, 3, 4... )。

没有 np.repeat

版本 4:

您可以使用内置的 pd.DataFrame.index.repeat 函数,如下所示:

 newdf = df.loc[df.index.repeat(3)].reset_index(drop=True)
print(newdf)

上面的代码也会输出:

   Person   ID ZipCode  Gender
0  12345  882   38182  Female
1  12345  882   38182  Female
2  12345  882   38182  Female
3  32917  271   88172    Male
4  32917  271   88172    Male
5  32917  271   88172    Male
6  18273  552   90291  Female
7  18273  552   90291  Female
8  18273  552   90291  Female

记得添加 reset_index 来排列 index

版本 5:

或者通过使用 concatsort_index ,如下所示:

 newdf = pd.concat([df] * 3).sort_index().reset_index(drop=True)
print(newdf)

上面的代码也会输出:

   Person   ID ZipCode  Gender
0  12345  882   38182  Female
1  12345  882   38182  Female
2  12345  882   38182  Female
3  32917  271   88172    Male
4  32917  271   88172    Male
5  32917  271   88172    Male
6  18273  552   90291  Female
7  18273  552   90291  Female
8  18273  552   90291  Female

版本 6:

您还可以将 loc 与 Python list 乘法和 sorted 一起使用,如下所示:

 newdf = df.loc[sorted([*df.index] * 3)].reset_index(drop=True)
print(newdf)

上面的代码也会输出:

   Person   ID ZipCode  Gender
0  12345  882   38182  Female
1  12345  882   38182  Female
2  12345  882   38182  Female
3  32917  271   88172    Male
4  32917  271   88172    Male
5  32917  271   88172    Male
6  18273  552   90291  Female
7  18273  552   90291  Female
8  18273  552   90291  Female

计时:

用以下代码计时:

 import timeit
import pandas as pd
import numpy as np

df = pd.DataFrame({'Person': {0: 12345, 1: 32917, 2: 18273}, 'ID': {0: 882, 1: 271, 2: 552}, 'ZipCode': {0: 38182, 1: 88172, 2: 90291}, 'Gender': {0: 'Female', 1: 'Male', 2: 'Female'}})

def version1():
    newdf = pd.DataFrame(np.repeat(df.values, 3, axis=0))
    newdf.columns = df.columns

def version2():
    newdf = pd.DataFrame(np.repeat(df.values, 3, axis=0), columns=df.columns)


def version3():
    newdf = df.loc[np.repeat(df.index, 3)].reset_index(drop=True)


def version4():
    newdf = df.loc[df.index.repeat(3)].reset_index(drop=True)


def version5():
    newdf = pd.concat([df] * 3).sort_index().reset_index(drop=True)


def version6():
    newdf = df.loc[sorted([*df.index] * 3)].reset_index(drop=True)

print('Version 1 Speed:', timeit.timeit('version1()', 'from __main__ import version1', number=20000))
print('Version 2 Speed:', timeit.timeit('version2()', 'from __main__ import version2', number=20000))
print('Version 3 Speed:', timeit.timeit('version3()', 'from __main__ import version3', number=20000))
print('Version 4 Speed:', timeit.timeit('version4()', 'from __main__ import version4', number=20000))
print('Version 5 Speed:', timeit.timeit('version5()', 'from __main__ import version5', number=20000))
print('Version 6 Speed:', timeit.timeit('version6()', 'from __main__ import version6', number=20000))

输出:

 Version 1 Speed: 9.879425965991686
Version 2 Speed: 7.752138633004506
Version 3 Speed: 7.078321029010112
Version 4 Speed: 8.01169377300539
Version 5 Speed: 19.853051771002356
Version 6 Speed: 9.801617017001263

我们可以看到版本 2 和版本 3 比其他版本快,这是因为它们都使用 np.repeat 函数,而 numpy 函数非常快,因为它们是用C。

由于使用 loc 而不是 DataFrame ,版本 3 略胜于版本 2。

Version 5 is significantly slower because of the functions concat and sort_index , since concat copies DataFrame s quadratically, which takes longer time.

最快的版本:版本 3。

原文由 U13-Forward 发布,翻译遵循 CC BY-SA 4.0 许可协议

这些将重复索引并保留列,如操作所示

iloc 版本1

 df.iloc[np.arange(len(df)).repeat(3)]


iloc 版本 2

 df.iloc[np.arange(len(df) * 3) // 3]

原文由 piRSquared 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题