簡體   English   中英

將數據幀拆分為多個數據幀

[英]Splitting dataframe into multiple dataframes

我有一個非常大的數據框(大約 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

我沒有收到錯誤消息,腳本似乎永遠運行!

有聰明的方法嗎?

我可以問為什么不通過切片數據框來做到這一點。 就像是

#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']

希望有幫助

首先,您的方法效率低下,因為逐行附加到列表會很慢,因為當新條目的空間不足時,它必須定期增加列表,列表理解在這方面更好,因為大小已確定前面並分配一次。

但是,我認為從根本上講,您的方法有點浪費,因為您已經有了一個數據框,那么為什么要為這些用戶中的每一個都創建一個新的呢?

我會按列'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'

您可以將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

推薦,但可以按組創建數據幀:

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

簡單:

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

Groupby 可以幫助您:

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

然后,您可以像處理每個參與者的數據框一樣處理每個組。 而DataFrameGroupBy對象的方法如(apply、transform、aggregate、head、first、last)返回一個DataFrame對象。

或者您可以從grouped創建列表grouped索引獲取所有數據幀:

l_grouped = list(grouped)

l_grouped[0][1] - 具有名字的第一個組的數據幀。

除了 Gusev Slava 的回答之外,您可能還想使用 groupby 的組:

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

這將生成一個字典,其中包含您分組的鍵,指向相應的分區。 優點是鍵被維護並且不會在列表索引中消失。

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

基於列表理解和groupby - 將所有拆分數據幀存儲在列表變量中,並且可以使用索引進行訪問。

例子

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

ans[0]
ans[0].column_name
  • OP中的方法有效,但效率不高。 它可能似乎永遠運行,因為數據集很長。
  • 'method'列上使用.groupby ,並使用dict DataFrames以唯一的'method'值作為鍵創建DataFramesdict-comprehension
    • .groupby返回一個groupby對象,其中包含有關組的信息,其中g是每個組的'method'的唯一值, d是該組的DataFrame
  • df_dict中每個keyvalue將是一個DataFrame ,可以以標准方式訪問, df_dict['key']
  • 最初的問題想要一個DataFrames list ,這可以通過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

或者

  • 這是使用DataFrames創建單獨DataFrames的手動方法:布爾索引
  • 這類似於已接受的答案,但不需要.loc
  • 這是創建幾個額外DataFrames的可接受方法。
  • 創建多個對象的 Pythonic 方法是將它們放在一個容器中(例如dictlistgenerator等),如上所示。
df1 = df[df.method == 'Astrometry']
df2 = df[df.method == 'Eclipse Timing Variations']

如果您的數據已有一些標簽,則可以使用 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)]

它返回out_list兩個pd.Serieslist

[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

這是一個可能對某些人有所幫助的小函數(效率可能並不完美,但緊湊 + 或多或少易於理解):

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]

現有的答案涵蓋了所有好的案例,並且很好地解釋了groupby對象如何像一個可以通過.groups訪問的鍵和值的字典。 還有更多方法可以完成與現有答案相同的工作:

  • 通過解包 groupby 對象並將其轉換為字典來創建列表:
dict([*df.groupby('Name')]) # same as dict(list(df.groupby('Name')))
  • 創建一個元組 + 字典(這與@jezrael 的回答相同):
dict((*df.groupby('Name'),))
  • 如果我們只想要數據幀,我們可以獲取字典(上面創建的)的值:
[*dict([*df.groupby('Name')]).values()]

我有類似的問題。 我有 10 家不同商店和 50 種不同商品的每日銷售額的時間序列。 我需要將原始數據幀拆分為 500 個數據幀(10 個商店 * 50 個商店)以將機器學習模型應用於每個數據幀,而我無法手動完成。

這是數據幀的頭部:

數據幀的頭部:df

我創建了兩個列表; 一個用於數據幀的名稱,另一個用於數組 [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 個數據幀。

希望這會有所幫助!

暫無
暫無

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

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