代码之家  ›  专栏  ›  技术社区  ›  A. Sarid arch

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

  •  1
  • A. Sarid arch  · 技术社区  · 6 年前

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

    简单地说,我有这样一行:

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

    我想知道是否有一种简单的方法(可能使用pandas或任何其他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 回复  |  直到 6 年前
        1
  •  1
  •   mad_    6 年前

    可能不是最干净的,但可以用一下 np.histrogram 将值转换为容器

    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}]
    
        2
  •  0
  •   Mehrdad Dowlatabadi    6 年前

    您可以使用楼层和列表理解和字典理解: IDEA是计算楼层,然后将每个元素的提醒除以1,以尽可能多地包含关闭元素,例如假设 102 n=4 我们有 reminder=2 ,结果是: 25+1,25+1,25,25

    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)
    

    输出(n=4时):

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