簡體   English   中英

加入兩個 Pandas 數據幀,從較小的 dataframe 采樣

[英]Join two Pandas dataframes, sampling from the smaller dataframe

我有兩個數據框,如下所示:

import pandas as pd
import io

train_data="""input_example,user_id
example0.npy, jane
example1.npy, bob
example4.npy, alice
example5.npy, jane
example3.npy, bob
example2.npy, bob
"""

user_data="""user_data,user_id
data_jane0.npy, jane
data_jane1.npy, jane
data_bob0.npy, bob
data_bob1.npy, bob
data_alice0.npy, alice
data_alice1.npy, alice
data_alice2.npy, alice
"""

train_df = pd.read_csv(io.StringIO(train_data), sep=",")
user_df = pd.read_csv(io.StringIO(user_data), sep=",")

假設train_df表有數千個條目,即有 1000 個唯一的“exampleN.npy”文件。 我想知道是否有一種直接的方法來合並train_dfuser_df表,其中連接表的每一行都與鍵user_id匹配,但從user_df進行子采樣。

這是生成的 dataframe 的一個示例(我正在嘗試進行統一采樣,因此理論上,有無限可能的結果數據幀):

>>> result_df
    input_example        user_data   user_id
0    example0.npy   data_jane0.npy      jane
1    example1.npy    data_bob1.npy       bob
2    example4.npy  data_alice0.npy     alice
3    example5.npy   data_jane1.npy      jane
4    example3.npy    data_bob0.npy       bob
5    example2.npy    data_bob0.npy       bob

也就是說, user_data列填充了基於相應user_id的隨機選擇的文件名。

我知道可以使用一些基於多行 for 循環查詢的方法編寫此代碼,但也許有一種更快的方法使用內置 Pandas 函數,例如“sample”、“merge”、“join”或“combine” ”。

您可以在user_df中按組進行采樣,然后將其與train_df一起加入。 例如,

# this samples by fraction so each data is equally likely 
user_df = user_df.groupby("user_id").sample(frac=0.5, replace=True) 

    user_data           user_id
6   data_alice2.npy     alice
4   data_alice0.npy     alice
3   data_bob1.npy       bob
0   data_jane0.npy      jane

或者

# this will sample 2 samples per group
user_df = user_df.groupby("user_id").sample(n=2, replace=True) 

    user_data           user_id
6   data_alice2.npy     alice
4   data_alice0.npy     alice
2   data_bob0.npy       bob
2   data_bob0.npy       bob
0   data_jane0.npy      jane
1   data_jane1.npy      jane

加入

pd.merge(train_df, user_df)

我不知道是否可以在不先合並兩者的情況下與樣本合並。 這不包括多行 for 循環:

merged = train_df.merge(user_df, on="user_id", how="left").\
    groupby("input_example", as_index=False).\
        apply(lambda x: x.sample(1)).\
            reset_index(drop=True)
  1. 將兩者合並在一起,在“user_id”上,只取那些出現在左邊的
  2. 按“input_example”分組,假設這些都是唯一的(其他可以在 train_df 的兩列上分組)
  3. 為這些取一個大小為 1 的樣本
  4. 重置索引

合並后的第二個采樣意味着具有相同 user_id 的行不一定相同(但首先采樣 user_df 會導致 output dataframe 中的所有行都具有相同的 user_id)。

認為我自己想出了一個解決方案,它是單行的,但從概念上講它與@Rawson 建議的相同。 首先,我進行了左合並,這會產生一個包含許多重復項的表。 然后我將所有行打亂以使其具有隨機性。 最后,我刪除了重復項。 如果我添加“sort_index”,結果表將與原始表具有相同的順序。

我可以使用random_state kwarg 來切換使用哪個 user_data 文件。 看這里:

>>> train_df.merge(user_df, on='user_id', how='left').sample(frac=1, random_state=0).drop_duplicates('input_example').sort_index()
   input_example user_id        user_data
1   example0.npy    jane   data_jane1.npy
2   example1.npy     bob    data_bob0.npy
6   example4.npy   alice  data_alice2.npy
8   example5.npy    jane   data_jane1.npy
10  example3.npy     bob    data_bob1.npy
11  example2.npy     bob    data_bob0.npy

>>> train_df.merge(user_df, on='user_id', how='left').sample(frac=1, random_state=1).drop_duplicates('input_example').sort_index()
   input_example user_id        user_data
1   example0.npy    jane   data_jane1.npy
2   example1.npy     bob    data_bob0.npy
4   example4.npy   alice  data_alice0.npy
7   example5.npy    jane   data_jane0.npy
10  example3.npy     bob    data_bob1.npy
12  example2.npy     bob    data_bob1.npy

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM