将行拆分为多行,同时平均分配某些值并保持某些静态值

时间:2019-02-11 16:23:04

标签: python algorithm split

我有一个JSON格式的表(字典列表),其中每一行都是一个字典。

为简单起见,我要这样一行:

{
    'dimension1': 'foo',
    'dimension2': 'bar',
    'metric1': 102,
    'metric2': 200
}

我想知道是否有一种简单的方法(也许使用熊猫或其他任何python工具)将该行拆分为给定数量的n行,其中:

  1. 尺寸将保持不变。
  2. 指标值将在所有行中平均分配。
  3. 所有指标均为int,应保留为int
  4. 总和应等于原始行。

例如,如果为n = 4,则上一行的输出应为:

[{
    'dimension1': 'foo',
    'dimension2': 'bar',
    'metric1': 25,
    'metric2': 50
},{
    'dimension1': 'foo',
    'dimension2': 'bar',
    'metric1': 25,
    'metric2': 50
},{
    'dimension1': 'foo',
    'dimension2': 'bar',
    'metric1': 26,
    'metric2': 50
},{
    'dimension1': 'foo',
    'dimension2': 'bar',
    'metric1': 26,
    'metric2': 50
}]

我试图寻找一种使用pandas或其他工具进行此操作的方法,但是找不到一种方法来给出一组应保持静态的维度和一组应拆分的指标同时保持总和。

希望这很清楚。我知道可以明确地编写此逻辑,但想知道是否有我缺少的更简单,更强大的方法。

2 个答案:

答案 0 :(得分:1)

可能不是最干净的一种,但可以使用np.histrogram将值转换为bins来尝试

def value_to_bins(df_value,n):
    value=np.arange(df_value, dtype=int)
    return np.histogram(value, bins=n)[0]

import pandas as pd
import numpy as np
d={
    'dimension1': 'foo',
    'dimension2': 'bar',
    'metric1': 101,
    'metric2': 200
}
df=pd.DataFrame(d,index=[0])
n=2

df2=pd.DataFrame(index=range(n),columns=['dimension1','dimension2']) # create new dataframe with NaN
df2.dimension1=df2.dimension1.fillna(df.dimension1[0]) # fill with values of previous dimension1
df2.dimension2=df2.dimension2.fillna(df.dimension2[0]) # fill with values of previous dimension2

df2['metric1'] = value_to_bins(df.metric1[0],n)
df2['metric2'] = value_to_bins(df.metric2[0],n)
df2.to_dict('records')

输出

[{'dimension1': 'foo', 'dimension2': 'bar', 'metric1': 50L, 'metric2': 100L},
 {'dimension1': 'foo', 'dimension2': 'bar', 'metric1': 51L, 'metric2': 100L}]

要保留int

[{k:int(v) if v!=np.nan and k in ['metric1','metric2']  else v for k,v in i.items() } for i in df2.to_dict('records')]

输出

[{'dimension1': 'foo', 'dimension2': 'bar', 'metric1': 50, 'metric2': 100},
 {'dimension1': 'foo', 'dimension2': 'bar', 'metric1': 51, 'metric2': 100}]

答案 1 :(得分:0)

您可以使用下层和列表理解以及字典理解: 想法是计算层,然后将每个元素的提醒除以1并共享,以使每个元素尽可能接近,例如假设102n=4我们有reminder=2,则结果为:{ {1}}

25+1,25+1,25,25

输出(n = 4):

import math

data={
'dimension1': 'foo',
'dimension2': 'bar',
'metric1': 102,
'metric2': 203
}
#finds all keys with integer values
division_fields=[k for k,v in data.items() if str(v).isdigit()]
values={}
n=4
#creates a list with desired  values for each numeric field
#and diveds reminder betweens elements of list by 1 foreach element 
for  field in division_fields:
    values[field]= [math.floor(data[field]/n) if i+1>data[field]%n else math.floor(data[field]/n)+1 for i in range(0,n)]

result=[{k:values[k][i] if k in division_fields else v for k,v in data.items() } for i in range(0,n)]

print (result)