【问题标题】:Splitting dataframe into multiple dataframes将数据帧拆分为多个数据帧
【发布时间】:2013-11-16 10:23:57
【问题描述】:

我有一个非常大的数据框(大约 100 万行),其中包含来自实验的数据(60 位受访者)。

我想将数据框拆分为 60 个数据框(每个参与者一个数据框)。

在数据框data中,有一个名为'name'的变量,它是每个参与者的唯一代码。

我尝试了以下操作,但没有任何反应(或执行不会在一小时内停止)。我打算做的是将data 拆分为更小的数据帧,并将它们附加到列表中(datalist):

import pandas as pd

def splitframe(data, name='name'):
    
    n = data[name][0]

    df = pd.DataFrame(columns=data.columns)

    datalist = []

    for i in range(len(data)):
        if data[name][i] == n:
            df = df.append(data.iloc[i])
        else:
            datalist.append(df)
            df = pd.DataFrame(columns=data.columns)
            n = data[name][i]
            df = df.append(data.iloc[i])
        
    return datalist

我没有收到错误消息,脚本似乎永远运行!

有什么聪明的方法吗?

【问题讨论】:

    标签: python split pandas dataframe


    【解决方案1】:
    • OP 中的方法有效,但效率不高。它可能似乎永远运行,因为数据集很长。
    • 'method' 列上使用.groupby,并创建DataFramesdict,以唯一的'method' 值作为键,并使用dict-comprehension
      • .groupby 返回一个groupby 对象,其中包含有关组的信息,其中g'method' 中每个组的唯一值,d 是该组的DataFrame
    • df_dict 中每个keyvalue 将是一个DataFrame,可以通过标准方式df_dict['key'] 访问。
    • 最初的问题想要listDataFrames,可以用list-comprehension 完成
      • df_list = [d for _, d in df.groupby('method')]
    import pandas as pd
    import seaborn as sns  # for test dataset
    
    # load data for example
    df = sns.load_dataset('planets')
    
    # display(df.head())
                method  number  orbital_period   mass  distance  year
    0  Radial Velocity       1         269.300   7.10     77.40  2006
    1  Radial Velocity       1         874.774   2.21     56.95  2008
    2  Radial Velocity       1         763.000   2.60     19.84  2011
    3  Radial Velocity       1         326.030  19.40    110.62  2007
    4  Radial Velocity       1         516.220  10.50    119.47  2009
    
    
    # Using a dict-comprehension, the unique 'method' value will be the key
    df_dict = {g: d for g, d in df.groupby('method')}
    
    print(df_dict.keys())
    [out]:
    dict_keys(['Astrometry', 'Eclipse Timing Variations', 'Imaging', 'Microlensing', 'Orbital Brightness Modulation', 'Pulsar Timing', 'Pulsation Timing Variations', 'Radial Velocity', 'Transit', 'Transit Timing Variations'])
    
    # or a specific name for the key, using enumerate (e.g. df1, df2, etc.)
    df_dict = {f'df{i}': d for i, (g, d) in enumerate(df.groupby('method'))}
    
    print(df_dict.keys())
    [out]:
    dict_keys(['df0', 'df1', 'df2', 'df3', 'df4', 'df5', 'df6', 'df7', 'df8', 'df9'])
    
    • df_dict['df1].head(3)df_dict['Astrometry'].head(3)
    • 这个组只有2个
             method  number  orbital_period  mass  distance  year
    113  Astrometry       1          246.36   NaN     20.77  2013
    537  Astrometry       1         1016.00   NaN     14.98  2010
    
    • df_dict['df2].head(3)df_dict['Eclipse Timing Variations'].head(3)
                           method  number  orbital_period  mass  distance  year
    32  Eclipse Timing Variations       1         10220.0  6.05       NaN  2009
    37  Eclipse Timing Variations       2          5767.0   NaN    130.72  2008
    38  Eclipse Timing Variations       2          3321.0   NaN    130.72  2008
    
    • df_dict['df3].head(3)df_dict['Imaging'].head(3)
         method  number  orbital_period  mass  distance  year
    29  Imaging       1             NaN   NaN     45.52  2005
    30  Imaging       1             NaN   NaN    165.00  2007
    31  Imaging       1             NaN   NaN    140.00  2004
    

    或者

    • 这是使用pandas: Boolean Indexing 创建单独的DataFrames 的手动方法
    • 这类似于接受的答案,但不需要.loc
    • 这是一种可接受的方法来创建一对额外的DataFrames
    • 创建多个对象的 Python 方式是将它们放入容器中(例如 dictlistgenerator 等),如上所示。
    df1 = df[df.method == 'Astrometry']
    df2 = df[df.method == 'Eclipse Timing Variations']
    

    【讨论】:

      【解决方案2】:

      这里有一个小功能可能会有所帮助(效率可能并不完美,但紧凑+或多或少容易理解):

      def get_splited_df_dict(df: 'pd.DataFrame', split_column: 'str'):
          """
          splits a pandas.DataFrame on split_column and returns it as a dict
          """
      
          df_dict = {value: df[df[split_column] == value].drop(split_column, axis=1) for value in df[split_column].unique()}
      
          return df_dict
      

      它通过选择给定列中的每个唯一值并将所有这些条目放入单独的 DataFrame 中,将一个 DataFrame 转换为多个 DataFrame。 .drop(split_column, axis=1) 仅用于删除用于拆分 DataFrame 的列。删除不是必需的,但可以帮助减少操作后的内存使用量。

      get_splited_df_dict 的结果是dict,这意味着可以像这样访问每个 DataFrame:

      splitted = get_splited_df_dict(some_df, some_column)
      # accessing the DataFrame with 'some_column_value'
      splitted[some_column_value]
      

      【讨论】:

        【解决方案3】:

        首先,您的方法效率低下,因为逐行追加到列表会很慢,因为当新条目的空间不足时,它必须定期增长列表,列表理解在这方面更好,因为大小预先确定并分配一次。

        但是,我认为从根本上说,您的方法有点浪费,因为您已经有了一个数据框,那么为什么要为这些用户中的每一个创建一个新的呢?

        我会按列'name' 对数据框进行排序,将索引设置为这个,如果需要,不要删除该列。

        然后生成所有唯一条目的列表,然后您可以使用这些条目执行查找,最重要的是,如果您只查询数据,请使用选择标准返回数据框的视图,而不会产生昂贵的数据副本。

        使用pandas.DataFrame.sort_valuespandas.DataFrame.set_index

        # sort the dataframe
        df.sort_values(by='name', axis=1, inplace=True)
        
        # set the index to be this and don't drop
        df.set_index(keys=['name'], drop=False,inplace=True)
        
        # get a list of names
        names=df['name'].unique().tolist()
        
        # now we can perform a lookup on a 'view' of the dataframe
        joe = df.loc[df.name=='joe']
        
        # now you can query all 'joes'
        

        【讨论】:

        • 据我了解 - 排序时轴应为零
        【解决方案4】:

        简单:

        [v for k, v in df.groupby('name')]
        

        【讨论】:

          【解决方案5】:

          Groupby 可以帮助您:

          grouped = data.groupby(['name'])
          

          然后,您可以与每个组一起工作,就像为每个参与者使用数据框一样。而DataFrameGroupBy对象方法如(apply、transform、aggregate、head、first、last)返回一个DataFrame对象。

          或者您可以从grouped 列出并按索引获取所有DataFrame:

          l_grouped = list(grouped)
          

          l_grouped[0][1] - 具有名字的第一个组的 DataFrame。

          【讨论】:

            【解决方案6】:

            如果您的数据已经有一些标签,您可以使用 groupby 命令。

             out_list = [group[1] for group in in_series.groupby(label_series.values)]
            

            这里有一个详细的例子:

            假设我们想使用一些标签将一个 pd 系列划分为一个块列表 例如,in_series 是:

            2019-07-01 08:00:00   -0.10
            2019-07-01 08:02:00    1.16
            2019-07-01 08:04:00    0.69
            2019-07-01 08:06:00   -0.81
            2019-07-01 08:08:00   -0.64
            Length: 5, dtype: float64
            

            而其对应的label_series为:

            2019-07-01 08:00:00   1
            2019-07-01 08:02:00   1
            2019-07-01 08:04:00   2
            2019-07-01 08:06:00   2
            2019-07-01 08:08:00   2
            Length: 5, dtype: float64
            

            运行

            out_list = [group[1] for group in in_series.groupby(label_series.values)]
            

            它返回两个pd.Series中的out_list一个list

            [2019-07-01 08:00:00   -0.10
            2019-07-01 08:02:00   1.16
            Length: 2, dtype: float64,
            2019-07-01 08:04:00    0.69
            2019-07-01 08:06:00   -0.81
            2019-07-01 08:08:00   -0.64
            Length: 3, dtype: float64]
            

            请注意,您可以使用 in_series 本身的一些参数对系列进行分组,例如,in_series.index.day

            【讨论】:

              【解决方案7】:

              您可以将groupby 对象转换为tuples,然后再转换为dict

              df = pd.DataFrame({'Name':list('aabbef'),
                                 'A':[4,5,4,5,5,4],
                                 'B':[7,8,9,4,2,3],
                                 'C':[1,3,5,7,1,0]}, columns = ['Name','A','B','C'])
              
              print (df)
                Name  A  B  C
              0    a  4  7  1
              1    a  5  8  3
              2    b  4  9  5
              3    b  5  4  7
              4    e  5  2  1
              5    f  4  3  0
              
              d = dict(tuple(df.groupby('Name')))
              print (d)
              {'b':   Name  A  B  C
              2    b  4  9  5
              3    b  5  4  7, 'e':   Name  A  B  C
              4    e  5  2  1, 'a':   Name  A  B  C
              0    a  4  7  1
              1    a  5  8  3, 'f':   Name  A  B  C
              5    f  4  3  0}
              
              print (d['a'])
                Name  A  B  C
              0    a  4  7  1
              1    a  5  8  3
              

              不是recommended,而是可以按组创建DataFrame:

              for i, g in df.groupby('Name'):
                  globals()['df_' + str(i)] =  g
              
              print (df_a)
                Name  A  B  C
              0    a  4  7  1
              1    a  5  8  3
              

              【讨论】:

                【解决方案8】:

                基于列表理解和groupby的方法- 将所有拆分的数据帧存储在列表变量中,可以使用索引访问。

                例子

                ans = [pd.DataFrame(y) for x, y in DF.groupby('column_name', as_index=False)]
                
                ans[0]
                ans[0].column_name
                

                【讨论】:

                  【解决方案9】:

                  我有类似的问题。我有 10 家不同商店和 50 种不同商品的每日销售时间序列。我需要将原始数据帧拆分为 500 个数据帧(10 个存储*50 个存储)以将机器学习模型应用于每个数据帧,而我无法手动完成。

                  这是数据框的头部:

                  我创建了两个列表; 一个用于数据框的名称 一个用于数组 [item_number, store_number]。

                      list=[]
                      for i in range(1,len(items)*len(stores)+1):
                      global list
                      list.append('df'+str(i))
                  
                      list_couple_s_i =[]
                      for item in items:
                            for store in stores:
                                    global list_couple_s_i
                                    list_couple_s_i.append([item,store])
                  

                  一旦这两个列表准备就绪,您就可以循环它们以创建您想要的数据框:

                           for name, it_st in zip(list,list_couple_s_i):
                                     globals()[name] = df.where((df['item']==it_st[0]) & 
                                                                  (df['store']==(it_st[1])))
                                     globals()[name].dropna(inplace=True)
                  

                  通过这种方式,我创建了 500 个数据框。

                  希望这会有所帮助!

                  【讨论】:

                    【解决方案10】:

                    除了 Gusev Slava 的回答,您可能还想使用 groupby 的组:

                    {key: df.loc[value] for key, value in df.groupby("name").groups.items()}
                    

                    这将产生一个字典,其中包含您分组的键,指向相应的分区。优点是键被维护并且不会在列表索引中消失。

                    【讨论】:

                      【解决方案11】:
                      In [28]: df = DataFrame(np.random.randn(1000000,10))
                      
                      In [29]: df
                      Out[29]: 
                      <class 'pandas.core.frame.DataFrame'>
                      Int64Index: 1000000 entries, 0 to 999999
                      Data columns (total 10 columns):
                      0    1000000  non-null values
                      1    1000000  non-null values
                      2    1000000  non-null values
                      3    1000000  non-null values
                      4    1000000  non-null values
                      5    1000000  non-null values
                      6    1000000  non-null values
                      7    1000000  non-null values
                      8    1000000  non-null values
                      9    1000000  non-null values
                      dtypes: float64(10)
                      
                      In [30]: frames = [ df.iloc[i*60:min((i+1)*60,len(df))] for i in xrange(int(len(df)/60.) + 1) ]
                      
                      In [31]: %timeit [ df.iloc[i*60:min((i+1)*60,len(df))] for i in xrange(int(len(df)/60.) + 1) ]
                      1 loops, best of 3: 849 ms per loop
                      
                      In [32]: len(frames)
                      Out[32]: 16667
                      

                      这是一种分组方式(您可以进行任意应用而不是求和)

                      In [9]: g = df.groupby(lambda x: x/60)
                      
                      In [8]: g.sum()    
                      
                      Out[8]: 
                      <class 'pandas.core.frame.DataFrame'>
                      Int64Index: 16667 entries, 0 to 16666
                      Data columns (total 10 columns):
                      0    16667  non-null values
                      1    16667  non-null values
                      2    16667  non-null values
                      3    16667  non-null values
                      4    16667  non-null values
                      5    16667  non-null values
                      6    16667  non-null values
                      7    16667  non-null values
                      8    16667  non-null values
                      9    16667  non-null values
                      dtypes: float64(10)
                      

                      Sum 被 cythonized 这就是为什么它这么快

                      In [10]: %timeit g.sum()
                      10 loops, best of 3: 27.5 ms per loop
                      
                      In [11]: %timeit df.groupby(lambda x: x/60)
                      1 loops, best of 3: 231 ms per loop
                      

                      【讨论】:

                        【解决方案12】:

                        我能问一下为什么不通过对数据框进行切片来做到这一点。类似的东西

                        #create some data with Names column
                        data = pd.DataFrame({'Names': ['Joe', 'John', 'Jasper', 'Jez'] *4, 'Ob1' : np.random.rand(16), 'Ob2' : np.random.rand(16)})
                        
                        #create unique list of names
                        UniqueNames = data.Names.unique()
                        
                        #create a data frame dictionary to store your data frames
                        DataFrameDict = {elem : pd.DataFrame for elem in UniqueNames}
                        
                        for key in DataFrameDict.keys():
                            DataFrameDict[key] = data[:][data.Names == key]
                        

                        嘿,你有一个数据框字典,就像(我认为)你想要的那样。需要访问一个吗?直接输入

                        DataFrameDict['Joe']
                        

                        希望有帮助

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          相关资源
                          最近更新 更多