Repository: Qiskit/qiskit

Issue:
Expose parameter_prefix to ZZFeatureMap
### What is the expected enhancement?

Currently, the `ZZFeatureMap` class inherits from `PauliFeatureMap` but the `parameter_prefix` cannot be set in the constructor.
https://github.com/Qiskit/qiskit-terra/blob/fe5acd4d15355a566a32ee63fb4a50771e5994d4/qiskit/circuit/library/data_preparation/zz_feature_map.py#L60-L68

Thus, when one wants to include more than one `ZZFeatureMap`s per quantum circuit, one needs to rebind the parameters by doing:
```
params_a = ParamVector(...) 
params_b = ParamVector(...) 
qc_a = fm.bind_parameters(params_a) 
qc_b = fm.bind_parameters(params_b)
``` 
Circuits with multiple feature maps are often used when employing data reuploading. If `parameter_prefix` would be exposed to `ZZFeatureMap`, the user could just initialise the different feature maps with distinct parameter prefixes and append them to the larger circuit without having to define/rebind additional parameter vectors.  Furthermore, `parameter_prefix` is already exposed to other forms such as `TwoLocal`, so by adding this feature, the code would become more consistent.



Discussion:
This seems very sensible to me.  Ideally it should take all the same arguments as `PauliFeatureMap`, since it's really a very thin wrapper around it.  Honestly, I'm not 100% sure why this exists as a class at all, and isn't just a loose function, but now that it exists, it's probably best to leave it as-is.
I guess we had these as separate classes in Aqua and when they came over to the circuit library they were preserved in a parallel structure. We had the Z and ZZ feature maps as these seemed most used, so they were more convenience, but the base class provided the ability to do more. Since its possible to use the base PauliFeatureMap class/circuit here directly, and provide your own parameter customization, one could also argue to keep these simpler. But if its decided to alter ZZFeatureMap to expose such a capability then I guess it should be replicated in the ZFeatureMap too.

Resolving patch:
diff --git a/qiskit/circuit/library/data_preparation/z_feature_map.py b/qiskit/circuit/library/data_preparation/z_feature_map.py
--- a/qiskit/circuit/library/data_preparation/z_feature_map.py
+++ b/qiskit/circuit/library/data_preparation/z_feature_map.py
@@ -77,6 +77,7 @@ def __init__(
         feature_dimension: int,
         reps: int = 2,
         data_map_func: Optional[Callable[[np.ndarray], float]] = None,
+        parameter_prefix: str = "x",
         insert_barriers: bool = False,
         name: str = "ZFeatureMap",
     ) -> None:
@@ -87,6 +88,7 @@ def __init__(
             reps: The number of repeated circuits. Defaults to 2, has a minimum value of 1.
             data_map_func: A mapping function for data x which can be supplied to override the
                 default mapping from :meth:`self_product`.
+            parameter_prefix: The prefix used if default parameters are generated.
             insert_barriers: If True, barriers are inserted in between the evolution instructions
                 and hadamard layers.
 
@@ -96,6 +98,7 @@ def __init__(
             paulis=["Z"],
             reps=reps,
             data_map_func=data_map_func,
+            parameter_prefix=parameter_prefix,
             insert_barriers=insert_barriers,
             name=name,
         )
diff --git a/qiskit/circuit/library/data_preparation/zz_feature_map.py b/qiskit/circuit/library/data_preparation/zz_feature_map.py
--- a/qiskit/circuit/library/data_preparation/zz_feature_map.py
+++ b/qiskit/circuit/library/data_preparation/zz_feature_map.py
@@ -63,6 +63,7 @@ def __init__(
         reps: int = 2,
         entanglement: Union[str, List[List[int]], Callable[[int], List[int]]] = "full",
         data_map_func: Optional[Callable[[np.ndarray], float]] = None,
+        parameter_prefix: str = "x",
         insert_barriers: bool = False,
         name: str = "ZZFeatureMap",
     ) -> None:
@@ -74,6 +75,7 @@ def __init__(
             entanglement: Specifies the entanglement structure. Refer to
                 :class:`~qiskit.circuit.library.NLocal` for detail.
             data_map_func: A mapping function for data x.
+            parameter_prefix: The prefix used if default parameters are generated.
             insert_barriers: If True, barriers are inserted in between the evolution instructions
                 and hadamard layers.
 
@@ -92,6 +94,7 @@ def __init__(
             entanglement=entanglement,
             paulis=["Z", "ZZ"],
             data_map_func=data_map_func,
+            parameter_prefix=parameter_prefix,
             insert_barriers=insert_barriers,
             name=name,
         )


Test patch:
diff --git a/test/python/circuit/library/test_pauli_feature_map.py b/test/python/circuit/library/test_pauli_feature_map.py
--- a/test/python/circuit/library/test_pauli_feature_map.py
+++ b/test/python/circuit/library/test_pauli_feature_map.py
@@ -19,7 +19,7 @@
 from ddt import ddt, data, unpack
 
 from qiskit.test.base import QiskitTestCase
-from qiskit.circuit import QuantumCircuit
+from qiskit.circuit import QuantumCircuit, Parameter, ParameterVector
 from qiskit.circuit.library import PauliFeatureMap, ZFeatureMap, ZZFeatureMap, HGate
 from qiskit.quantum_info import Operator
 
@@ -128,6 +128,54 @@ def test_zzfeaturemap_raises_if_too_small(self):
         with self.assertRaises(ValueError):
             _ = ZZFeatureMap(1)
 
+    def test_parameter_prefix(self):
+        """Test the Parameter prefix"""
+        encoding_pauli = PauliFeatureMap(
+            feature_dimension=2, reps=2, paulis=["ZY"], parameter_prefix="p"
+        )
+        encoding_z = ZFeatureMap(feature_dimension=2, reps=2, parameter_prefix="q")
+        encoding_zz = ZZFeatureMap(feature_dimension=2, reps=2, parameter_prefix="r")
+        x = ParameterVector("x", 2)
+        y = Parameter("y")
+
+        self.assertEqual(
+            str(encoding_pauli.parameters),
+            "ParameterView([ParameterVectorElement(p[0]), ParameterVectorElement(p[1])])",
+        )
+        self.assertEqual(
+            str(encoding_z.parameters),
+            "ParameterView([ParameterVectorElement(q[0]), ParameterVectorElement(q[1])])",
+        )
+        self.assertEqual(
+            str(encoding_zz.parameters),
+            "ParameterView([ParameterVectorElement(r[0]), ParameterVectorElement(r[1])])",
+        )
+
+        encoding_pauli_param_x = encoding_pauli.assign_parameters(x)
+        encoding_z_param_x = encoding_z.assign_parameters(x)
+        encoding_zz_param_x = encoding_zz.assign_parameters(x)
+
+        self.assertEqual(
+            str(encoding_pauli_param_x.parameters),
+            "ParameterView([ParameterVectorElement(x[0]), ParameterVectorElement(x[1])])",
+        )
+        self.assertEqual(
+            str(encoding_z_param_x.parameters),
+            "ParameterView([ParameterVectorElement(x[0]), ParameterVectorElement(x[1])])",
+        )
+        self.assertEqual(
+            str(encoding_zz_param_x.parameters),
+            "ParameterView([ParameterVectorElement(x[0]), ParameterVectorElement(x[1])])",
+        )
+
+        encoding_pauli_param_y = encoding_pauli.assign_parameters({1, y})
+        encoding_z_param_y = encoding_z.assign_parameters({1, y})
+        encoding_zz_param_y = encoding_zz.assign_parameters({1, y})
+
+        self.assertEqual(str(encoding_pauli_param_y.parameters), "ParameterView([Parameter(y)])")
+        self.assertEqual(str(encoding_z_param_y.parameters), "ParameterView([Parameter(y)])")
+        self.assertEqual(str(encoding_zz_param_y.parameters), "ParameterView([Parameter(y)])")
+
 
 if __name__ == "__main__":
     unittest.main()