【问题标题】:Maintaining a ratio when splitting up data in python function在python函数中拆分数据时保持比率
【发布时间】:2013-04-18 22:25:51
【问题描述】:

我有一些数据,我想将其分成保持共同比率的较小组。我写了一个函数,它将接受两个数组的输入并计算大小比,然后告诉我可以将它分成多少组的选项(如果所有组的大小相同),这里是函数:

def cross_validation_group(train_data, test_data):
    import numpy as np
    from calculator import factors
    test_length = len(test_data)
    train_length = len(train_data)
    total_length = test_length + train_length
    ratio = test_length/float(total_length)
    possibilities = factors(total_length)
    print possibilities
    print possibilities[len(possibilities)-1] * ratio
    super_count = 0
    for i in possibilities:
        if i < len(possibilities)/2:
            pass
        else: 
            attempt = float(i * ratio)
            if attempt.is_integer():
                print str(i) + " is an option for total size with " +  str(attempt) + " as test size and " + str(i - attempt) + " as train size! This is with " + str(total_length/i) + " folds."
            else:
                pass
    folds = int(raw_input("So how many folds would you like to use? If no possibilities were given that would be sufficient, type 0: "))
    if folds != 0:
        total_size = total_length/folds
        test_size = float(total_size * ratio)
        train_size = total_size - test_size
        columns = train_data[0]
        columns= len(columns)
        groups = np.empty((folds,(test_size + train_size),columns))
        i = 0
        a = 0
        b = 0
        for j in range (0,folds):
            test_size_new = test_size * (j + 1)
            train_size_new = train_size * j
            total_size_new = (train_size + test_size) * (j + 1)
            cut_off = total_size_new - train_size
            p = 0
            while i < total_size_new:
                if i < cut_off:
                    groups[j,p] = test_data[a]
                    a += 1
                else:
                    groups[j,p] = train_data[b]
                    b += 1
                i += 1
                p += 1
        return groups
    else:
        print "This method cannot be used because the ratio cannot be maintained with equal group sizes other than for the options you were givens"

所以我的问题是我如何才能使函数的第三个输入成为折叠数并更改函数,而不是迭代以确保每个组具有相同的数量正确的比例,它只会有正确的比例,但大小不一?

@JamesHolderness 的补充

所以你的方法几乎是完美的,但这里有一个问题:

长度为 357 和 143,9 折,这是返回列表:

[(39, 16), (39, 16), (39, 16), (39, 16), (39, 16), (39, 16), (39, 16), (39, 16), (39, 16)]

现在,当您将列相加时,您会得到:351 144

351 很好,因为它小于 357,但 144 不起作用,因为它大于 143!原因是357和143是数组的长度,所以那个数组的第144行不存在……

【问题讨论】:

  • 您的意思是要使用不同的训练集进行交叉验证吗?这在统计上听起来有点不确定?在实践中通常会这样做吗?
  • 是的,这是用于交叉验证。不,这应该测试测试集和训练集之间的相似性,以检查测试数据中是否存在训练数据中没有的内容。通常交叉验证只在一个训练集上完成,这也可以应用于它们,而不是两个数组,你可以在训练数组和训练数组中给出列,它会这样做。
  • 如果您的两个数组的大小为mn,并且m 除以n 的不可约分数是p/q,那么m = k*pn = k*q。一旦您拥有k,其中的任何partition 都会引导您拆分原始数据以保持元素的比例。如果您需要我详细说明,请告诉我。
  • 啊,好古老的数论......不幸的是,这是有限的。我希望能够拥有任意数量的组,即使是一个不均分的组,因为只要一个数据集与另一个数据集的比率一致,大小就可以不同。这有意义吗?

标签: python function numpy


【解决方案1】:

这是一个我认为可能对你有用的算法。

您将 test_length 和 train_length 除以它们的 GCD,得到一个简单分数的比率。你把分子和分母加在一起,这就是你的组的大小因素。

例如如果比例是 3:2,那么每组的大小必须是 5 的倍数。

然后,您将总长度除以折叠数,以获得第一组的理想大小,这很可能是一个浮点数。您找到小于或等于 5 的最大倍数,这就是您的第一组。

从您的总数中减去该值,然后除以 folds-1 以获得下一组的理想尺寸。再次找到 5 的最大倍数,从总数中减去 ,然后继续,直到计算完所有组。

一些示例代码:

total_length = test_length + train_length          
divisor = gcd(test_length,train_length)
test_multiple = test_length/divisor
train_multiple = train_length/divisor
total_multiple = test_multiple + train_multiple 

# Adjust the ratio if there isn't enough data for the requested folds
if total_length/total_multiple < folds:
  total_multiple = total_length/folds
  test_multiple = int(round(float(test_length)*total_multiple/total_length))
  train_multiple = total_multiple - test_multiple

groups = []
for i in range(folds,0,-1):
  float_size = float(total_length)/i
  int_size = int(float_size/total_multiple)*total_multiple
  test_size = int_size*test_multiple/total_multiple
  train_size = int_size*train_multiple/total_multiple
  test_length -= test_size    # keep track of the test data used
  train_length -= train_size  # keep track of the train data used
  total_length -= int_size
  groups.append((test_size,train_size))

# If the test_length or train_length are negative, we need to adjust the groups
# to "give back" some of the data.
distribute_overrun(groups,test_length,0)
distribute_overrun(groups,train_length,1)

这已更新,以跟踪每个组(测试和训练)使用的大小,但如果我们最初使用过多也不必担心。

最后,如果有任何超支(即test_lengthtrain_length 变为负数),我们会通过在尽可能多的项目中减少比率的适当一侧来将超支分配回组中使溢出恢复为零。

distribute_overrun 函数包含在下面。

def distribute_overrun(groups,overrun,part):
    i = 0
    while overrun < 0:
      group = list(groups[i])
      group[part] -= 1
      groups[i] = tuple(group)
      overrun += 1
      i += 1

最后,groups 将是一个包含每个组的 test_size 和 train_size 的元组列表。

如果这听起来像你想要的,但你需要我扩展代码示例,请告诉我。

【讨论】:

  • 几乎完美!!!它在大多数情况下都很好用,唯一的问题是如果分数不能简化,它会将所有元组返回为(0,0),除了最后一个,它只是原始数字。如果比率不可能,我可以添加到函数中使其稍微打破比率的任何东西吗?
  • 开头还要加上total_length = train_length + test_length,你没有定义total_length
  • 我使用的是您原始代码中的total_length,但已将其添加到示例中以进行澄清。如果没有足够的数据,还使用一些额外的代码更新了答案以调整比率。我应该补充一点,如果您的数据没有除以请求的折叠数,那么您最终会留下一些数据。
  • 是的,我知道这一点,但不幸的是,并不是每两个数据集的折叠次数都适用。现在唯一错误的是,当它稍微重新调整数字和比率时,有时其中一个输出会增加一个比以前更大的总数。这将使用不存在的行。我一直在乱搞,但让它总是低于原来的样子似乎不起作用......
  • 我不确定我是否理解你。你能给出一些发生这种情况的示例值吗?我只是指 test_length、train_length 和折叠数。
【解决方案2】:

在另一个问题中,作者想进行与您类似的交叉验证。请take a look to this answer。找出问题的答案,就像:

import numpy as np
# in both train_data the first line is used for the cross-validation,
# and the other lines will follow, so you can add as many lines as you want
test_data = np.array([ 0.,  1.,  2.,  3.,  4.,  5.])
train_data  = np.array([[ 0.09,  1.9,  1.1,  1.5,  4.2,  3.1,  5.1],
                       [    3,    4,  3.1,   10,   20,    2,    3]])

def cross_validation_group( test_data, train_data):
    om1,om2 = np.meshgrid(test_data,train_data[0])
    dist = (om1-om2)**2
    indexes = np.argsort( dist, axis=0 )
    return train_data[:, indexes[0]]

print cross_validation_group( test_data, train_data )
# array([[  0.09,   1.1 ,   1.9 ,   3.1 ,   4.2 ,   5.1 ],
#        [     3 ,  3.1 ,     4 ,     2 ,    20 ,     3 ]])

您将拥有与test_data 中定义的间隔相对应的train_data

【讨论】:

  • 这根本不是我想要的......我的分组对于这样的事情很好,但我需要我的函数来获取另一个变量,该变量将是为数组和数组的大小可以不同,只要它们从训练数据到测试数据的比例相同
  • 所以我想我错过了你的意思。这个适用于不同的大小,但没有变量告诉组的数量(由您提供的 test_data 控制......
  • 基本上我需要另一个变量 x,其中 x = 组数。行数可以不同,但​​在每一组中,来自 test_data 的行和来自训练数据的行的比率必须相同。这样交叉验证就没有偏见了
  • 您能否提供输入文件或变量以便我们使用它? (使用 Dropbox 之类的东西很方便)
  • 这对任何类型的数据都有效,这一点非常重要。所以我会说只需放入 2 个 numpy 数组,一个全为 1,另一个全为 0,每个数组都有相同数量的列,并且像这样乱七八糟!它还可以很容易地看到它正在混合来自单独数组的行
猜你喜欢
  • 2019-03-07
  • 1970-01-01
  • 2015-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-07
  • 1970-01-01
相关资源
最近更新 更多