Разделение фрейма данных на несколько фреймов данных


92

У меня очень большой фрейм данных (около 1 миллиона строк) с данными эксперимента (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

Я не получаю сообщения об ошибке, сценарий просто запускается вечно!

Есть ли разумный способ сделать это?

Ответы:


53

Во-первых, ваш подход неэффективен, потому что добавление к списку построчно будет медленным, так как он должен периодически увеличивать список, когда недостаточно места для новой записи, понимание списка лучше в этом отношении, поскольку размер определяется вверх спереди и выделяется один раз.

Тем не менее, я думаю, что в принципе ваш подход немного расточителен, поскольку у вас уже есть фреймворк, так зачем создавать новый для каждого из этих пользователей?

Я бы отсортировал фрейм данных по столбцу 'name', установил индекс таким образом и, если необходимо, не удалял столбец.

Затем сгенерируйте список всех уникальных записей, а затем вы можете выполнить поиск, используя эти записи, и, что особенно важно, если вы запрашиваете только данные, используйте критерии выбора, чтобы вернуть представление на фрейм данных, не неся дорогостоящее копирование данных.

Используйте pandas.DataFrame.sort_valuesи pandas.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'

74

Могу я спросить, почему бы просто не сделать это, разрезав фрейм данных. Что-то типа

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

надеюсь, это поможет


38

Вы можете преобразовать 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

Не рекомендуется , но возможно создавать DataFrames по группам:

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


16

Groupby может помочь вам:

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

Затем вы можете работать с каждой группой, как с фреймом данных для каждого участника. А методы объекта DataFrameGroupBy, такие как (apply, transform, aggregate, head, first, last), возвращают объект DataFrame.

Или вы можете составить список groupedи получить все DataFrame по индексу:

l_grouped = list(grouped)

l_grouped[0][1] - DataFrame для первой группы с именем.


7

В дополнение к ответу Гусева Славы вы можете использовать группы groupby:

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

Это даст словарь с ключами, которые вы сгруппировали, указывая на соответствующие разделы. Преимущество состоит в том, что ключи сохраняются и не исчезают в индексе списка.


3
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)

Сумма цитируется, поэтому это так быстро

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

1

Метод, основанный на понимании списка и groupby- который хранит весь разделенный фрейм данных в переменной списка и может быть доступен с помощью индекса.

пример

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

ans[0]
ans[0].column_name

1
  • Во-первых, метод в OP работает, но неэффективен. Может показаться, что это будет длиться вечно, потому что набор данных был длинным.
  • Используйте .groupbyв 'method'столбце и создайте dictиз DataFramesс уникальными 'method'значениями в качестве ключей с помощью dict-comprehension.
    • .groupbyвозвращает groupbyобъект, содержащий информацию о группах, где g- уникальное значение 'method'для каждой группы, а d- DataFrameдля этой группы.
  • valueКаждый keyин df_dict, будет DataFrame, которые могут быть доступны стандартным образом, df_dict['key'].
  • Оригинальный вопрос хотел listиз DataFrames, который может быть сделан с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с помощью pandas: логическое индексирование
  • Это похоже на принятый ответ , но .locне требуется.
  • Это приемлемый метод для создания пары лишних DataFrames.
  • Вещий способ для создания нескольких объектов, путем размещения их в контейнере (например dict, list, generatorи т.д.), как показано выше.
df1 = df[df.method == 'Astrometry']
df2 = df[df.method == 'Eclipse Timing Variations']

0

Вы можете использовать команду 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_listlistpd.Series

[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


-1

У меня была аналогичная проблема. У меня был временной ряд ежедневных продаж для 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 фреймов данных.

Надеюсь, это будет полезно!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.