使用列中的先前值和pandas

时间:2017-07-18 15:42:32

标签: python pandas

我的数据框如下所示:

   scale  cons    hold    supply   add.supply     s_res      z_res
48  -5     NaN    NaN      NaN       NaN           NaN        NaN   
49  -4     NaN    NaN      NaN       NaN           NaN        NaN   
50  -3     NaN    NaN      NaN       NaN           NaN        NaN   
51  -2     NaN    NaN      NaN       NaN           NaN        NaN   
52  -1     NaN    NaN      NaN       NaN           NaN        NaN   
53   0      0     300       0        NaN           100        200   
54   1     20     NaN       0        NaN           200        322   
55   2     30     NaN      70        NaN           100        100   
56   3     25     NaN       0        NaN           400        110   
57   4     15     NaN       0        NaN           100        300   
58   5     10     NaN       0        NaN           100        180   
59   6     40     NaN       0        NaN           100        100   
...

我需要做以下事情:

scale = 1填充列hold的值开始,其值按如下方式计算:

我从列hold中取出先前的值,并从列cons中减去当前单元格的相应值,并从列supply中添加相应的值。

(对于与hold对应的列scale = 1中的单元格,它将为(300 - 20) + 0 = 280, 下一个单元格(280 - 30) + 70) = 320,下一个单元格(320 - 25) + 0) = 295等等

如果列hold中的值小于列s_res中的对应值,则对于下一个单元格,我必须在列{{{}}中添加相应的下一个单元格值之间的差异1}}和s_res

例如,列z_res中的值为hold,其中295。该值小于列scale = 3中的值。然后我需要计算下一个值:s_res = 400。并在(295 - 15) + 0 + (300 - 100) = 480列中的s_resz_res之间写下这种区别。

我需要列add.supply中的每个新计算值检查它是否小于hold列中的值。

结果应如下所示:

s_res

我很感激任何建议。

UPD 我尝试应用代码

   scale  cons    hold    supply   add.supply     s_res      z_res
48  -5     NaN    NaN      NaN       NaN           NaN        NaN   
49  -4     NaN    NaN      NaN       NaN           NaN        NaN   
50  -3     NaN    NaN      NaN       NaN           NaN        NaN   
51  -2     NaN    NaN      NaN       NaN           NaN        NaN   
52  -1     NaN    NaN      NaN       NaN           NaN        NaN   
53   0      0     300       0        NaN           100        200   
54   1     20     280       0        NaN           200        322   
55   2     30     320      70        NaN           100        100   
56   3     25     295       0        NaN           400        110   
57   4     15     480       0        200           100        300   
58   5     10     470       0        NaN           100        180   
59   6     40     430       0        NaN           100        100   
...

更大的数据框,我遇到了问题

我的新数据框

df['hold'] = df.hold.fillna(method='ffill') - df.cons.cumsum() + df.supply.cumsum()
df['add.supply'] = np.where(df.hold.shift() < df.s_res.shift(), df.z_res - df.s_res, np.nan)
df['hold'] = df.hold + df['add.supply'].fillna(0).cumsum()

结果应如下:

   scale   cons   hold  supply  add.supply   s_res   z_res
 0   0       0    300     0        NaN        100     200
 1   1      20    NaN     0        NaN        200     322
 2   2      30    NaN    70        NaN        100     100
 3   3      25    NaN     0        NaN        400     110
 4   4      15    NaN     0        NaN        100     300
 5   5      10    NaN     0        NaN        100     180
 6   6      40    NaN     0        NaN        100     100
 7   7      60    NaN     0        NaN        300     400
 8   8      50    NaN     0        NaN        245     300
 9   9      70    NaN     0        NaN        300     600
10  10      50    NaN     0        NaN        143     228
...

但代码执行的结果并非如此:

   scale   cons   hold  supply  add.supply   s_res   z_res
 0   0       0    300     0        NaN        100     200
 1   1      20    280     0        NaN        200     322
 2   2      30    320    70        NaN        100     100
 3   3      25    295     0        NaN        400     110
 4   4      15    480     0        200        100     300
 5   5      10    470     0        NaN        100     180
 6   6      40    430     0        NaN        100     100
 7   7      60    370     0        NaN        300     400
 8   8      50    320     0        NaN        245     300
 9   9      70    250     0        NaN        300     600
10  10      50    285     0         85        143     228
...

scale cons hold supply add.supply s_res z_res 0 0 0 300 0 NaN 100 200 1 1 20 280 0 NaN 200 322 2 2 30 320 70 NaN 100 100 3 3 25 295 0 NaN 400 110 4 4 15 480 0 200 100 300 5 5 10 470 0 NaN 100 180 6 6 40 430 0 NaN 100 100 7 7 60 370 0 NaN 300 400 8 8 50 375 0 55 245 300 9 9 70 605 0 300 300 600 10 10 50 640 0 85 143 228 ... 后出现错误,但我不明白为什么。

1 个答案:

答案 0 :(得分:2)

您可以使用cumsum()np.where的组合在整个DataFrame中执行此操作,而不是逐行执行此操作:

df['hold'] = df.hold.fillna(method='ffill') - df.cons.cumsum() + df.supply.cumsum()
df['add.supply'] = np.where(df.hold.shift() < df.s_res.shift(), df.z_res - df.s_res, np.nan)
df['hold'] = df.hold + df['add.supply'].fillna(0).cumsum()

想想你想分两个阶段做的转变。您有一个初始阶段,您正在添加和减去初始值df.hold。然后,根据某些条件,你在某些情况下改变了新的持有价值。

cumsum()采用Series或DataFrame并创建一个新版本,其中每一行是前一行和当前行的累积和。您可以对df.consdf.supply执行此操作,以获取将从df.hold中扣除并添加到df.hold的累计金额。现在您已经计算了np.where的第一阶段。

您可以使用df.hold查找df['add.supply']何时符合您感兴趣的条件。如果符合您的条件,您可以相应地设置df.hold。然后,您可以将此新列添加到fillna(0)。请注意,我们使用cumsum()确保每一行都有一个值,并再次使用add.supply来保留添加的条件值。

<强>更新

上面的原始代码在添加一个df.hold值后无效,因为df['hold'] = df.hold.fillna(method='ffill') - df.cons.cumsum() + df.supply.cumsum() hold = df.hold.tolist() s_res = df.s_res.tolist() add = (df.z_res - df.s_res).shift(-1).tolist() newh = [hold[0]] totala = 0 for h, s, a in zip(hold, s_res, add): newh.append(h + totala) if newh[-1] < s: totala += a df['hold'] = pd.Series(newh[1:]) df['add.supply'] = np.where(df.hold.shift() < df.s_res.shift(), df.z_res - df.s_res, np.nan) 的第一阶段的未来值尚未包含它。可能有一种方法可以非迭代地执行此操作,并且肯定比我在下面所做的更好更清洁,但这至少可以完成工作:

function multiRequest($data, $options = array()) {

  // array of curl handles
  $curly = array();
  // data to be returned
  $result = array();

  // multi handle
  $mh = curl_multi_init();

  // loop through $data and create curl handles
  // then add them to the multi-handle
  foreach ($data as $id => $d) {

    $curly[$id] = curl_init();

    $url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d;
    curl_setopt($curly[$id], CURLOPT_URL,            $url);
    curl_setopt($curly[$id], CURLOPT_HEADER,         0);
    curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1);

    // post?
    if (is_array($d)) {
      if (!empty($d['post'])) {
        curl_setopt($curly[$id], CURLOPT_POST,       1);
        curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']);
      }
    }

    // extra options?
    if (!empty($options)) {
      curl_setopt_array($curly[$id], $options);
    }

    curl_multi_add_handle($mh, $curly[$id]);
  }

  // execute the handles
  $running = null;
  do {
    curl_multi_exec($mh, $running);
  } while($running > 0);


  // get content and remove handles
  foreach($curly as $id => $c) {
    $result[$id] = curl_multi_getcontent($c);
    curl_multi_remove_handle($mh, $c);
  }

  // all done
  curl_multi_close($mh);

  return $result;
}