Panel Data Processing with paneldesc

Dmitrii Tereshchenko

2026-07-21

Although the paneldesc package is primarily focused on descriptive analysis and panel data exploration, it also includes a set of functions for processing panel data. It may be relevant because sometimes data transformations are necessary for full analysis. This vignette presents the main capabilities of the paneldesc package for processing panel data.

Loading the package

Load the package.

library(paneldesc)

Data import

The package includes a simulated dataset called production.

data(production)

It contains information on 30 firms over up to 6 years, with variables such as sales, capital, labor, industry, ownership, and region. Missing values are present in some variables to mimic real‑world data.

str(production)
#> 'data.frame':    180 obs. of  8 variables:
#>  $ firm     : int  1 1 1 1 1 1 2 2 2 2 ...
#>  $ year     : int  1 2 3 4 5 6 1 2 3 4 ...
#>  $ sales    : num  33 38.7 39 31.6 NA ...
#>  $ capital  : num  6.29 5.03 6.82 17.94 NA ...
#>  $ labor    : num  49.7 65.1 73.9 26.9 NA ...
#>  $ industry : Factor w/ 3 levels "Industry 1","Industry 2",..: 3 3 3 3 NA NA 3 3 2 2 ...
#>  $ ownership: Factor w/ 3 levels "private","public",..: 1 1 1 1 NA NA 2 2 2 3 ...
#>  $ region   : Factor w/ 4 levels "west","east",..: 1 1 1 1 NA NA 4 4 4 4 ...

To avoid repeatedly specifying the entity and time variables (firm and year), we create a panel_data object using make_panel(). This adds metadata that many subsequent functions will automatically use.

panel <- make_panel(production, index = c("firm", "year"))

Creating balanced panel data

make_balanced() allows to balance panel data using various options:

balance_entities <- make_balanced(panel, balance = "entities")
dim(balance_entities)
#> [1] 96  8
balance_periods <- make_balanced(panel, balance = "periods")
dim(balance_periods)
#> [1] 30  8
balance_rows <- make_balanced(panel, delta = 1, balance = "rows")
dim(balance_rows)
#> [1] 180   8

In the latter case, the returned data frame is the same as the original one.

Reshaping panel data

A standard type of panel data transformation is reshaping from long format to wide format and vice versa.

Note that region variable is time-invariant, while other variables are time-varying. For reuse, we first create a vector with names of variables to be reshaped (everything except static variables and panel identifiers).

vars <- c("sales", "capital", "labor", "industry", "ownership")

Since the original data frame is presented in long format, we can reshape it to wide format using make_wide().

panel_wide <- make_wide(panel, select = vars)
#>   Static variables: region 
#> Reshaped variables: sales_1, sales_2, sales_3, sales_4, sales_5, sales_6 
#>                     capital_1, capital_2, capital_3, capital_4, capital_5, capital_6 
#>                     labor_1, labor_2, labor_3, labor_4, labor_5, labor_6 
#>                     industry_1, industry_2, industry_3, industry_4, industry_5, industry_6 
#>                     ownership_1, ownership_2, ownership_3, ownership_4, ownership_5, ownership_6

Next, as an exercise, we can convert the wide format data we just obtained back to long format.

panel_long <- make_long(panel_wide, select = vars)
#>   Static variables: region 
#> Reshaped variables: sales, capital, labor, industry, ownership

In the latter case, the data frame is the same as the original one.

Within-group demeaning

make_demeaned() performs within-group demeaning (centering) for all numeric variables in a data frame.

demeaned <- make_demeaned(panel)
#> Demeaning numeric variables: sales, capital, labor

The returned dataframe has the same structure as the original one, but its numeric variables are transformed. The resulting dataframe can be used for descriptive analysis of the transformed data or for regression analysis.

summary(demeaned)
#>       firm           year         sales             capital       
#>  Min.   : 1.0   Min.   :1.0   Min.   :-75.9166   Min.   :-58.719  
#>  1st Qu.: 8.0   1st Qu.:2.0   1st Qu.:-22.7824   1st Qu.:-17.756  
#>  Median :15.5   Median :3.5   Median : -0.6208   Median : -2.802  
#>  Mean   :15.5   Mean   :3.5   Mean   :  0.0000   Mean   :  0.000  
#>  3rd Qu.:23.0   3rd Qu.:5.0   3rd Qu.: 16.3642   3rd Qu.:  8.911  
#>  Max.   :30.0   Max.   :6.0   Max.   :163.1807   Max.   :110.610  
#>                               NA's   :26         NA's   :26       
#>      labor                industry    ownership    region  
#>  Min.   :-130.319   Industry 1:63   private:80   west :38  
#>  1st Qu.: -31.447   Industry 2:45   public :36   east :40  
#>  Median :  -8.731   Industry 3:49   mixed  :41   north:36  
#>  Mean   :   0.000   NA's      :23   NA's   :23   south:43  
#>  3rd Qu.:  17.989                                NA's :23  
#>  Max.   : 401.908                                          
#>  NA's   :26

Adding group means

add_means() adds group means of numeric variables to a data frame, which can be used for Mundlak-style (correlated random effects) modeling or for other purposes where within-group averages are needed.

panel_means <- add_means(panel)
#> Adding group means for numeric variables: sales, capital, labor
names(panel_means)
#>  [1] "firm"              "year"              "sales"            
#>  [4] "capital"           "labor"             "industry"         
#>  [7] "ownership"         "region"            "sales_mean_firm"  
#> [10] "sales_mean_year"   "capital_mean_firm" "capital_mean_year"
#> [13] "labor_mean_firm"   "labor_mean_year"