Ern*_*niu 9 python dataframe pandas
我有一个 Pandas DataFrame,如下所示:
df = pd.DataFrame({'col1': [1, 2, 3],
'col2': [4, 5, 6],
'col3': [7, 8, 9]})
df
col1 col2 col3
0 1 4 7
1 2 5 8
2 3 6 9
Run Code Online (Sandbox Code Playgroud)
我想创建一个像这样的 Pandas DataFrame:
df_new
col1 col2 col3
0 1 4 7
1 1 5 8
2 1 6 9
3 2 4 7
4 2 5 8
5 2 6 9
6 3 4 7
7 3 5 8
8 3 6 9
Run Code Online (Sandbox Code Playgroud)
是否有内置或内置 Pandas 方法的组合可以实现此目的?
即使 中存在重复项df
,我也希望输出具有相同的格式。换句话说:
df
col1 col2 col3
0 1 4 7
1 2 5 8
2 2 6 8
df_new
col1 col2 col3
0 1 4 7
1 1 5 8
2 1 6 8
3 2 4 7
4 2 5 8
5 2 6 8
6 2 4 7
7 2 5 8
8 2 6 8
Run Code Online (Sandbox Code Playgroud)
我很想看到一个更加Pythonic或“熊猫独有”的答案,但是这个也很好用!
import pandas as pd
import numpy as np
n=3
df = pd.DataFrame({'col1': [1, 2, 3],
'col2': [4, 5, 6],
'col3': [7, 8, 9]})
# Edited and added this new method.
df2 = pd.DataFrame({df.columns[0]:np.repeat(df['col1'].values, n)})
df2[df.columns[1:]] = df.iloc[:,1:].apply(lambda x: np.tile(x, n))
""" Old method.
for col in df.columns[1:]:
df2[col] = np.tile(df[col].values, n)
"""
print(df2)
Run Code Online (Sandbox Code Playgroud)
我也会merge
按照 @Henry 在评论中的建议选择十字架:
out = df[['col1']].merge(df[['col2', 'col3']], how='cross').reset_index(drop=True)
Run Code Online (Sandbox Code Playgroud)
输出:
col1 col2 col3
0 1 4 7
1 1 5 8
2 1 6 9
3 2 4 7
4 2 5 8
5 2 6 9
6 3 4 7
7 3 5 8
8 3 6 9
Run Code Online (Sandbox Code Playgroud)
不同方法的比较:
请注意,当行重复时,@sammywemmy 的方法表现不同,这会导致不可比较的计时。
您可以连接数据帧的副本,并col1
在每个副本中替换为 中的每个值col1
:
out = df.drop('col1', axis=1)
out = pd.concat([out.assign(col1=c1) for c1 in df['col1']]).reset_index(drop=True)
Run Code Online (Sandbox Code Playgroud)
输出:
col2 col3 col1
0 4 7 1
1 5 8 1
2 6 9 1
3 4 7 2
4 5 8 2
5 6 9 2
6 4 7 3
7 5 8 3
8 6 9 3
Run Code Online (Sandbox Code Playgroud)
如果您愿意,您可以使用以下命令将列重新排序回原始状态
col2 col3 col1
0 4 7 1
1 5 8 1
2 6 9 1
3 4 7 2
4 5 8 2
5 6 9 2
6 4 7 3
7 5 8 3
8 6 9 3
Run Code Online (Sandbox Code Playgroud)
您可以使用np.repeat
和np.tile
来获得预期的输出:
import numpy as np
N = 3
cols_to_repeat = ['col1'] # 1, 1, 1, 2, 2, 2
cols_to_tile = ['col2', 'col3'] # 1, 2, 1, 2, 1, 2
data = np.concatenate([np.tile(df[cols_to_tile].values.T, N).T,
np.repeat(df[cols_to_repeat].values, N, axis=0)], axis=1)
out = pd.DataFrame(data, columns=cols_to_tile + cols_to_repeat)[df.columns]
Run Code Online (Sandbox Code Playgroud)
输出:
>>> out
col1 col2 col3
0 1 4 7
1 1 5 8
2 1 6 9
3 2 4 7
4 2 5 8
5 2 6 9
6 3 4 7
7 3 5 8
8 3 6 9
Run Code Online (Sandbox Code Playgroud)
您可以创建一个通用函数:
def repeat(df: pd.DataFrame, to_repeat: list[str], to_tile: list[str]=None) -> pd.DataFrame:
to_tile = to_tile if to_tile else df.columns.difference(to_repeat).tolist()
assert df.columns.difference(to_repeat + to_tile).empty, "all columns should be repeated or tiled"
data = np.concatenate([np.tile(df[to_tile].values.T, N).T,
np.repeat(df[to_repeat].values, N, axis=0)], axis=1)
return pd.DataFrame(data, columns=to_tile + to_repeat)[df.columns]
repeat(df, ['col1'])
Run Code Online (Sandbox Code Playgroud)
用法:
>>> repeat(df, ['col1'])
col1 col2 col3
0 1 4 7
1 1 5 8
2 1 6 9
3 2 4 7
4 2 5 8
5 2 6 9
6 3 4 7
7 3 5 8
8 3 6 9
Run Code Online (Sandbox Code Playgroud)
另一种可能的解决方案基于itertools.product
:
from itertools import product
pd.DataFrame([[x, y[0], y[1]] for x, y in
product(df['col1'], zip(df['col2'], df['col3']))],
columns=df.columns)
Run Code Online (Sandbox Code Playgroud)
输出:
col1 col2 col3
0 1 4 7
1 1 5 8
2 1 6 9
3 2 4 7
4 2 5 8
5 2 6 9
6 3 4 7
7 3 5 8
8 3 6 9
Run Code Online (Sandbox Code Playgroud)
# pip install pyjanitor
import janitor
import pandas as pd
df.complete('col1', ('col2','col3'))
col1 col2 col3
0 1 4 7
1 1 5 8
2 1 6 9
3 2 4 7
4 2 5 8
5 2 6 9
6 3 4 7
7 3 5 8
8 3 6 9
Run Code Online (Sandbox Code Playgroud)
完整主要是为了暴露丢失的行 - 上面的输出恰好是一个很好的副作用。一个更合适但相当冗长的选项是Expand_grid:
# pip install pyjanitor
import janitor as jn
import pandas as pd
others = {'df1':df.col1, 'df2':df[['col2','col3']]}
jn.expand_grid(others=others).droplevel(axis=1,level=0)
col1 col2 col3
0 1 4 7
1 1 5 8
2 1 6 8
3 2 4 7
4 2 5 8
5 2 6 8
6 2 4 7
7 2 5 8
8 2 6 8
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
449 次 |
最近记录: |