我的熊猫数据框看起来像这样:
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')
但他们都没有工作。
np.repeat
: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
重复df
,3
次的值。
然后我们添加分配
new_df.columns = df.columns
的列。
您还可以在第一行分配列名,如下所示:
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
你可以用
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
:pd.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
.
或者使用
concat
和 sort_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
你也可以使用
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。
版本 5 明显较慢,因为函数
concat
和 sort_index
,因为 concat
二次方复制 DataFrame
s,这需要更长的时间。
最快的版本:版本 3.
这些将重复索引并保留操作演示的列
iloc
版本 1df.iloc[np.arange(len(df)).repeat(3)]
iloc
版本 2df.iloc[np.arange(len(df) * 3) // 3]
使用
concat
:
pd.concat([df]*3).sort_index()
Out[129]:
Person ID ZipCode Gender
0 12345 882 38182 Female
0 12345 882 38182 Female
0 12345 882 38182 Female
1 32917 271 88172 Male
1 32917 271 88172 Male
1 32917 271 88172 Male
2 18273 552 90291 Female
2 18273 552 90291 Female
2 18273 552 90291 Female
我不确定为什么从来没有提出过,但是您可以轻松地使用
df.index.repeat
与.loc
:
new_df = df.loc[df.index.repeat(3)]
输出:
>>> new_df
Person ID ZipCode Gender
0 12345 882 38182 Female
0 12345 882 38182 Female
0 12345 882 38182 Female
1 32917 271 88172 Male
1 32917 271 88172 Male
1 32917 271 88172 Male
2 18273 552 90291 Female
2 18273 552 90291 Female
2 18273 552 90291 Female
您可以试试下面的代码:
df = df.iloc[df.index.repeat(3),:].reset_index()
df.index.repeat(3)
将创建一个列表,其中每个索引值将重复 3 次,df.iloc[df.index.repeat(3),:]
将帮助生成一个数据框,其中的行与此列表完全返回。
你可以这样做。
def do_things(df, n_times):
ndf = df.append(pd.DataFrame({'name' : np.repeat(df.name.values, n_times) }))
ndf = ndf.sort_values(by='name')
ndf = ndf.reset_index(drop=True)
return ndf
if __name__ == '__main__':
df = pd.DataFrame({'name' : ['Peter', 'Quill', 'Jackson']})
n_times = 3
print do_things(df, n_times)
还有解释...
import pandas as pd
import numpy as np
n_times = 3
df = pd.DataFrame({'name' : ['Peter', 'Quill', 'Jackson']})
# name
# 0 Peter
# 1 Quill
# 2 Jackson
# Duplicating data.
df = df.append(pd.DataFrame({'name' : np.repeat(df.name.values, n_times) }))
# name
# 0 Peter
# 1 Quill
# 2 Jackson
# 0 Peter
# 1 Peter
# 2 Peter
# 3 Quill
# 4 Quill
# 5 Quill
# 6 Jackson
# 7 Jackson
# 8 Jackson
# The DataFrame is sorted by 'name' column.
df = df.sort_values(by=['name'])
# name
# 2 Jackson
# 6 Jackson
# 7 Jackson
# 8 Jackson
# 0 Peter
# 0 Peter
# 1 Peter
# 2 Peter
# 1 Quill
# 3 Quill
# 4 Quill
# 5 Quill
# Reseting the index.
# You can play with drop=True and drop=False, as parameter of `reset_index()`
df = df.reset_index()
# index name
# 0 2 Jackson
# 1 6 Jackson
# 2 7 Jackson
# 3 8 Jackson
# 4 0 Peter
# 5 0 Peter
# 6 1 Peter
# 7 2 Peter
# 8 1 Quill
# 9 3 Quill
# 10 4 Quill
# 11 5 Quill
如果你需要为你的重复建立索引(例如对于一个多索引)并且重复的次数基于列中的一个值,你可以这样做:
someDF["RepeatIndex"] = someDF["RepeatBasis"].fillna(value=0).apply(lambda x: list(range(int(x))) if x > 0 else [])
superDF = someDF.explode("RepeatIndex").dropna(subset="RepeatIndex")
这给出了一个 DataFrame,其中每条记录都会重复,但是在“RepeatBasis”列中指示了很多次。 DataFrame 还有一个“RepeatIndex”列,您可以将其与现有索引组合成一个多索引,从而保持索引的唯一性。
如果有人想知道为什么你想做这样的事情,在我的例子中,当我得到频率已经被总结的数据时,无论出于什么原因,我都需要进行单一观察。 (想想对直方图进行逆向工程)
这个问题还没有足够的答案!这里还有一些方法可以做到这一点,但仍然缺少并且允许链接 :)
# SQL-style cross-join
# (one line and counts replicas)
(
data
.join(pd.DataFrame(range(3), columns=["replica"]), how="cross")
.drop(columns="replica") # remove if you want to count replicas
)
# DataFrame.apply + Series.repeat
# (most readable, but potentially slow)
(
data
.apply(lambda x: x.repeat(3))
.reset_index(drop=True)
)
# DataFrame.explode
# (fun to have explosions in your code)
(
data
.assign(replica=lambda df: [[x for x in range(3)]] * len(df))
.explode("replica", ignore_index=True)
.drop(columns="replica") # or keep if you want to know which copy it is
)
(编辑:更重要的是,如果您需要计算副本,则使用
explode
很有用and每行有一个动态副本计数。例如,如果您有每个客户的使用数据,开始和结束日期,您可以使用上面的方法将数据转换为每月每个客户的使用数据。)
当然这里是创建测试数据的片段:
data = pd.DataFrame([
[12345, 882, 38182, "Female"],
[32917, 271, 88172, "Male"],
[18273, 552, 90291, "Female"],
],
columns=["Person", "ID", "ZipCode", "Gender"]
)
使用
pd.concat
:创建三个相同的数据帧并将它们合并在一起,不使用大量代码:
df = pd.concat([df]*3, ignore_index=True)
print(df)
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
注意:
ignore_index=True
使索引重置。
也可以用
np.tile()
df.loc[np.tile(df.index,3)].sort_index().reset_index(drop=True)
输出:
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