我有以下数据框:
public boolean doSomething(MyEnum param1Enum, String param2){
...
String param1 = param1Enum.getString();
}
每次V1的总和达到50k时,我需要得到索引。因此,当值V1大于50k的限制时,则索引重复达到限制的次数,或者如果值V1低于50k的限制,则将行分组直到达到或超过50k的限制。结果将是这样的:
V1
1 100000
2 50000
3 20000
4 30000
5 150000
6 30000
7 20000
8 200000
我设法用循环来解决它,但我想知道是否可以使用具有pandas功能的分组。
答案 0 :(得分:1)
在你用
提供的例子中df = pd.DataFrame({'V1':[100000,50000, 20000, 30000,
150000, 30000, 20000, 200000]},
index=range(1,9))
我所理解的“获取每次V1的总和达到50k的索引”,你可以通过创建一个数字恰好为50k的列来实现直到每一行:
ser_50k = (df.V1.cumsum()/50000).astype(int)
df['nb_50'] = (ser_50k - ser_50k.shift()).fillna(ser_50k).astype(int)
现在,当50k达到多次时,您可以使用stack
创建具有相同索引的行:
df_join = (df['nb_50'].apply(lambda x: pd.Series(range(x)))
.stack().reset_index(level=1).drop('level_1',1))
df = df.join(df_join).dropna().drop(['nb_50',0],1)
您可以使用输入示例获得预期的输出。
问题是,当你有
时df= pd.DataFrame({'V1':[180000, 20000, 30000, 50000]})
我的方法为您提供:
V1
0 180000
0 180000
0 180000
1 20000
3 50000
并且稍后可能会发生一些错误,而当您说“当值V1大于50k的限制时,则索引会重复达到限制的次数,或者如果值V1低于达到50k的限制,将行数分组直到达到或超过50k的限制“我理解你会期望:
V1
0 180000
0 180000
0 180000
2 30000
3 50000
在这种情况下,如果您不想使用循环,当数字高于50K时,您可以这样做(与以前的想法大致相同):
df = df.join(df['V1'].apply(lambda x: pd.Series(range(x/50000)))
.stack().reset_index(level=1).drop('level_1',1)).drop(0,1)
但我无法找到一个简单的方法来处理数字小于50k的情况,因此你的循环for
可能已经足够了。否则,我想到了这个方式:
def nb_group_under(v1):
global nb_group
if v1 < 50000:
return nb_group
else:
nb_group += 1
nb_group = 1
df['under_50'] = df['V1'].apply(nb_group_under)
然后你试图找到在创建的组中传递50k的位置:
df['sum_under50'] = (df.groupby('under_50').V1.cumsum()/50000).astype(int)
df['sum_under50'] = df.sum_under50 - (df.groupby('under_50').sum_under50
.shift().fillna(df.sum_under50))
df = (df[(df['sum_under50']>0) | (df['V1'] >= 50000)]
.drop(['under_50', 'sum_under50'],1))
我对50岁以下的案件的方法并不特别满意,但却想不到另一种方式。
希望无论如何它是有用的,或者给你一些关于如何在没有循环的情况下解决问题的想法
编辑:对于更通用的解决方案,你可以创建一个函数,返回50k在值v1中的时间,或者在50k以上时返回1的部分和,你还需要一个全局变量:
def nb_lim_reached (v1, lim_v1):
global partial_sum
if v1 >= lim_v1:
partial_sum = 0
return pd.np.floor(v1/lim_v1)
else:
partial_sum += v1
if partial_sum >= lim_v1:
partial_sum -= lim_v1
return 1
else:
return 0
现在您可以使用此功能创建另一列:
v1_lim = 50000
partial_sum = 0
df['nb_lim'] = df['V1'].apply(nb_lim_reached, args=( v1_lim,)).astype(int)
现在,您使用与pd.Series
和stack
的reviosu解决方案相同的想法:
df = (df.join(df['nb_lim'].apply(lambda nb: pd.Series(range(nb)))
.stack().reset_index(level=1).drop('level_1',1))
.dropna().drop(['nb_lim',0],1))