根据唯一列值重复数据帧行n次,并对每行重复创建具有不同值的新列

问题描述 投票:0回答:3

正如标题所指定的那样,我正在尝试获取重复行的数据帧。决定N次重复执行的因素基于原始数据帧中存在的特定列的唯一值的长度。在执行重复过程之后,我想创建一个新列,将原始数据帧的特定列的所有相同唯一值应用于创建的每个新行。

我知道这有点令人困惑,但我不能试图以更好的方式揭露我的怀疑。因此,为了便于您理解我想要的方法,我的数据帧和所需的输出数据帧是一个简单的例子:

 >> Original Dataframe

       Samp     Age     Cs
 1       A      51      msi
 2       B      62      cin
 3       C      55      msi
 4       D      70      ebv
 5       E      56      gs
 ....

如您所见,我的Cs列有4个唯一值(对于不同的数据帧可能并不总是相同)。所以,我的目标是获得具有以下结构的数据帧:

 >> Desired Dataframe

       Samp     Age     Cs
 1       A      51      msi
 1       A      51      cin
 1       A      51      ebv
 1       A      51      gs
 2       B      62      cin
 2       B      62      msi
 2       B      62      gs
 2       B      62      ebv
 3       C      55      msi
 3       C      55      cin
 3       C      55      ebv
 3       C      55      gs
 4       D      70      ebv
 4       D      70      cin
 4       D      70      msi
 4       D      70      gs
 5       E      56      gs
 5       E      56      cin
 5       E      56      msi
 5       E      56      ebv
 ....

正如您所看到的,在我想要的数据框中,所有行都重复了4次(等于唯一Cs列值的数量),例外情况是Cs列(它在不同的行中应用其所有唯一值)。

python pandas dataframe rows repeat
3个回答
1
投票

一种解决方案是将'Cs'转换为Categorical。然后使用GroupBy + first

df['Cs'] = df['Cs'].astype('category')

res = df.groupby(['Samp', 'Cs']).first().reset_index()
res['Age'] = res.groupby('Samp')['Age'].transform('first').astype(int)

结果

   Samp   Cs  Age
0     A  cin   51
1     A  ebv   51
2     A   gs   51
3     A  msi   51
4     B  cin   62
5     B  ebv   62
6     B   gs   62
7     B  msi   62
8     C  cin   55
9     C  ebv   55
10    C   gs   55
11    C  msi   55
12    D  cin   70
13    D  ebv   70
14    D   gs   70
15    D  msi   70
16    E  cin   56
17    E  ebv   56
18    E   gs   56
19    E  msi   56

1
投票

您可以使用pivot函数,然后使用fillna两种方法来计算结果:

df.pivot('Cs', 'Samp', 'Age').fillna(method='ffill').fillna(method='bfill').unstack().to_frame('Age').reset_index()

1
投票

使用numpy.unique创建另一个DataFrame并执行合并,这将生成两个帧的笛卡尔积。

s = pd.Series(np.unique(df.Cs.values)).rename('Cs').to_frame()

pd.merge(
    df.iloc[:, :2].assign(key=0),
    s.assign(key=0),
    on='key'
).drop('key', 1)

   Samp  Age   Cs
0     A   51  cin
1     A   51  ebv
2     A   51   gs
3     A   51  msi
4     B   62  cin
5     B   62  ebv
6     B   62   gs
7     B   62  msi
8     C   55  cin
9     C   55  ebv
10    C   55   gs
11    C   55  msi
12    D   70  cin
13    D   70  ebv
14    D   70   gs
15    D   70  msi
16    E   56  cin
17    E   56  ebv
18    E   56   gs
19    E   56  msi

计时

tmp = pd.DataFrame({
    'Samp': np.arange(10000),
    'Age': np.arange(10000),
    'Cs': np.repeat(df.Cs, 2000)
})

In [90]: %%timeit
    ...: s = pd.Series(np.unique(tmp.Cs.values)).rename('Cs').to_frame()
    ...: pd.merge(
    ...:     tmp.iloc[:, :2].assign(key=0),
    ...:     s.assign(key=0),
    ...:     on='key'
    ...: ).drop('key', 1)
    ...:
10.3 ms ± 92.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [91]: %%timeit
    ...: tmp['Cs'] = tmp['Cs'].astype('category')
    ...:
    ...: res = tmp.groupby(['Samp', 'Cs']).first().reset_index()
    ...: res['Age'] = res.groupby('Samp')['Age'].transform('first').astype(int)
    ...:
    ...:
51.5 ms ± 1.69 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
© www.soinside.com 2019 - 2024. All rights reserved.