簡體   English   中英

如何在最小和最大尺寸條件下應用熊貓組(Pythonic方式)

[英]How to apply panda group by with minimum and maximum size condition (Pythonic way)

我在 pandas 中有一個 dataframe ,我需要將其分組並存儲在一個新數組中,在該數組中我需要具有特定大小的每個組的大小,如果超過最小大小,則應將其添加到具有最小的尺寸。 例如,在我對數據進行分組后,我將擁有一組G ,即len(G)<=blen(G)>=aa <= len(G) <= b 所以,我需要用len(G)>=a使組滿足條件a <= len(G) <= b

該代碼現在正在運行 所以,我想知道是否有更方便的方法來做到這一點。

import numpy as np
import pandas as pd

rng = np.random.default_rng()  # Just for testing
df = pd.DataFrame(rng.integers(0, 10, size=(1000, 4)), columns=list('ABCD'))
# The dataframe is grouped depend on specific column.
ans = [pd.DataFrame(y) for x, y in df.groupby(df.columns[3], as_index=False)] 

n = 20 # The maximum size of the group is 25

new_arrayi_index = 0
new_array = []
for count_index in range(len(ans)):
    l = ans[count_index]
   
    if len(l) > n:

        df_shuffled = pd.DataFrame(l).sample(frac=1)
        final = [df_shuffled[i:i+n] for i in range(0,df_shuffled.shape[0],n)]

        for inde in range(len(final)):
            if len(final[inde]) <= 5 and new_arrayi_index != 0: #The minimum size of the group is 5

                new_array[new_arrayi_index - 1]=new_array[new_arrayi_index - 1]+final[inde]

            else:
                new_array.append(final[inde])
                new_arrayi_index += 1

    else: 

        new_array.append(l)
        new_arrayi_index += 1

count_index_ = 0
for count_index in range(len(new_array)):
    print("count", count_index, "Size", len(new_array[count_index]))
    print(new_array[count_index])
    count_index_ += count_index

print(count_index_)

將此行 -> ans = [pd.DataFrame(y) for x, y in df.groupby(df.columns[3], as_index=False)]更改為ans = [pd.DataFrame(y) for x, y in df.groupby(df.columns[3].min(), as_index=False)] for min

ans = [pd.DataFrame(y) for x, y in df.groupby(df.columns[3].max(), as_index=False)] for max

我寫了一個 function 將 dataframe 分成等於最大大小的塊。 它檢查最后一個塊的剩余部分的大小,如果剩余部分小於最小大小,它將最后兩個塊分成大小大致相等的兩個塊。

拆分大型 pandas dataframe時建立答案

import numpy as np
import pandas as pd


rng = np.random.default_rng(seed=1)  # Just for testing
df = pd.DataFrame(rng.integers(0, 10, size=(1000, 4)), columns=list('ABCD'))
# The dataframe is grouped depend on specific column.

n = 20  # The maximum size of the group is 25


# https://stackoverflow.com/questions/17315737/split-a-large-pandas-dataframe

def split_dataframe(df, chunk_size=20, min_size=10):

    chunks = list()
    remainder = len(df) % chunk_size

    if 0 < remainder < min_size:
        num_chunks = len(df) // chunk_size - 1
        for i in range(num_chunks):
            chunks.append(df[i * chunk_size:(i + 1) * chunk_size])
        df_ = df[(num_chunks) * chunk_size:]
        last_break = int(len(df_) / 2)
        chunks.append(df_[:last_break])
        chunks.append(df_[last_break:])
        return chunks
    else:
        num_chunks = len(df) // chunk_size + 1
        for i in range(num_chunks):
            chunks.append(df[i*chunk_size:(i+1)*chunk_size])
        return chunks


new_array = []
for group, df_ in df.groupby(df.columns[3], as_index=False):
    new_array.extend(split_dataframe(df_))

count_index_ = 0
for count_index in range(len(new_array)):
    print("count", count_index, "Size", len(new_array[count_index]))
    print(new_array[count_index])
    count_index_ += count_index

print(count_index_)

我從一開始就關注這篇文章,對討論將如何進行感到好奇,因為 OP 的問題並不總是可以解決。

解決方案的存在

舉個例子:一個組有 19 個元素,你想把它分成大小在 10 到 15 之間的部分。

當且僅當存在 integer g 時,解決方案才存在,使得n/b <= g <= n/a 在這種情況下,您可以看到長度a g部分將使用g*a <= n元素,長度為b的部分將使用g*b >= n

在這種情況下,也可以有一個平衡分區,最大的部分最多比最小的部分大一個記錄(最小的部分將有n//g條記錄)。

重述問題

我們可以對問題進行輕微修改,將其拆分為盡可能少的部分,每個部分最多包含b條記錄。 使得每個部分的長度滿足a <= len(s) <= a+1

請注意,在這種情況下,我們將ab最接近,以便問題有解決方案。 對於可解決的問題,解決方案將是原始問題的解決方案,對於無法解決的問題,它將通過減少a來修改原始需求,以便問題可以解決。

上面的示例將變為: 在不超過 15 個元素的盡可能少的平衡組中拆分 19 個元素。 然后解決方案是包含 10 個元素的部分和 9 個元素的部分。

一個pythonic的解決方案

def group_and_split(df, b, column):
    '''
    - df    : a datafame
    - b     : the largest allowed section
    - column: the column by which the data must be grouped
    '''
    
    # doing it in a pythonic way
    return [np.array_split(y, (len(y)+b-1)//b)
             for x, y in df.groupby(column, as_index=False)]

您可以檢查它是否為重述的問題提供了解決方案

pd.DataFrame([{
    'num-sections': len(g), 
    'largest-section': max(len(gi) for gi in g), 
    'smallest-sections':min(len(gi) for gi in g)
} for g in group_and_split(df, 25, 'D')])

暫無
暫無

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

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