在大熊猫数据框中,我有多个具有不同且大量行的子组。我想减少用于初步分析的行数,同时确保数据在整个范围内仍然具有代表性。
我使用2个因子或参数('A','B'
)和每个因子2个水平或值('A1','A2','B1','B2'
)进行了仿真。每个模拟对应于'A','B'
值的组合。计数器超过定义的数字(在下面的示例中为“ 35”)之后,模拟停止。
对于每个模拟,计数器及其增加都是不同的。并且在每个步骤中,从模拟中总结出一个值'eval'
。
下面的示例显示了模拟结果的示例。现在,该模拟实际上运行了更长的时间(例如,直到达到10000以上),并且在我的初步分析中需要花几个小时来绘制eval
值的变化。
此代码生成模拟结果的示例:
import pandas as pd
import numpy as np
columns = ['FactorA', 'FactorB', 'step']
data = [['A1', 'B1', 8], ['A1', 'B1', 13], ['A1', 'B1', 18], ['A1', 'B1', 23], ['A1', 'B1', 28], ['A1', 'B1', 33], ['A1', 'B1', 38],
['A1', 'B2', 7], ['A1', 'B2', 13],['A1', 'B2', 19],['A1', 'B2', 25],['A1', 'B2', 31],['A1', 'B2', 37],
['A2', 'B1', 6], ['A2', 'B1', 14],['A2', 'B1', 22],['A2', 'B1', 30],['A2', 'B1', 38],
['A2', 'B2', 10], ['A2', 'B2', 12],['A2', 'B2', 14],['A2', 'B2', 16],['A2', 'B2', 18],['A2', 'B2', 20],['A2', 'B2', 22],['A2', 'B2', 24],['A2', 'B2', 26],['A2', 'B2', 28],['A2', 'B2', 30],['A2', 'B2', 32],['A2', 'B2', 34],['A2', 'B2', 36]
]
df = pd.DataFrame(data, columns=columns)
df['eval'] = np.random.randint(1, 6, df.shape[0])
我尝试过此方法,但是虽然它减少了数据点,但并不能平衡每次模拟的数据点数量:
df_reduced = df.iloc[::2]
也尝试过:
df_reduced = df.sample(n=int(len(df)/6))
但是它也不能平衡每次模拟的数据点数量。
我想要一个每个子组具有相同行数的DataFrame。
为了确保选择或采样平衡,我希望使用.iloc
的每个子组的切片考虑确保每个子组选择'n'
个成员的步骤。
最好包括每个子组的第一行和最后一行。
答案 0 :(得分:0)
请查看帖子中的以下说明:
df.sample(n=int(len(df)))
这里有什么奇怪的地方
关于组平衡:
确定如何保持平衡:
下定决心:
groupby
源DataFrame,示例:如果要从 df 中进行选择,请从中选择 2 行的示例 每个组(选项1),运行:
df.groupby(['FactorA', 'FactorB']).apply(lambda grp: grp.sample(n=2))
如果要返回原始(单级)索引,请添加:
.reset_index(level=[0, 1], drop=True)
上述说明。
如果您喜欢选项2(分数),请将 n = ... 更改为 frac = ... 。
答案 1 :(得分:0)
在@Valdi_Bo回答之后,我转到Group By: split-apply-combine上的页面,并在here,here,here,here,和here得到一个非优雅但可行的解决方案。
对于示例中的数据框,我们可以计算每组的行数:
grouped = df.groupby(['FactorA','FactorB'])
grouped.size()
这将产生:
FactorA FactorB
A1 B1 7
B2 6
A2 B1 5
B2 14
dtype: int64
为了将每个组的数据行减少到一个以上但接近三的数字,并且每个子组的step
列中的值之间具有相等的间距,并强制包含最大的step
,我使用:
def filter_group(dfg, col, qty):
col_min = dfg[col].min()
col_max = dfg[col].max()
col_length = dfg[col].size
jumps = col_length-1
jump_size = int((col_max - col_min) / jumps)
new_jump_size = jumps/qty
if new_jump_size > 1:
new_jump_size = int(new_jump_size)*jump_size
else:
new_jump_size = jump_size
col_select = list(range(col_min, col_max, new_jump_size))
col_select.append(col_max)
return dfg[dfg[col].isin(col_select)]
grouped = df.groupby(['FactorA','FactorB'], group_keys=False).apply(lambda x: filter_group(x,'step',3))
我们可以验证演示数据框的行数:
grouped = grouped.groupby(['FactorA','FactorB'])
grouped.size()
这将产生:
FactorA FactorB
A1 B1 4
B2 6
A2 B1 5
B2 5
dtype: int64
如果有时间,我会尝试的,并将其修改为使用具有与steps
列范围相关的权重的样本函数时发布。这样我从范围的前三分之一获得了一半的数据点。