As Paul has pointed out in #2, Daniel Feenberg observed years ago that reshape long is inexplicably slow with larger datasets. To illustrate his point, he showed a technique that is significantly faster at performing a reshape to long form. The reason why reshape long is much slower was left to speculation. If you scan the code for reshape long, you find the following:
The code loops over variables to reshape to long form. At each pass, it reloads the whole original wide dataset, fetches the i j id variables and the variable to append (Longdo), and then performs an append and save cycle. As I have pointed out regularly to file appenders on Statalist, such a loop if very inefficient because the file that is constantly saved grows at each pass. Here's an example to illustrate just the I/O involved:
So reshape long is slower than needed because it uses two inefficient ways to get there. If you play with the parameters of the example, e.g. increase the number of variables by a factor of 10, then you get
So the I/O grows by a factor of 10 with Daniel's approach while the I/O with reshape long grows by a factor of 100.
Code:
while "`1'"!="" { restore, preserve noisily Longdo `1' append using "`new'" save "`new'", replace mac shift }
Code:
. * the width of i and j vars in bytes . local ij 12 . . * the width of ij vars and 1 variable to reshape . local ijvars = `ij' + 4 . . * the number of vars to reshape long . local nvars 100 . . * the number of observations . local nobs 10000 . . * the size of the original dataset . local dta = (`ij' + `nvars' * 4) * `nobs' . dis "size of data in MB = " `dta' / 1e6 size of data in MB = 4.12 . . * the size of the saved dataset after each pass . clear . set obs `nvars' number of observations (_N) was 0, now 100 . gen saved_size = sum(`nobs' * `ijvars') . . * the I/O required at each pass: . * 1. restore . * 2. append using the saved_size at that point . * 3. save it again . gen cumulative_io = sum(`dta' + saved_size[_n-1] + saved_size) . dis %20.0fc cumulative_io[_N] 2,007,719,936 . . * if you save each variable separately and then append them all . local pass1 = `nvars' * (`dta' + `nobs' * `ijvars') . local pass2 = `nvars' * `nobs' * `ijvars' . dis %20.0fc `pass1' + `pass2' 444,000,000 . . * Daniel Feenberg goes one further, the first pass loads just . * what's needed and then saves each variable separately . local pass1 = `nvars' * `nobs' * `ijvars' * 2 . local pass2 = `nvars' * `nobs' * `ijvars' . dis %20.0fc `pass1' + `pass2' 48,000,000
Code:
. dis %20.0fc cumulative_io[_N] 200,079,720,448 . dis %20.0fc `pass1' + `pass2' 480,000,000
Comment