Repository: statsmodels/statsmodels

Issue:
DynamicFactorMQ is not working 
I am running [this example](https://www.chadfulton.com/topics/statespace_large_dynamic_factor_models.html) 

In the past I had no problems replicating tis example. Now it seems has something changed and I get the following errors when I  try to create the DFM object: 

```

# Construct the dynamic factor model
model = sm.tsa.DynamicFactorMQ(
    endog_m, endog_quarterly=endog_q,
    factors=factors, factor_orders=factor_orders,
    factor_multiplicities=factor_multiplicities)


```
```

Traceback (most recent call last):
  File "/Users/safishajjouz/opt/anaconda3/envs/myport_management_env/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3378, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-55-40928c00cd95>", line 2, in <module>
    model = sm.tsa.DynamicFactorMQ(
  File "/Users/safishajjouz/opt/anaconda3/envs/myport_management_env/lib/python3.8/site-packages/statsmodels/tsa/statespace/dynamic_factor_mq.py", line 1320, in __init__
    s = self._s = DynamicFactorMQStates(
  File "/Users/safishajjouz/opt/anaconda3/envs/myport_management_env/lib/python3.8/site-packages/statsmodels/tsa/statespace/dynamic_factor_mq.py", line 443, in __init__
    self.factor_block_orders.append(default_block_orders))
  File "/Users/safishajjouz/opt/anaconda3/envs/myport_management_env/lib/python3.8/site-packages/pandas/core/generic.py", line 5989, in __getattr__
    return object.__getattribute__(self, name)
AttributeError: 'Series' object has no attribute 'append'
```

Discussion:

Patch:
diff --git a/statsmodels/tsa/statespace/dynamic_factor_mq.py b/statsmodels/tsa/statespace/dynamic_factor_mq.py
index 305fb2863..7caac527d 100644
--- a/statsmodels/tsa/statespace/dynamic_factor_mq.py
+++ b/statsmodels/tsa/statespace/dynamic_factor_mq.py
@@ -440,8 +440,8 @@ class DynamicFactorMQStates(dict):
                           tupleize_cols=False, name='block')
             default_block_orders = pd.Series(np.ones(len(ix), dtype=int),
                                              index=ix, name='order')
-            self.factor_block_orders = (
-                self.factor_block_orders.append(default_block_orders))
+            self.factor_block_orders = pd.concat(
+                [self.factor_block_orders, default_block_orders])
             factor_names = pd.Series(
                 np.concatenate(list(self.factor_block_orders.index)))
         duplicates = factor_names.duplicated()


Test patch:
diff --git a/statsmodels/tsa/statespace/tests/test_dynamic_factor_mq.py b/statsmodels/tsa/statespace/tests/test_dynamic_factor_mq.py
index 683ec3102..ff6d6012a 100644
--- a/statsmodels/tsa/statespace/tests/test_dynamic_factor_mq.py
+++ b/statsmodels/tsa/statespace/tests/test_dynamic_factor_mq.py
@@ -425,6 +425,78 @@ def test_factor_order_gt1():
     assert_allclose(mod['state_cov'], desired)
 
 
+def test_factor_order_12():
+    # Includes 2 monthly and 2 quarterly series
+    # This case: factors= 2, factor_orders=(1,2), idiosyncratic_ar1=True
+
+    # Create the datasets
+    index_M = pd.period_range(start='2000', periods=12, freq='M')
+    index_Q = pd.period_range(start='2000', periods=4, freq='Q')
+
+    dta_M = pd.DataFrame(np.zeros((12, 2)), index=index_M,
+                         columns=['M0', 'M1'])
+    dta_Q = pd.DataFrame(np.zeros((4, 2)), index=index_Q, columns=['Q0', 'Q1'])
+    # Add some noise so the variables aren't constants
+    dta_M.iloc[0] = 1.
+    dta_Q.iloc[1] = 1.
+
+    # Create the model instance
+    mod = dynamic_factor_mq.DynamicFactorMQ(
+        dta_M, endog_quarterly=dta_Q, factors=2, factor_orders={'0': 2},
+        idiosyncratic_ar1=True)
+
+    # Test dimensions
+    assert_equal(mod.k_endog, 2 + 2)
+    assert_equal(mod.k_states, 5 * 2 + 2 + 2 * 5)
+    assert_equal(mod.ssm.k_posdef, 2 + 2 + 2)
+
+    # Test names
+    assert_equal(mod.endog_names, ['M0', 'M1', 'Q0', 'Q1'])
+    desired = (['0', 'L1.0', 'L2.0', 'L3.0', 'L4.0', '1',
+                'L1.1', 'L2.1', 'L3.1', 'L4.1'] +
+               ['eps_M.M0', 'eps_M.M1', 'eps_Q.Q0', 'eps_Q.Q1'] +
+               ['L1.eps_Q.Q0', 'L1.eps_Q.Q1'] +
+               ['L2.eps_Q.Q0', 'L2.eps_Q.Q1'] +
+               ['L3.eps_Q.Q0', 'L3.eps_Q.Q1'] +
+               ['L4.eps_Q.Q0', 'L4.eps_Q.Q1'])
+    assert_equal(mod.state_names, desired)
+    desired = [
+        'loading.0->M0', 'loading.1->M0', 'loading.0->M1', 'loading.1->M1',
+        'loading.0->Q0', 'loading.1->Q0', 'loading.0->Q1', 'loading.1->Q1',
+        'L1.0->0', 'L2.0->0', 'L1.1->1',
+        'fb(0).cov.chol[1,1]', 'fb(1).cov.chol[1,1]',
+        'L1.eps_M.M0', 'L1.eps_M.M1',
+        'L1.eps_Q.Q0', 'L1.eps_Q.Q1',
+        'sigma2.M0', 'sigma2.M1', 'sigma2.Q0', 'sigma2.Q1']
+    assert_equal(mod.param_names, desired)
+
+    # Test fixed elements of state space representation
+    assert_allclose(mod['obs_intercept'], 0)
+
+    assert_allclose(mod['design', :2, 10:12], np.eye(2))
+    assert_allclose(mod['design', 2:, 12:14], np.eye(2))
+    assert_allclose(mod['design', 2:, 14:16], 2 * np.eye(2))
+    assert_allclose(mod['design', 2:, 16:18], 3 * np.eye(2))
+    assert_allclose(mod['design', 2:, 18:20], 2 * np.eye(2))
+    assert_allclose(mod['design', 2:, 20:22], np.eye(2))
+    assert_allclose(np.sum(mod['design']), 20)
+
+    assert_allclose(mod['obs_cov'], 0)
+    assert_allclose(mod['state_intercept'], 0)
+
+    assert_allclose(mod['transition', 1:5, :4], np.eye(4))
+    assert_allclose(mod['transition', 14:22, 12:20], np.eye(2 * 4))
+    assert_allclose(np.sum(mod['transition']), 16)
+
+    assert_allclose(mod['selection', :2, :2], np.array([[1, 0], [0, 0]]))
+    assert_allclose(mod['selection', 4:6, :2], np.array([[0, 0], [0, 1]]))
+    assert_allclose(mod['selection', 10:12, 2:4], np.eye(2))
+    assert_allclose(mod['selection', 12:14, 4:6], np.eye(2))
+    assert_allclose(np.sum(mod['selection']), 6)
+
+    assert_allclose(mod['state_cov'], 0)
+
+
 def test_k_factors_gt1_factor_order_gt1():
     # Includes 2 monthly and 2 quarterly series
     # This case: kactors=2, factor_orders=6, idiosyncratic_ar1=True