Фрейм данных Pandas для фрагментов, чтобы иметь уникальные значения определенного столбца в каждом фрагменте

У меня есть фрейм данных pandas с большим количеством столбцов:

Col1 Col2 Col3 Col4
A1   B3   C2   D4
A2   B4   C3   D2
A5   B2   C1   D1
A4   B3   C2   D4
A5   B4   C3   D2
A2   B3   C4   D1
A3   B2   C3   D4
A1   B4   C3   D2
A4   B2   C1   D1

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

Например: если n=3

df1:

Col1 Col2 Col3 Col4
A1   B3   C2   D4
A2   B4   C3   D2
A5   B2   C1   D1

df2:

Col1 Col2 Col3 Col4
A4   B3   C2   D4
A5   B4   C3   D2
A2   B3   C4   D1

df3:

Col1 Col2 Col3 Col4
A3   B2   C3   D4
A1   B4   C3   D2
A4   B2   C1   D1

person msksantosh    schedule 12.01.2018    source источник
comment
Что должно произойти, если n=4? Здесь мало уникальных случаев в Col4.   -  person Little Bobby Tables    schedule 12.01.2018
comment
вас волнует первоначальный порядок строк? о размере кусков? это похоже на очень индивидуальный вариант использования.   -  person louis_guitton    schedule 12.01.2018
comment
@josh, в таком случае я бы хотел, чтобы максимальное количество фрагментов соответствовало критериям. В моем случае у меня миллионы строк, так что этот сценарий невозможен.   -  person msksantosh    schedule 12.01.2018
comment
@laguittemh нет, меня не волнует исходный порядок строки или размер фрагментов   -  person msksantosh    schedule 12.01.2018
comment
Что вы в конечном итоге пытаетесь сделать с этим фрагментированием? Возможно, существует более простой способ достижения вашей конечной цели.   -  person Silenced Temporarily    schedule 12.01.2018
comment
Играя здесь в адвоката дьявола, что, если n=3 и в группе Col4 имеется более n уникальных записей для группы? Имеет ли значение, если у вас есть 5 в одном куске и 1 во всех остальных? например df1.Col4 = [D4, D4, D4, D2, D1], df2.Col4 = [D4, D2, D1].   -  person Little Bobby Tables    schedule 12.01.2018
comment
@А. Лейстра: Я пытаюсь построить случайный лес на каждом из фрагментов с col4 в качестве зависимой переменной, и я пытаюсь иметь как можно более единообразное представление col4 в каждом из фрагментов.   -  person msksantosh    schedule 12.01.2018
comment
@josh Я бы предпочел иметь как можно больше маленьких кусочков, но если нет другого пути, ваше решение тоже подойдет   -  person msksantosh    schedule 12.01.2018


Ответы (2)


Просто нужно groupby + //

import numpy as np 
import pandas as pd 
d={}
n=3

for x, y in df.groupby(np.arange(len(df)) // n):
    d[x] = y

d
Out[625]: 
{0:   Col1 Col2 Col3 Col4
 0   A1   B3   C2   D4
 1   A2   B4   C3   D2
 2   A5   B2   C1   D1, 1:   Col1 Col2 Col3 Col4
 3   A4   B3   C2   D4
 4   A5   B4   C3   D2
 5   A2   B3   C4   D1, 2:   Col1 Col2 Col3 Col4
 6   A3   B2   C3   D4
 7   A1   B4   C3   D2
 8   A4   B2   C1   D1}

Например

d[0]
Out[626]: 
  Col1 Col2 Col3 Col4
0   A1   B3   C2   D4
1   A2   B4   C3   D2
2   A5   B2   C1   D1
person BENY    schedule 12.01.2018

Это не очень красиво, но я считаю, что это решение, которое покрывает ваши вышеуказанные условия.

Мы можем разделить DataFrames, используя split_array форму numpy. См. этот сообщение для получения более подробной информации об этом.

import numpy as np

df = pd.DataFrame({'D': 'a a a b b b c c c c c c'.split(' '), 'A': range(12)})

n = 3

# here we count the nth position of the the 'D' categorical
df = df.assign(ranked=lambda df: df.groupby('D').transform(lambda x: x.rank()))

# we now filter into two dfs: one df with evenly distributed columns Ds
# and one with all the left overs where ranked > n
df1 = df.loc[lambda x: x.ranked<=n, :].sort_values('ranked')
df2 = df.loc[lambda x: x.ranked>n, :].sort_values('ranked')

# split them as mentioned before
df1_list = np.array_split(df1, n)
df2_list = np.array_split(df2, n)

#zip the lists of them back together and join df1 and df2 chunks
list_of_chunked_dfs = [pd.concat(df).drop('ranked', axis=1) for df in zip(df1_list, df2_list)]
person Little Bobby Tables    schedule 12.01.2018