Repository: pandas-dev/pandas
Pull request: BUG: Don't multiply sets during construction
- [x] closes #32582
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry


Problem statement:
Creating a column with a set replicates the set n times
#### Code Sample

If we try to define a dataframe using a dictionary containing a set, we get:

```python
pd.DataFrame({'a':{1,2,3}})

       a
0  {1, 2, 3}
1  {1, 2, 3}
2  {1, 2, 3}
```
#### Problem description

The set is being replicated `n` times, `n` being the length of the actual set. 
While defining a column with a set directly might not make a lot of sense given that they are by definition unordered collections, the behaviour  in any case seems clearly unexpected. 

#### Expected Output

In the case of a list, in order to obtain a single row containing a list, we would have to define a nested list, such as `pd.DataFrame({'a':[[1,2,3]]})`.
So similarly, with sets I would expect the same behaviour by defining the row with `pd.DataFrame({'a':[{1,2,3}]})`. 

In the case of a single set, even if the order is not guaranteed to be preserved, I'd see more reasonable the same output that we would obtain with:

```python

pd.DataFrame({'a':[1,2,3]})

   a
0  1
1  2
2  3
```
So:

```python
pd.DataFrame({'a':{1,2,3}})

   a
0  1
1  2
2  3
```

Where:
```python
pd.__version__
# '1.0.0'
```

Hints from issue discussion:

Commit message: Doc

Patch to review:
diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst
index e745bf3f5feed..bed74c7933b19 100644
--- a/doc/source/whatsnew/v1.1.0.rst
+++ b/doc/source/whatsnew/v1.1.0.rst
@@ -352,6 +352,7 @@ Other
   instead of ``TypeError: Can only append a Series if ignore_index=True or if the Series has a name`` (:issue:`30871`)
 - Set operations on an object-dtype :class:`Index` now always return object-dtype results (:issue:`31401`)
 - Bug in :meth:`AbstractHolidayCalendar.holidays` when no rules were defined (:issue:`31415`)
+- Bug in :class:`DataFrame` expanding sets when passed to the constructor (:issue:`32582`)
 
 .. ---------------------------------------------------------------------------
 
diff --git a/pandas/core/construction.py b/pandas/core/construction.py
index e2d8fba8d4148..06928f0058aa0 100644
--- a/pandas/core/construction.py
+++ b/pandas/core/construction.py
@@ -434,7 +434,9 @@ def sanitize_array(
             subarr = subarr.copy()
         return subarr
 
-    elif isinstance(data, (list, tuple)) and len(data) > 0:
+    elif isinstance(data, (list, tuple, set)) and len(data) > 0:
+        if isinstance(data, set):
+            data = list(data)
         if dtype is not None:
             subarr = _try_cast(data, dtype, copy, raise_cast_failure)
         else:
diff --git a/pandas/tests/frame/test_constructors.py b/pandas/tests/frame/test_constructors.py
index 071d2409f1be2..092be38d742e1 100644
--- a/pandas/tests/frame/test_constructors.py
+++ b/pandas/tests/frame/test_constructors.py
@@ -2609,3 +2609,10 @@ def test_from_2d_ndarray_with_dtype(self):
 
         expected = pd.DataFrame(array_dim2).astype("datetime64[ns, UTC]")
         tm.assert_frame_equal(df, expected)
+
+    def test_construction_from_set(self):
+        # https://github.com/pandas-dev/pandas/issues/32582
+        result = pd.DataFrame({"a": {1, 2, 3}})
+        expected = pd.DataFrame({"a": [1, 2, 3]})
+
+        tm.assert_frame_equal(result, expected)


Code review comments:
diff_hunk: @@ -434,7 +434,9 @@ def sanitize_array(
             subarr = subarr.copy()
         return subarr
 
-    elif isinstance(data, (list, tuple)) and len(data) > 0:
+    elif isinstance(data, (list, tuple, set)) and len(data) > 0:
path: pandas/core/construction.py
text: @user1:
Would it be appropriate to use `is_list_like(..., allow_sets=True)` here?

@author:
Good question. It looks like that ends up interfering a bit with some of the other cases (`range` inputs that are handled differently below, as well `array.array` which causes a test to fail when I try to use that here).

@user1:
Alright sounds like it's not a good fit here (maybe make a comment here why we can't use `is_list_like`)