如果满足条件,当要分配的列不独立时,使用来自另一个数据帧的随机样本填充 Pandas 数据帧

Populate Pandas dataframe with random sample from another dataframe if condition is met, when columns to be assigned are not independent

我有两个 DataFrame,df1df2。如果满足特定条件,df1 中的信息必须用于填充 df2 中的单元格。这是一个例子:

df1 = pd.DataFrame({"A":[1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4],"B":[1, 2, 3, 1, 2, 2, 3, 1, 2, 3, 4],"C":[5, 3, 2,10,11,12, 4, 5, 7, 2, 7], "D":[0.5, 0.3, 0.5, 0.7, 0.5, 0.6, 0.1, 0.6, 0.6, 0.5, 0.6]})
df2 = pd.DataFrame({"A":[5, 5, 6, 6, 6], "B":[1, 2, 1, 2, 3], "C":np.nan, "D":np.nan})

df2 中的 np.nan 条目表示需要填充的单元格。这些在流程开始时是空的。

要填充 df2,我需要使用列 df2['B'] 中的值。具体来说,在这个例子中,如果 df2['B'] 的值等于 1,那么我需要从 df1[df1['B']==1] 中为 df1['C']df1['D'].重要的是,这些值不是独立的。因此,我需要从 df1 的行子集中随机抽取一行,其中 df1['B'] 等于 1。然后我需要对 df2.

中的所有行执行此操作

df1['B'] 的值为 1 时,df1[df1['B']==1][['C','D']].sample(replace = True) 为一种情况抽取随机样本,但是

  1. 如何给df2分配相应的值?
  2. 如何为 df2 中的每一行执行此操作?

我已经尝试了几种带循环的替代方案,例如

for index, value in df2.iterrows():
    if df2.loc[index,'B'] == 1:
        temp_df = df1[df1['B'] == 1][['C','D']].sample(n = 1, replace = True)

    if df2.loc[index,'B'] == 2:
        temp_df = df1[df1['B'] == 2][['C','D']].sample(n = 1, replace = True)
        
    if df2.loc[index,'B'] == 3:
        temp_df = df1[df1['B'] == 3][['C','D']].sample(n = 1, replace = True)
        
    if df2.loc[index,'B'] == 4:
        temp_df = df1[df1['B'] == 4][['C','D']].sample(n = 1, replace = True)
        
        
    df2.loc[index, 'C'] = temp_df['C']
    df2.loc[index, 'D'] = temp_df['D']

但我收到一条错误消息说

---> 15     df2.loc[index, 'C'] = temp_df['C']
     16     df2.loc[index, 'D'] = temp_df['D']
...
ValueError: Incompatible indexer with Series

其中 ... 表示我跳过的错误消息中的行。

这是一种方法:

(i) 使用 groupby + size.

df2 获取样本大小

(ii) 使用 groupby + apply,其中我们使用 lambda 函数对 df1 中的项目进行抽样,每个唯一“B”的样本大小是从 (i) 中获得的.

(iii) 将这些采样值分配给 df2(因为“B”不是唯一的,我们按“B”对 df2 进行排序以使行对齐)

cols = ['C','D']
sample_sizes = df2.groupby('B')[cols].size()

df2 = df2.sort_values(by='B')
df2[cols] = (df1[df1['B'].isin(sample_sizes.index)]
             .groupby('B')[cols]
             .apply(lambda g: g.sample(sample_sizes[g.name], replace=True))
             .droplevel(1).reset_index(drop=True))
df2 = df2.sort_index()

一个样本:

   A  B   C    D
0  5  1   5  0.6
1  5  2  10  0.7
2  6  1  12  0.6
3  6  2  11  0.5
4  6  3   4  0.1