Розбиття кадру даних на кілька кадрів даних


93

У мене дуже великий кадр даних (близько 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']

Сподіваюся, це допомагає


39

Ви можете перетворити 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


16

Groupby can допомагає вам:

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

Тоді ви можете працювати з кожною групою, як з фреймом даних для кожного учасника. І такі методи об’єкта DataFrameGroupBy, як (застосувати, перетворити, агрегувати, заголовок, перший, останній) повертають об’єкт 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за допомогою панд: логічне індексування
  • Це схоже на прийняту відповідь , але .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_lista listз двох pd.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.