【问题标题】:How do I create test and train samples from one dataframe with pandas?如何使用 pandas 从一个数据帧创建测试和训练样本?
【发布时间】:2014-07-31 14:05:26
【问题描述】:

我有一个相当大的数据框形式的数据集,我想知道如何将数据框分成两个随机样本(80% 和 20%)用于训练和测试。

谢谢!

【问题讨论】:

    标签: python python-2.7 pandas dataframe


    【解决方案1】:

    我会使用 K 折交叉验证。 事实证明,它比train_test_split 提供了更好的结果,这是一篇关于如何从文档本身中将其与 sklearn 一起应用的文章:https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.KFold.html

    【讨论】:

      【解决方案2】:

      如果您想将其拆分为训练、测试和验证集,您可以使用此功能:

      from sklearn.model_selection import train_test_split
      import pandas as pd
      
      def train_test_val_split(df, test_size=0.15, val_size=0.45):
          temp, test = train_test_split(df, test_size=test_size)
          total_items_count = len(df.index)
          val_length = total_items_count * val_size
          new_val_propotion = val_length / len(temp.index) 
          train, val = train_test_split(temp, test_size=new_val_propotion)
          return train, test, val
      

      【讨论】:

        【解决方案3】:

        scikit learn's train_test_split 是一个不错的选择 - 它将两个 numpy 数组拆分为数据帧。

        from sklearn.model_selection import train_test_split
        
        train, test = train_test_split(df, test_size=0.2)
        

        【讨论】:

        • 这将返回 numpy 数组而不是 Pandas 数据帧
        • 顺便说一句,它现在确实返回了一个 Pandas 数据框(刚刚在 Sklearn 0.16.1 上测试过)
        • 在新版本(0.18,可能更早)中,改为导入为from sklearn.model_selection import train_test_split。
        • 在最新的 SciKit 版本中,您现在需要将其称为:from sklearn.cross_validation import train_test_split
        • @horseshoe cv 模块已弃用:DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20. "This module will be removed in 0.20.", DeprecationWarning)
        【解决方案4】:

        无需转换为 numpy。只需使用 pandas df 进行拆分,它将返回一个 pandas df。

        from sklearn.model_selection import train_test_split
        
        train, test = train_test_split(df, test_size=0.2)
        

        如果你想把 x 和 y 分开

        X_train, X_test, y_train, y_test = train_test_split(df[list_of_x_cols], df[y_col],test_size=0.2)
        
        

        如果你想分割整个df

        X, y = df[list_of_x_cols], df[y_col]
        

        【讨论】:

          【解决方案5】:

          就我而言,我想在 Train、test 和 dev 中使用特定数字拆分数据框。我在这里分享我的解决方案

          首先,为数据框分配一个唯一的 id(如果不存在)

          import uuid
          df['id'] = [uuid.uuid4() for i in range(len(df))]
          

          这是我的拆分号码:

          train = 120765
          test  = 4134
          dev   = 2816
          

          分割函数

          def df_split(df, n):
              
              first  = df.sample(n)
              second = df[~df.id.isin(list(first['id']))]
              first.reset_index(drop=True, inplace = True)
              second.reset_index(drop=True, inplace = True)
              return first, second
          

          现在拆分为训练、测试、开发

          train, test = df_split(df, 120765)
          test, dev   = df_split(test, 4134)
          

          【讨论】:

          • 如果您使用数据集和数据加载器,重置索引很重要,否则这是一个很好的约定。这是谈论重新索引的唯一答案。
          【解决方案6】:
          shuffle = np.random.permutation(len(df))
          test_size = int(len(df) * 0.2)
          test_aux = shuffle[:test_size]
          train_aux = shuffle[test_size:]
          TRAIN_DF =df.iloc[train_aux]
          TEST_DF = df.iloc[test_aux]
          

          【讨论】:

          • 如果您解释了您提供的代码如何回答问题,这将是一个更好的答案。
          • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
          • 第一行返回一个打乱的范围(相对于数据帧的大小)。第二行表示测试集的所需分数。第三和第四行将分数合并到打乱的范围中.其余的行应该是不言自明的。问候。
          • 将此解释添加到答案本身将是最佳的:)
          【解决方案7】:

          我会使用 scikit-learn 自己的 training_test_split,并从索引生成它

          from sklearn.model_selection import train_test_split
          
          
          y = df.pop('output')
          X = df
          
          X_train,X_test,y_train,y_test = train_test_split(X.index,y,test_size=0.2)
          X.iloc[X_train] # return dataframe train
          

          【讨论】:

          • cross_validation 模块现已弃用:DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
          • 当我使用 df 其 output 列是字符串时会出错。我得到TypeError: '<' not supported between instances of 'str' and 'float'。看来y 需要是DataFrame 而不是Series。实际上,在 train_test_split 中附加 .to_frame() 的定义或 y 的参数 y 是有效的。如果您使用的是stratify = y,则需要确保此y 也是DataFrame。如果我改为定义y = df[["output"]] 和X = df.drop("output", axis = 1),那么它也可以;这与将.to_frame() 附加到y 的定义中基本相同。
          【解决方案8】:

          您需要将 pandas 数据帧转换为 numpy 数组,然后将 numpy 数组转换回数据帧

           import pandas as pd
          df=pd.read_csv('/content/drive/My Drive/snippet.csv', sep='\t')
          from sklearn.model_selection import train_test_split
          
          train, test = train_test_split(df, test_size=0.2)
          train1=pd.DataFrame(train)
          test1=pd.DataFrame(test)
          train1.to_csv('/content/drive/My Drive/train.csv',sep="\t",header=None, encoding='utf-8', index = False)
          test1.to_csv('/content/drive/My Drive/test.csv',sep="\t",header=None, encoding='utf-8', index = False)
          

          【讨论】:

          • Stack Overflow 不接受纯代码答案。
          • 不需要转换为 numpy,并且在此代码中实际上并未执行。
          【解决方案9】:

          要拆分成两个以上的类,例如训练、测试和验证,可以这样做:

          probs = np.random.rand(len(df))
          training_mask = probs < 0.7
          test_mask = (probs>=0.7) & (probs < 0.85)
          validatoin_mask = probs >= 0.85
          
          
          df_training = df[training_mask]
          df_test = df[test_mask]
          df_validation = df[validatoin_mask]
          

          这会将大约 70% 的数据用于训练,15% 用于测试,15% 用于验证。

          【讨论】:

          • 您可能想要编辑您的答案以添加“大约”,如果您运行代码,您会发现它可能与确切的百分比相差甚远。例如我在 1000 个项目上进行了尝试,得到:700、141、159 - 所以 70%、14% 和 16%。
          【解决方案10】:

          您可以使用~(波浪号运算符)排除使用df.sample()采样的行,让pandas单独处理索引的采样和过滤,以获得两组。

          train_df = df.sample(frac=0.8, random_state=100)
          test_df = df[~df.index.isin(train_df.index)]
          

          【讨论】:

            【解决方案11】:

            上面有很多很好的答案,所以我只想再添加一个示例,以防您想仅使用 numpy 库来指定训练集和测试集的确切样本数。

            # set the random seed for the reproducibility
            np.random.seed(17)
            
            # e.g. number of samples for the training set is 1000
            n_train = 1000
            
            # shuffle the indexes
            shuffled_indexes = np.arange(len(data_df))
            np.random.shuffle(shuffled_indexes)
            
            # use 'n_train' samples for training and the rest for testing
            train_ids = shuffled_indexes[:n_train]
            test_ids = shuffled_indexes[n_train:]
            
            train_data = data_df.iloc[train_ids]
            train_labels = labels_df.iloc[train_ids]
            
            test_data = data_df.iloc[test_ids]
            test_labels = data_df.iloc[test_ids]
            

            【讨论】:

              【解决方案12】:

              Pandas 随机样本也可以使用

              train=df.sample(frac=0.8,random_state=200) #random state is a seed value
              test=df.drop(train.index)
              

              【讨论】:

              • random_statearg 在做什么?
              • @RishabhAgrahari 每次根据 frac arg 随机打乱不同的数据拆分。如果您想控制随机性,您可以声明自己的种子,如示例中所示。
              • 这似乎运作良好,并且比引入 sklearn 更优雅的解决方案。是否有理由认为这不应该是一个更好接受的答案?
              • @RajV 以其当前形式 test 将被随机选择,但行将按其原始顺序排列。 sklearn 方法对训练和测试进行了洗牌。
              • @peer 如果需要改组的test 集,则很容易解决此限制,正如此处stackoverflow.com/questions/29576430/shuffle-dataframe-rows 所指出的那样。 test=df.drop(train.index).sample(frac=1.0)
              【解决方案13】:

              有很多方法可以创建训练/测试甚至验证样本。

              案例一:经典方式train_test_split 没有任何选项:

              from sklearn.model_selection import train_test_split
              train, test = train_test_split(df, test_size=0.3)
              

              案例 2:非常小的数据集(

              from sklearn.model_selection import KFold
              kf = KFold(n_splits=10, random_state=0)
              y_hat_all = []
              for train_index, test_index in kf.split(X, y):
                  reg = RandomForestRegressor(n_estimators=50, random_state=0)
                  X_train, X_test = X[train_index], X[test_index]
                  y_train, y_test = y[train_index], y[test_index]
                  clf = reg.fit(X_train, y_train)
                  y_hat = clf.predict(X_test)
                  y_hat_all.append(y_hat)
              

              案例 3a:用于分类目的的不平衡数据集。按照案例1,下面是等效的解决方案:

              from sklearn.model_selection import train_test_split
              X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.3)
              

              案例 3b:用于分类目的的不平衡数据集。按照案例2,这里是等效的解决方案:

              from sklearn.model_selection import StratifiedKFold
              kf = StratifiedKFold(n_splits=10, random_state=0)
              y_hat_all = []
              for train_index, test_index in kf.split(X, y):
                  reg = RandomForestRegressor(n_estimators=50, random_state=0)
                  X_train, X_test = X[train_index], X[test_index]
                  y_train, y_test = y[train_index], y[test_index]
                  clf = reg.fit(X_train, y_train)
                  y_hat = clf.predict(X_test)
                  y_hat_all.append(y_hat)
              

              案例 4:您需要在大数据上创建训练/测试/验证集来调整超参数(60% 训练、20% 测试和 20% 验证)。

              from sklearn.model_selection import train_test_split
              X_train, X_test_val, y_train, y_test_val = train_test_split(X, y, test_size=0.6)
              X_test, X_val, y_test, y_val = train_test_split(X_test_val, y_test_val, stratify=y, test_size=0.5)
              

              【讨论】:

                【解决方案14】:

                对我来说更优雅一点的是创建一个随机列,然后按它拆分,这样我们就可以得到一个适合我们需要并且是随机的拆分。

                def split_df(df, p=[0.8, 0.2]):
                import numpy as np
                df["rand"]=np.random.choice(len(p), len(df), p=p)
                r = [df[df["rand"]==val] for val in df["rand"].unique()]
                return r
                

                【讨论】:

                  【解决方案15】:
                  import pandas as pd
                  
                  from sklearn.model_selection import train_test_split
                  
                  datafile_name = 'path_to_data_file'
                  
                  data = pd.read_csv(datafile_name)
                  
                  target_attribute = data['column_name']
                  
                  X_train, X_test, y_train, y_test = train_test_split(data, target_attribute, test_size=0.8)
                  

                  【讨论】:

                  • 你有一个小错误。您应该先删除目标列,然后将其放入 train_test_split。 data = data.drop(columns = ['column_name'], axis = 1)
                  【解决方案16】:

                  您可以使用以下代码来创建测试和训练样本:

                  from sklearn.model_selection import train_test_split
                  trainingSet, testSet = train_test_split(df, test_size=0.2)
                  

                  测试大小可能会有所不同,具体取决于您要放入测试和训练数据集中的数据百分比。

                  【讨论】:

                    【解决方案17】:

                    如果您需要根据数据集中的标签列拆分数据,您可以使用:

                    def split_to_train_test(df, label_column, train_frac=0.8):
                        train_df, test_df = pd.DataFrame(), pd.DataFrame()
                        labels = df[label_column].unique()
                        for lbl in labels:
                            lbl_df = df[df[label_column] == lbl]
                            lbl_train_df = lbl_df.sample(frac=train_frac)
                            lbl_test_df = lbl_df.drop(lbl_train_df.index)
                            print '\n%s:\n---------\ntotal:%d\ntrain_df:%d\ntest_df:%d' % (lbl, len(lbl_df), len(lbl_train_df), len(lbl_test_df))
                            train_df = train_df.append(lbl_train_df)
                            test_df = test_df.append(lbl_test_df)
                    
                        return train_df, test_df
                    

                    并使用它:

                    train, test = split_to_train_test(data, 'class', 0.7)
                    

                    如果你想控制分裂随机性或使用一些全局随机种子,你也可以传递 random_state。

                    【讨论】:

                      【解决方案18】:

                      像这样从df中选择范围行

                      row_count = df.shape[0]
                      split_point = int(row_count*1/5)
                      test_data, train_data = df[:split_point], df[split_point:]
                      

                      【讨论】:

                      • 这只有在数据框中的数据已经随机排序时才有效。如果数据集来自多个来源并已附加到同一个数据帧,那么很可能会得到一个非常倾斜的数据集,用于使用上述方法进行训练/测试。
                      • 您可以在拆分数据帧之前对其进行洗牌stackoverflow.com/questions/29576430/shuffle-dataframe-rows
                      • 绝对!如果你在你的代码中添加df,sn-p 是(或应该是)改组它会改善答案。
                      【解决方案19】:

                      有很多有效的答案。添加一个到一堆。 从 sklearn.cross_validation 导入 train_test_split

                      #gets a random 80% of the entire set
                      X_train = X.sample(frac=0.8, random_state=1)
                      #gets the left out portion of the dataset
                      X_test = X.loc[~df_model.index.isin(X_train.index)]
                      

                      【讨论】:

                        【解决方案20】:

                        这个怎么样? df 是我的数据框

                        total_size=len(df)
                        
                        train_size=math.floor(0.66*total_size) (2/3 part of my dataset)
                        
                        #training dataset
                        train=df.head(train_size)
                        #test dataset
                        test=df.tail(len(df) -train_size)
                        

                        【讨论】:

                          【解决方案21】:

                          您可以利用 df.as_matrix() 函数创建 Numpy-array 并传递它。

                          Y = df.pop()
                          X = df.as_matrix()
                          x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size = 0.2)
                          model.fit(x_train, y_train)
                          model.test(x_test)
                          

                          【讨论】:

                            【解决方案22】:

                            如果您想稍后添加列,我认为您还需要获取副本而不是数据框切片。

                            msk = np.random.rand(len(df)) < 0.8
                            train, test = df[msk].copy(deep = True), df[~msk].copy(deep = True)
                            

                            【讨论】:

                              【解决方案23】:

                              如果您希望输入一个数据帧并输出两个数据帧(不是 numpy 数组),这应该可以解决问题:

                              def split_data(df, train_perc = 0.8):
                              
                                 df['train'] = np.random.rand(len(df)) < train_perc
                              
                                 train = df[df.train == 1]
                              
                                 test = df[df.train == 0]
                              
                                 split_data ={'train': train, 'test': test}
                              
                                 return split_data
                              

                              【讨论】:

                                【解决方案24】:

                                这是我需要拆分 DataFrame 时写的。我考虑过使用上面 Andy 的方法,但不喜欢我无法精确控制数据集的大小(即有时是 79,有时是 81,等等)。

                                def make_sets(data_df, test_portion):
                                    import random as rnd
                                
                                    tot_ix = range(len(data_df))
                                    test_ix = sort(rnd.sample(tot_ix, int(test_portion * len(data_df))))
                                    train_ix = list(set(tot_ix) ^ set(test_ix))
                                
                                    test_df = data_df.ix[test_ix]
                                    train_df = data_df.ix[train_ix]
                                
                                    return train_df, test_df
                                
                                
                                train_df, test_df = make_sets(data_df, 0.2)
                                test_df.head()
                                

                                【讨论】:

                                  【解决方案25】:

                                  您也可以考虑将训练集和测试集分层划分。 Startified Division 也随机生成训练和测试集,但以保留原始类比例的方式。这使得训练和测试集更好地反映了原始数据集的属性。

                                  import numpy as np  
                                  
                                  def get_train_test_inds(y,train_proportion=0.7):
                                      '''Generates indices, making random stratified split into training set and testing sets
                                      with proportions train_proportion and (1-train_proportion) of initial sample.
                                      y is any iterable indicating classes of each observation in the sample.
                                      Initial proportions of classes inside training and 
                                      testing sets are preserved (stratified sampling).
                                      '''
                                  
                                      y=np.array(y)
                                      train_inds = np.zeros(len(y),dtype=bool)
                                      test_inds = np.zeros(len(y),dtype=bool)
                                      values = np.unique(y)
                                      for value in values:
                                          value_inds = np.nonzero(y==value)[0]
                                          np.random.shuffle(value_inds)
                                          n = int(train_proportion*len(value_inds))
                                  
                                          train_inds[value_inds[:n]]=True
                                          test_inds[value_inds[n:]]=True
                                  
                                      return train_inds,test_inds
                                  

                                  df[train_inds] 和 df[test_inds] 为您提供原始 DataFrame df 的训练和测试集。

                                  【讨论】:

                                  • 这是监督学习任务的首选策略。
                                  • 尝试使用此功能时出现错误。 ValueError: assignment destination is read-only in line "np.random.shuffle(value_inds)"
                                  【解决方案26】:

                                  我只会使用 numpy 的 randn:

                                  In [11]: df = pd.DataFrame(np.random.randn(100, 2))
                                  
                                  In [12]: msk = np.random.rand(len(df)) < 0.8
                                  
                                  In [13]: train = df[msk]
                                  
                                  In [14]: test = df[~msk]
                                  

                                  只是为了看看这是否有效:

                                  In [15]: len(test)
                                  Out[15]: 21
                                  
                                  In [16]: len(train)
                                  Out[16]: 79
                                  

                                  【讨论】:

                                  • 对不起,我的错误。只要msk 的dtype 为bool、df[msk]、df.iloc[msk] 和df.loc[msk] 总是返回相同的结果。
                                  • 我认为你应该使用 rand 到 &lt; 0.8 是有意义的,因为它返回 0 到 1 之间的均匀分布的随机数。
                                  • 有人可以用python 术语来解释in[12]、in[13]、in[14] 行中到底发生了什么吗?我想在这里了解python代码本身
                                  • 使用 gobrewers14 中的 sklearn 的答案是更好的答案。它不那么复杂,更容易调试。我建议使用下面的答案。
                                  • @kuatroka np.random.rand(len(df)) 是一个大小为 len(df) 的数组,浮点值在 [0, 1] 范围内随机均匀分布。 &lt; 0.8 按元素应用比较并将结果存储在适当的位置。因此,值 True,值 >= 0.8 变为 False
                                  猜你喜欢
                                  • 2015-07-16
                                  • 2016-10-04
                                  • 1970-01-01
                                  • 2017-12-25
                                  • 2020-09-24
                                  • 2019-07-06
                                  • 2018-06-04
                                  相关资源
                                  最近更新 更多