2.0.0 中的新功能 (2023年4月3日)#

这些是 pandas 2.0.0 中的更改。有关包括其他版本 pandas 的完整更新日志,请参见 发行说明

增强功能#

使用 pip extras 安装可选依赖项#

在使用 pip 安装 pandas 时,可以通过指定 extras 来安装可选的依赖项集合。

pip install "pandas[performance, aws]>=2.0.0"

可用的额外功能,在 安装指南 中找到,包括 [all, performance, computation, fss, aws, gcp, excel, parquet, feather, hdf5, spss, postgresql, mysql, sql-other, html, xml, plot, output_formatting, clipboard, compression, test] (GH 39164)。

Index 现在可以容纳 numpy 数值类型#

现在可以在 Index 中使用任何 numpy 数值类型 (GH 42717)。

之前只能使用 int64uint64float64 数据类型:

In [1]: pd.Index([1, 2, 3], dtype=np.int8)
Out[1]: Int64Index([1, 2, 3], dtype="int64")
In [2]: pd.Index([1, 2, 3], dtype=np.uint16)
Out[2]: UInt64Index([1, 2, 3], dtype="uint64")
In [3]: pd.Index([1, 2, 3], dtype=np.float32)
Out[3]: Float64Index([1.0, 2.0, 3.0], dtype="float64")

Int64Index, UInt64IndexFloat64Index 在 pandas 版本 1.4 中已被弃用,现在已被移除。取而代之的是应直接使用 Index,它可以接受所有 numpy 数值类型,即 int8/ int16/int32/int64/uint8/uint16/uint32/uint64/float32/float64 类型:

In [1]: pd.Index([1, 2, 3], dtype=np.int8)
Out[1]: Index([1, 2, 3], dtype='int8')

In [2]: pd.Index([1, 2, 3], dtype=np.uint16)
Out[2]: Index([1, 2, 3], dtype='uint16')

In [3]: pd.Index([1, 2, 3], dtype=np.float32)
Out[3]: Index([1.0, 2.0, 3.0], dtype='float32')

Index 能够持有 numpy 数值类型的能力意味着 pandas 功能的一些变化。特别是,以前被迫创建 64 位索引的操作,现在可以创建更低位大小的索引,例如 32 位索引。

以下是一个可能不全面的变更列表:

  1. 现在,使用 numpy 数值数组实例化时会遵循 numpy 数组的 dtype。以前,从 numpy 数值数组创建的所有索引都被强制为 64 位。现在,例如,Index(np.array([1, 2, 3])) 在 32 位系统上将是 int32,而以前即使在 32 位系统上也会是 int64。使用数字列表实例化 Index 仍将返回 64 位 dtype,例如 Index([1, 2, 3]) 将具有 int64 dtype,这与以前相同。

  2. DatetimeIndex 的各种数值日期时间属性(daymonthyear 等)之前是 int64 类型,而 arrays.DatetimeArrayint32 类型。现在它们在 DatetimeIndex 上也是 int32 类型:

    In [4]: idx = pd.date_range(start='1/1/2018', periods=3, freq='ME')
    
    In [5]: idx.array.year
    Out[5]: array([2018, 2018, 2018], dtype=int32)
    
    In [6]: idx.year
    Out[6]: Index([2018, 2018, 2018], dtype='int32')
    
  3. Series.sparse.from_coo() 索引上的级别 dtypes 现在是 int32 类型,这与 scipy 稀疏矩阵上的 rows/cols 类型相同。以前它们是 int64 类型。

    In [7]: from scipy import sparse
    
    In [8]: A = sparse.coo_matrix(
       ...:     ([3.0, 1.0, 2.0], ([1, 0, 0], [0, 2, 3])), shape=(3, 4)
       ...: )
       ...: 
    
    In [9]: ser = pd.Series.sparse.from_coo(A)
    
    In [10]: ser.index.dtypes
    Out[10]: 
    level_0    int32
    level_1    int32
    dtype: object
    
  4. Index 不能使用 float16 dtype 实例化。以前使用 dtype float16 实例化一个 Index 会生成一个 float64 dtype 的 Float64Index。现在会引发一个 NotImplementedError

    In [11]: pd.Index([1, 2, 3], dtype=np.float16)
    ---------------------------------------------------------------------------
    NotImplementedError                       Traceback (most recent call last)
    Cell In[11], line 1
    ----> 1 pd.Index([1, 2, 3], dtype=np.float16)
    
    File /home/pandas/pandas/core/indexes/base.py:576, in Index.__new__(cls, data, dtype, copy, name, tupleize_cols)
        572 arr = ensure_wrapped_if_datetimelike(arr)
        574 klass = cls._dtype_to_subclass(arr.dtype)
    --> 576 arr = klass._ensure_array(arr, arr.dtype, copy=False)
        577 return klass._simple_new(arr, name, refs=refs)
    
    File /home/pandas/pandas/core/indexes/base.py:589, in Index._ensure_array(cls, data, dtype, copy)
        586     raise ValueError("Index data must be 1-dimensional")
        587 elif dtype == np.float16:
        588     # float16 not supported (no indexing engine)
    --> 589     raise NotImplementedError("float16 indexes are not supported")
        591 if copy:
        592     # asarray_tuplesafe does not always copy underlying data,
        593     #  so need to make sure that this happens
        594     data = data.copy()
    
    NotImplementedError: float16 indexes are not supported
    

参数 dtype_backend,用于返回 pyarrow 支持的或 numpy 支持的可空数据类型#

以下函数获得了一个新的关键字 dtype_backend (GH 36712)

当此选项设置为 "numpy_nullable" 时,它将返回一个由可空类型支持的 DataFrame

当此关键字设置为 "pyarrow" 时,这些函数将返回由 pyarrow 支持的可空 ArrowDtype DataFrame (GH 48957, GH 49997):

In [12]: import io

In [13]: data = io.StringIO("""a,b,c,d,e,f,g,h,i
   ....:     1,2.5,True,a,,,,,
   ....:     3,4.5,False,b,6,7.5,True,a,
   ....: """)
   ....: 

In [14]: df = pd.read_csv(data, dtype_backend="pyarrow")

In [15]: df.dtypes
Out[15]: 
a     int64[pyarrow]
b    double[pyarrow]
c      bool[pyarrow]
d    string[pyarrow]
e     int64[pyarrow]
f    double[pyarrow]
g      bool[pyarrow]
h    string[pyarrow]
i      null[pyarrow]
dtype: object

In [16]: data.seek(0)
Out[16]: 0

In [17]: df_pyarrow = pd.read_csv(data, dtype_backend="pyarrow", engine="pyarrow")

In [18]: df_pyarrow.dtypes
Out[18]: 
a     int64[pyarrow]
b    double[pyarrow]
c      bool[pyarrow]
d    string[pyarrow]
e     int64[pyarrow]
f    double[pyarrow]
g      bool[pyarrow]
h    string[pyarrow]
i      null[pyarrow]
dtype: object

写时复制改进#

  • 一个新的延迟复制机制被添加到 写时复制优化 中列出的方法中,该机制在对象被修改之前推迟复制。这些方法在启用写时复制时返回视图,与常规执行相比提供了显著的性能提升 (GH 49473)。

  • 当启用写时复制时,将 DataFrame 的单个列作为 Series 访问(例如 df["col"])现在每次构造时总是返回一个新对象(而不是多次返回相同的、缓存的 Series 对象)。这确保了这些 Series 对象正确遵循写时复制规则 (GH 49450)

  • 当从现有的 Series 构造 Series 时,如果 copy=False 的默认值为 False,Series 构造函数现在将创建一个惰性副本(将副本推迟到对数据进行修改时)(GH 50471)

  • DataFrame 构造函数现在在从现有的 DataFrame 构造时会创建一个延迟复制(将复制推迟到对数据进行修改时),默认情况下 copy=False (GH 51239)

  • 当从一系列对象的字典构造 DataFrame 时,如果指定 copy=FalseDataFrame 构造函数现在将使用这些 Series 对象的惰性拷贝作为 DataFrame 的列 (GH 50777)

  • 当从 SeriesIndex 构造 DataFrame 并指定 copy=False 时,DataFrame 构造函数现在将尊重写时复制。

  • 当从NumPy数组构造时,DataFrameSeries 构造函数现在默认会复制数组,以避免在修改数组时改变 DataFrame / Series。指定 copy=False 以获得旧的行为。当设置 copy=False 时,pandas不保证在创建 DataFrame / Series 后修改NumPy数组时的正确写时复制行为。

  • DataFrame.from_records() 现在在调用 DataFrame 时会尊重写时复制。

  • 尝试使用链式赋值设置值(例如,df["a"][1:3] = 0)在启用写时复制时现在总会引发警告。在这种模式下,链式赋值永远无法工作,因为我们总是在索引操作(getitem)结果的临时对象中设置值,而在写时复制下,这总是表现为复制。因此,通过链式赋值永远无法更新原始的 Series 或 DataFrame。因此,会向用户引发一个信息性警告,以避免静默地不执行任何操作 (GH 49467)。

  • DataFrame.replace() 现在会在 inplace=True 时尊重写时复制机制。

  • DataFrame.transpose() 现在将尊重写入时复制机制。

  • 可以就地进行的算术运算,例如 ser *= 2 现在将尊重写时复制机制。

  • DataFrame.__getitem__() 现在在 DataFrame 具有 MultiIndex 列时会尊重写时复制机制。

  • Series.__getitem__() 现在将在使用时尊重写时复制机制。

    Series 有一个 MultiIndex

  • Series.view() 现在将尊重写时复制机制。

写时复制可以通过以下方式启用:

pd.set_option("mode.copy_on_write", True)
pd.options.mode.copy_on_write = True

另外,可以通过以下方式在本地启用写时复制:

with pd.option_context("mode.copy_on_write", True):
    ...

其他增强功能#

值得注意的错误修复#

这些是可能具有显著行为变化的错误修复。

DataFrameGroupBy.cumsum()DataFrameGroupBy.cumprod() 溢出而不是有损转换为浮点数#

在以前的版本中,我们在应用 cumsumcumprod 时转换为浮点数,这即使结果可以用 int64 数据类型保持,也会导致不正确的结果。此外,当达到 int64 的限制时,聚合会与 numpy 和常规的 DataFrame.cumprod()DataFrame.cumsum() 方法一致地溢出 (GH 37493)。

旧行为

In [1]: df = pd.DataFrame({"key": ["b"] * 7, "value": 625})
In [2]: df.groupby("key")["value"].cumprod()[5]
Out[2]: 5.960464477539062e+16

我们在第6个值上返回了不正确的结果。

新行为

In [19]: df = pd.DataFrame({"key": ["b"] * 7, "value": 625})

In [20]: df.groupby("key")["value"].cumprod()
Out[20]: 
0                   625
1                390625
2             244140625
3          152587890625
4        95367431640625
5     59604644775390625
6    359414837200037393
Name: value, dtype: int64

我们溢出了第7个值,但第6个值仍然是正确的。

DataFrameGroupBy.nth()SeriesGroupBy.nth() 现在表现为过滤器#

在 pandas 的早期版本中,DataFrameGroupBy.nth()SeriesGroupBy.nth() 的行为类似于聚合。然而,对于大多数输入 n,它们可能每个组返回零行或多行。这意味着它们是过滤操作,类似于例如 DataFrameGroupBy.head()。pandas 现在将它们视为过滤操作 (GH 13666)。

In [21]: df = pd.DataFrame({"a": [1, 1, 2, 1, 2], "b": [np.nan, 2.0, 3.0, 4.0, 5.0]})

In [22]: gb = df.groupby("a")

旧行为

In [5]: gb.nth(n=1)
Out[5]:
   A    B
1  1  2.0
4  2  5.0

新行为

In [23]: gb.nth(n=1)
Out[23]: 
   a    b
1  1  2.0
4  2  5.0

特别是,结果的索引是通过选择适当的行从输入中派生的。此外,当 n 大于组时,返回的是没有行而不是 NaN

旧行为

In [5]: gb.nth(n=3, dropna="any")
Out[5]:
    B
A
1 NaN
2 NaN

新行为

In [24]: gb.nth(n=3, dropna="any")
Out[24]: 
Empty DataFrame
Columns: [a, b]
Index: []

向后不兼容的 API 更改#

使用 datetime64 或 timedelta64 dtype 构造时,分辨率不受支持#

在过去的版本中,当构建 SeriesDataFrame 并传递一个不支持分辨率(即除“ns”以外的任何分辨率)的“datetime64”或“timedelta64” dtype 时,pandas 会静默地将给定的 dtype 替换为其纳秒模拟:

以前的行为:

In [5]: pd.Series(["2016-01-01"], dtype="datetime64[s]")
Out[5]:
0   2016-01-01
dtype: datetime64[ns]

In [6] pd.Series(["2016-01-01"], dtype="datetime64[D]")
Out[6]:
0   2016-01-01
dtype: datetime64[ns]

在 pandas 2.0 中,我们支持分辨率 “s”、”ms”、”us” 和 “ns”。当传递一个支持的 dtype(例如 “datetime64[s]”)时,结果现在具有完全请求的 dtype:

新行为:

In [25]: pd.Series(["2016-01-01"], dtype="datetime64[s]")
Out[25]: 
0   2016-01-01
dtype: datetime64[s]

对于不支持的数据类型,pandas 现在会引发错误,而不是静默地替换为支持的数据类型:

新行为:

In [26]: pd.Series(["2016-01-01"], dtype="datetime64[D]")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[26], line 1
----> 1 pd.Series(["2016-01-01"], dtype="datetime64[D]")

File /home/pandas/pandas/core/series.py:503, in Series.__init__(self, data, index, dtype, name, copy)
    501         data = data.copy()
    502 else:
--> 503     data = sanitize_array(data, index, dtype, copy)
    504     data = SingleBlockManager.from_array(data, index, refs=refs)
    506 NDFrame.__init__(self, data)

File /home/pandas/pandas/core/construction.py:645, in sanitize_array(data, index, dtype, copy, allow_2d)
    642     subarr = np.array([], dtype=np.float64)
    644 elif dtype is not None:
--> 645     subarr = _try_cast(data, dtype, copy)
    647 else:
    648     subarr = maybe_convert_platform(data)

File /home/pandas/pandas/core/construction.py:805, in _try_cast(arr, dtype, copy)
    800     return lib.ensure_string_array(arr, convert_na_value=False, copy=copy).reshape(
    801         shape
    802     )
    804 elif dtype.kind in "mM":
--> 805     return maybe_cast_to_datetime(arr, dtype)
    807 # GH#15832: Check if we are requesting a numeric dtype and
    808 # that we can convert the data to the requested dtype.
    809 elif dtype.kind in "iu":
    810     # this will raise if we have e.g. floats

File /home/pandas/pandas/core/dtypes/cast.py:1225, in maybe_cast_to_datetime(value, dtype)
   1221     raise TypeError("value must be listlike")
   1223 # TODO: _from_sequence would raise ValueError in cases where
   1224 #  _ensure_nanosecond_dtype raises TypeError
-> 1225 _ensure_nanosecond_dtype(dtype)
   1227 if lib.is_np_dtype(dtype, "m"):
   1228     res = TimedeltaArray._from_sequence(value, dtype=dtype)

File /home/pandas/pandas/core/dtypes/cast.py:1282, in _ensure_nanosecond_dtype(dtype)
   1279     raise ValueError(msg)
   1280 # TODO: ValueError or TypeError? existing test
   1281 #  test_constructor_generic_timestamp_bad_frequency expects TypeError
-> 1282 raise TypeError(
   1283     f"dtype={dtype} is not supported. Supported resolutions are 's', "
   1284     "'ms', 'us', and 'ns'"
   1285 )

TypeError: dtype=datetime64[D] is not supported. Supported resolutions are 's', 'ms', 'us', and 'ns'

值计数将结果名称设置为 count#

在过去的版本中,当运行 Series.value_counts() 时,结果会继承原始对象的名称,而结果索引将是无名的。这会在重置索引时引起混淆,并且列名与列值不对应。现在,结果名称将是 'count' (如果传递了 normalize=True ,则为 'proportion' ),索引将命名为原始对象的名称 (GH 49497)。

以前的行为:

In [8]: pd.Series(['quetzal', 'quetzal', 'elk'], name='animal').value_counts()

Out[2]:
quetzal    2
elk        1
Name: animal, dtype: int64

新行为:

In [27]: pd.Series(['quetzal', 'quetzal', 'elk'], name='animal').value_counts()
Out[27]: 
animal
quetzal    2
elk        1
Name: count, dtype: int64

同样适用于其他 value_counts 方法(例如,DataFrame.value_counts())。

不允许将 astype 转换为不支持的 datetime64/timedelta64 dtypes#

在之前的版本中,将 SeriesDataFramedatetime64[ns] 转换为不同的 datetime64[X] dtype 时,会返回 datetime64[ns] dtype 而不是请求的 dtype。在 pandas 2.0 中,增加了对 “datetime64[s]”、”datetime64[ms]” 和 “datetime64[us]” dtypes 的支持,因此转换为这些 dtypes 时会返回请求的 dtype:

以前的行为:

In [28]: idx = pd.date_range("2016-01-01", periods=3)

In [29]: ser = pd.Series(idx)

以前的行为:

In [4]: ser.astype("datetime64[s]")
Out[4]:
0   2016-01-01
1   2016-01-02
2   2016-01-03
dtype: datetime64[ns]

使用新的行为,我们得到了完全请求的 dtype:

新行为:

In [30]: ser.astype("datetime64[s]")
Out[30]: 
0   2016-01-01
1   2016-01-02
2   2016-01-03
dtype: datetime64[s]

对于不支持的分辨率,例如“datetime64[D]”,我们改为引发错误,而不是静默忽略请求的dtype:

新行为:

In [31]: ser.astype("datetime64[D]")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[31], line 1
----> 1 ser.astype("datetime64[D]")

File /home/pandas/pandas/core/generic.py:6401, in NDFrame.astype(self, dtype, copy, errors)
   6397     results = [ser.astype(dtype, errors=errors) for _, ser in self.items()]
   6399 else:
   6400     # else, only a single dtype is given
-> 6401     new_data = self._mgr.astype(dtype=dtype, errors=errors)
   6402     res = self._constructor_from_mgr(new_data, axes=new_data.axes)
   6403     return res.__finalize__(self, method="astype")

File /home/pandas/pandas/core/internals/managers.py:588, in BaseBlockManager.astype(self, dtype, errors)
    587 def astype(self, dtype, errors: str = "raise") -> Self:
--> 588     return self.apply("astype", dtype=dtype, errors=errors)

File /home/pandas/pandas/core/internals/managers.py:438, in BaseBlockManager.apply(self, f, align_keys, **kwargs)
    436         applied = b.apply(f, **kwargs)
    437     else:
--> 438         applied = getattr(b, f)(**kwargs)
    439     result_blocks = extend_blocks(applied, result_blocks)
    441 out = type(self).from_blocks(result_blocks, self.axes)

File /home/pandas/pandas/core/internals/blocks.py:609, in Block.astype(self, dtype, errors, squeeze)
    606         raise ValueError("Can not squeeze with more than one column.")
    607     values = values[0, :]  # type: ignore[call-overload]
--> 609 new_values = astype_array_safe(values, dtype, errors=errors)
    611 new_values = maybe_coerce_values(new_values)
    613 refs = None

File /home/pandas/pandas/core/dtypes/astype.py:234, in astype_array_safe(values, dtype, copy, errors)
    231     dtype = dtype.numpy_dtype
    233 try:
--> 234     new_values = astype_array(values, dtype, copy=copy)
    235 except (ValueError, TypeError):
    236     # e.g. _astype_nansafe can fail on object-dtype of strings
    237     #  trying to convert to float
    238     if errors == "ignore":

File /home/pandas/pandas/core/dtypes/astype.py:176, in astype_array(values, dtype, copy)
    172     return values
    174 if not isinstance(values, np.ndarray):
    175     # i.e. ExtensionArray
--> 176     values = values.astype(dtype, copy=copy)
    178 else:
    179     values = _astype_nansafe(values, dtype, copy=copy)

File /home/pandas/pandas/core/arrays/datetimes.py:754, in DatetimeArray.astype(self, dtype, copy)
    752 elif isinstance(dtype, PeriodDtype):
    753     return self.to_period(freq=dtype.freq)
--> 754 return dtl.DatetimeLikeArrayMixin.astype(self, dtype, copy)

File /home/pandas/pandas/core/arrays/datetimelike.py:495, in DatetimeLikeArrayMixin.astype(self, dtype, copy)
    491 elif (dtype.kind in "mM" and self.dtype != dtype) or dtype.kind == "f":
    492     # disallow conversion between datetime/timedelta,
    493     # and conversions for any datetimelike to float
    494     msg = f"Cannot cast {type(self).__name__} to dtype {dtype}"
--> 495     raise TypeError(msg)
    496 else:
    497     return np.asarray(self, dtype=dtype)

TypeError: Cannot cast DatetimeArray to dtype datetime64[D]

对于从 timedelta64[ns] 数据类型的转换,旧的行为是转换为浮点格式。

以前的行为:

In [32]: idx = pd.timedelta_range("1 Day", periods=3)

In [33]: ser = pd.Series(idx)

以前的行为:

In [7]: ser.astype("timedelta64[s]")
Out[7]:
0     86400.0
1    172800.0
2    259200.0
dtype: float64

In [8]: ser.astype("timedelta64[D]")
Out[8]:
0    1.0
1    2.0
2    3.0
dtype: float64

新的行为,对于 datetime64 来说,要么给出确切请求的 dtype,要么引发错误:

新行为:

In [34]: ser.astype("timedelta64[s]")
Out[34]: 
0   1 days
1   2 days
2   3 days
dtype: timedelta64[s]

In [35]: ser.astype("timedelta64[D]")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[35], line 1
----> 1 ser.astype("timedelta64[D]")

File /home/pandas/pandas/core/generic.py:6401, in NDFrame.astype(self, dtype, copy, errors)
   6397     results = [ser.astype(dtype, errors=errors) for _, ser in self.items()]
   6399 else:
   6400     # else, only a single dtype is given
-> 6401     new_data = self._mgr.astype(dtype=dtype, errors=errors)
   6402     res = self._constructor_from_mgr(new_data, axes=new_data.axes)
   6403     return res.__finalize__(self, method="astype")

File /home/pandas/pandas/core/internals/managers.py:588, in BaseBlockManager.astype(self, dtype, errors)
    587 def astype(self, dtype, errors: str = "raise") -> Self:
--> 588     return self.apply("astype", dtype=dtype, errors=errors)

File /home/pandas/pandas/core/internals/managers.py:438, in BaseBlockManager.apply(self, f, align_keys, **kwargs)
    436         applied = b.apply(f, **kwargs)
    437     else:
--> 438         applied = getattr(b, f)(**kwargs)
    439     result_blocks = extend_blocks(applied, result_blocks)
    441 out = type(self).from_blocks(result_blocks, self.axes)

File /home/pandas/pandas/core/internals/blocks.py:609, in Block.astype(self, dtype, errors, squeeze)
    606         raise ValueError("Can not squeeze with more than one column.")
    607     values = values[0, :]  # type: ignore[call-overload]
--> 609 new_values = astype_array_safe(values, dtype, errors=errors)
    611 new_values = maybe_coerce_values(new_values)
    613 refs = None

File /home/pandas/pandas/core/dtypes/astype.py:234, in astype_array_safe(values, dtype, copy, errors)
    231     dtype = dtype.numpy_dtype
    233 try:
--> 234     new_values = astype_array(values, dtype, copy=copy)
    235 except (ValueError, TypeError):
    236     # e.g. _astype_nansafe can fail on object-dtype of strings
    237     #  trying to convert to float
    238     if errors == "ignore":

File /home/pandas/pandas/core/dtypes/astype.py:176, in astype_array(values, dtype, copy)
    172     return values
    174 if not isinstance(values, np.ndarray):
    175     # i.e. ExtensionArray
--> 176     values = values.astype(dtype, copy=copy)
    178 else:
    179     values = _astype_nansafe(values, dtype, copy=copy)

File /home/pandas/pandas/core/arrays/timedeltas.py:356, in TimedeltaArray.astype(self, dtype, copy)
    352         return type(self)._simple_new(
    353             res_values, dtype=res_values.dtype, freq=self.freq
    354         )
    355     else:
--> 356         raise ValueError(
    357             f"Cannot convert from {self.dtype} to {dtype}. "
    358             "Supported resolutions are 's', 'ms', 'us', 'ns'"
    359         )
    361 return dtl.DatetimeLikeArrayMixin.astype(self, dtype, copy=copy)

ValueError: Cannot convert from timedelta64[ns] to timedelta64[D]. Supported resolutions are 's', 'ms', 'us', 'ns'

UTC 和固定偏移时区默认使用标准库的 tzinfo 对象#

在之前的版本中,用于表示UTC的默认 tzinfo 对象是 pytz.UTC。在pandas 2.0中,我们默认使用 datetime.timezone.utc 代替。同样地,对于表示固定UTC偏移的时区,我们使用 datetime.timezone 对象而不是 pytz.FixedOffset 对象。见 (GH 34916)

以前的行为:

In [2]: ts = pd.Timestamp("2016-01-01", tz="UTC")
In [3]: type(ts.tzinfo)
Out[3]: pytz.UTC

In [4]: ts2 = pd.Timestamp("2016-01-01 04:05:06-07:00")
In [3]: type(ts2.tzinfo)
Out[5]: pytz._FixedOffset

新行为:

In [36]: ts = pd.Timestamp("2016-01-01", tz="UTC")

In [37]: type(ts.tzinfo)
Out[37]: datetime.timezone

In [38]: ts2 = pd.Timestamp("2016-01-01 04:05:06-07:00")

In [39]: type(ts2.tzinfo)
Out[39]: datetime.timezone

对于既不是UTC也不是固定偏移的时区,例如“US/Pacific”,我们继续默认使用 pytz 对象。

空的 DataFrame/Series 现在默认会有一个 RangeIndex#

之前,构造一个空的(其中 dataNone 或一个类似空列表的参数) SeriesDataFrame 而不指定轴(index=None, columns=None)会返回轴为具有对象数据类型的空 Index

现在,轴返回一个空的 RangeIndex (GH 49572)。

以前的行为:

In [8]: pd.Series().index
Out[8]:
Index([], dtype='object')

In [9] pd.DataFrame().axes
Out[9]:
[Index([], dtype='object'), Index([], dtype='object')]

新行为:

In [40]: pd.Series().index
Out[40]: RangeIndex(start=0, stop=0, step=1)

In [41]: pd.DataFrame().axes
Out[41]: [RangeIndex(start=0, stop=0, step=1), RangeIndex(start=0, stop=0, step=1)]

DataFrame 到 LaTeX 有一个新的渲染引擎#

现有的 DataFrame.to_latex() 已被重构,以利用之前在 Styler.to_latex() 下可用的扩展实现。参数签名相似,尽管 col_space 已被移除,因为它被LaTeX引擎忽略。此渲染引擎还需要 jinja2 作为依赖项,需要安装,因为渲染基于jinja2模板。

下面列出的 pandas latex 选项不再使用并已被移除。通用的最大行和列参数仍然保留,但应替换为 Styler 等效项。下面指出了提供类似功能的替代选项:

  • display.latex.escape: 替换为 styler.format.escape,

  • display.latex.longtable: 替换为 styler.latex.environment,

  • display.latex.multicolumn, display.latex.multicolumn_formatdisplay.latex.multirow: 替换为 styler.sparse.rows, styler.sparse.columns, styler.latex.multirow_alignstyler.latex.multicol_align,

  • display.latex.repr: 替换为 styler.render.repr,

  • display.max_rowsdisplay.max_columns:替换为 styler.render.max_rowsstyler.render.max_columnsstyler.render.max_elements

请注意,由于这一变化,一些默认值也发生了变化:

  • multirow 现在默认为 True

  • multirow_align 默认为 “r” 而不是 “l”

  • multicol_align 默认值为 “r” 而不是 “l”

  • escape 现在默认设置为 False

注意 _repr_latex_ 的行为也发生了变化。以前设置 display.latex.repr 只会在使用 nbconvert 转换 JupyterNotebook 时生成 LaTeX,而在用户运行笔记本时不会生成。现在 styler.render.repr 选项允许在 JupyterNotebooks 中控制特定操作的输出(不仅仅是 nbconvert 转换时)。请参见 GH 39911

增加了依赖项的最低版本要求#

一些依赖项的最低支持版本已更新。如果已安装,我们现在要求:

最低版本

必需的

Changed

mypy (dev)

1.0

X

pytest (开发版)

7.0.0

X

pytest-xdist (开发版)

2.2.0

X

hypothesis (开发)

6.34.2

X

python-dateutil

2.8.2

X

X

tzdata

2022.1

X

X

对于 可选库 ,一般的建议是使用最新版本。下表列出了每个库在 pandas 开发过程中目前测试的最低版本。低于最低测试版本的可选库可能仍然有效,但不被视为支持。

最低版本

Changed

pyarrow

7.0.0

X

matplotlib

3.6.1

X

fastparquet

0.6.3

X

xarray

0.21.0

X

更多信息请参见 依赖项可选依赖项

日期时间现在以一致的格式解析#

在过去,to_datetime() 独立地猜测每个元素的格式。这在某些元素具有混合日期格式的情况下是合适的——然而,当用户期望一致的格式时,函数在元素之间切换格式时会经常导致问题。从版本 2.0.0 开始,解析将使用一致的格式,由第一个非 NA 值决定(除非用户指定了格式,在这种情况下使用该格式)。

旧行为:

In [1]: ser = pd.Series(['13-01-2000', '12-01-2000'])
In [2]: pd.to_datetime(ser)
Out[2]:
0   2000-01-13
1   2000-12-01
dtype: datetime64[ns]

新行为:

In [42]: ser = pd.Series(['13-01-2000', '12-01-2000'])

In [43]: pd.to_datetime(ser)
Out[43]: 
0   2000-01-13
1   2000-01-12
dtype: datetime64[s]

请注意,这也会影响 read_csv()

如果你仍然需要解析格式不一致的日期,你可以使用 format='mixed' (可能与 dayfirst 一起使用)

ser = pd.Series(['13-01-2000', '12 January 2000'])
pd.to_datetime(ser, format='mixed', dayfirst=True)

或者,如果你的格式都是 ISO8601(但可能不是完全相同的格式)

ser = pd.Series(['2020-01-01', '2020-01-01 03:00'])
pd.to_datetime(ser, format='ISO8601')

其他 API 更改#

  • Timestamp 构造函数中的 tznanosecondunit 关键字现在仅限关键字使用 (GH 45307, GH 32526)

  • Timestamp 中传递大于 999 或小于 0 的 nanoseconds 现在会引发 ValueError (GH 48538, GH 48255)

  • read_csv():当使用c解析器时,通过``index_col``指定不正确的列数现在会引发``ParserError``而不是``IndexError``。

  • get_dummies()dtype 的默认值从 uint8 改为 bool (GH 45848)

  • DataFrame.astype(), Series.astype(), 和 DatetimeIndex.astype() 将 datetime64 数据转换为 “datetime64[s]”, “datetime64[ms]”, “datetime64[us]” 中的任何一个时,将返回具有给定分辨率的对象,而不是强制转换回 “datetime64[ns]” (GH 48928)

  • DataFrame.astype(), Series.astype(), 和 DatetimeIndex.astype() 将 timedelta64 数据转换为 “timedelta64[s]”, “timedelta64[ms]”, “timedelta64[us]” 中的任何一个时,将返回具有给定分辨率的对象,而不是强制转换为 “float64” dtype (GH 48963)

  • DatetimeIndex.astype(), TimedeltaIndex.astype(), PeriodIndex.astype() Series.astype(), DataFrame.astype() 使用 datetime64, timedelta64PeriodDtype 数据类型时,不再允许转换为除 “int64” 以外的整数数据类型,请改为使用 obj.astype('int64', copy=False).astype(dtype) (GH 49715)

  • Index.astype() 现在允许从 float64 dtype 转换为类似日期时间的 dtype,与 Series 行为匹配 (GH 49660)

  • 将数据类型为 “timedelta64[s]”、”timedelta64[ms]” 或 “timedelta64[us]” 的数据传递给 TimedeltaIndexSeriesDataFrame 构造函数时,现在将保留该数据类型,而不是转换为 “timedelta64[ns]”;分辨率较低的 timedelta64 数据将被转换为最低支持的分辨率 “timedelta64[s]” (GH 49014)

  • dtype 为 “timedelta64[s]”、”timedelta64[ms]” 或 “timedelta64[us]” 传递给 TimedeltaIndexSeriesDataFrame 构造函数现在将保留该 dtype 而不是转换为 “timedelta64[ns]”;为 SeriesDataFrame 传递较低分辨率的 dtype 将被转换为最低支持的分辨率 “timedelta64[s]” (GH 49014)

  • np.datetime64 对象以非纳秒分辨率传递给 Timestamp 时,如果输入分辨率为“s”、“ms”、“us”或“ns”,则将保留输入分辨率;否则它将被转换为最接近的支持分辨率 (GH 49008)

  • 传递 datetime64 值时,如果分辨率不是纳秒,则 to_datetime() 将保留输入分辨率,如果它是“s”、“ms”、“us”或“ns”;否则它将被转换为最接近的支持分辨率 (GH 50369)

  • 传递整数值和一个非纳秒的 datetime64 数据类型(例如 “datetime64[s]”)的 DataFrameSeriesIndex 将把值视为数据类型单位的倍数,匹配例如 Series(np.array(values, dtype="M8[s]")) 的行为(GH 51092

  • 将ISO-8601格式的字符串传递给 Timestamp 将保留解析输入的分辨率,如果它是“s”、“ms”、“us”或“ns”;否则它将被转换为最接近的支持分辨率 (GH 49737)

  • DataFrame.mask()Series.mask() 中的 other 参数现在默认为 no_default 而不是 np.nan,与 DataFrame.where()Series.where() 一致。条目将被填充为相应的 NULL 值(numpy dtypes 为 np.nan,extension dtypes 为 pd.NA)。(GH 49111)

  • 更改了带有 SparseDtypeSeries.quantile()DataFrame.quantile() 的行为,以保留稀疏数据类型 (GH 49583)

  • 当使用对象类型的 Index 创建 Series 时,如果索引是日期时间对象,pandas 不再静默地将索引转换为 DatetimeIndex (GH 39307, GH 23598)

  • pandas.testing.assert_index_equal() 参数 exact="equiv" 现在认为当两者都是 RangeIndexIndex 且具有 int64 dtype 时,两个索引是相等的。以前这意味着要么是 RangeIndex 要么是 Int64Index (GH 51098)

  • Series.unique() 使用 dtype “timedelta64[ns]” 或 “datetime64[ns]” 现在返回 TimedeltaArrayDatetimeArray 而不是 numpy.ndarray (GH 49176)

  • to_datetime()DatetimeIndex 现在允许包含 datetime 对象和数值条目的序列,匹配 Series 的行为 (GH 49037, GH 50453)

  • pandas.api.types.is_string_dtype() 现在仅对 dtype=object 的类数组对象返回 True,当元素被推断为字符串时 (GH 15585)

  • 将包含 datetime 对象和 date 对象的序列传递给 Series 构造函数将返回 object 类型而不是 datetime64[ns] 类型,这与 Index 行为一致(GH 49341

  • 将无法解析为日期时间的字符串传递给带有 dtype="datetime64[ns]"SeriesDataFrame 将引发错误,而不是默默忽略关键字并返回 object 类型 (GH 24435)

  • 将一个包含无法转换为 Timedelta 类型的序列传递给 to_timedelta() 或使用 dtype="timedelta64[ns]" 传递给 SeriesDataFrame 构造函数,或传递给 TimedeltaIndex 现在会引发 TypeError 而不是 ValueError (GH 49525)

  • 更改了包含至少一个 NaT 以及其余为 NoneNaN 的序列的 Index 构造函数行为,推断为 datetime64[ns] 数据类型而不是 object,与 Series 行为匹配 (GH 49340)

  • read_stata() 参数 index_col 设置为 ``None``(默认值)时,现在会将返回的 DataFrame 的索引设置为 RangeIndex 而不是 Int64Index (GH 49745)

  • 在处理对象数据类型时,IndexSeriesDataFrame 算术方法的行为已更改,数组操作的结果不再进行类型推断,使用 result.infer_objects(copy=False) 对结果进行类型推断 (GH 49999, GH 49714)

  • 更改了包含全``bool``值或全复数值的对象类型 numpy.ndarrayIndex 构造函数的行为,现在这将保留对象类型,与 Series 行为一致 (GH 49594)

  • 更改了 Series.astype() 从包含 bytes 对象的 object-dtype 到字符串 dtypes 的行为;现在对 bytes 对象执行 val.decode() 而不是 str(val),与 Index.astype() 行为匹配 (GH 45326)

  • read_csv() 中添加了 "None" 到默认的 na_values (GH 50286)

  • 当给定一个整数数据类型和不是整数的浮点数据时,SeriesDataFrame 构造函数的行为发生了变化,现在会引发 ValueError 而不是静默保留浮点数据类型;执行 Series(data)DataFrame(data) 以获得旧的行为,执行 Series(data).astype(dtype)DataFrame(data).astype(dtype) 以获得指定的数据类型 (GH 49599)

  • 更改了 DataFrame.shift()axis=1、整数 fill_value 和同质日期时间类型时的行为,现在用整数类型填充新列,而不是转换为日期时间类型 (GH 49842)

  • read_json() 中遇到异常时,文件现在会被关闭 (GH 49921)

  • 更改了 read_csv()read_json()read_fwf() 的行为,当未指定索引时,索引现在将始终为 RangeIndex。以前,如果新的 DataFrame/Series 长度为 0,索引将是一个 dtype 为 objectIndex (GH 49572)

  • DataFrame.values(), DataFrame.to_numpy(), DataFrame.xs(), DataFrame.reindex(), DataFrame.fillna(), 和 DataFrame.replace() 不再静默地合并底层数组;请使用 df = df.copy() 以确保合并 (GH 49356)

  • 使用 lociloc 在两个轴上进行完整切片创建一个新的 DataFrame(例如 df.loc[:, :]df.iloc[:, :])现在返回一个新的 DataFrame(浅拷贝)而不是原始 DataFrame,与其他获取完整切片的方法一致(例如 df.loc[:]df[:])(GH 49469)

  • SeriesDataFrame 构造函数现在在分别传递一个 Series 和 DataFrame 时,并且默认 copy=False``(并且如果没有其他关键字触发复制)时,将返回一个浅拷贝(即共享数据,但不共享属性)。以前,新的 Series DataFrame 会共享索引属性(例如 ``df.index = ... 也会更新父级或子级的索引)(GH 49523)

  • 不允许对 Timedelta 对象计算 cumprod;之前这会返回不正确的值 (GH 50246)

  • DataFrame 对象从 HDFStore 文件中读取时,如果没有索引,现在会有一个 RangeIndex 而不是 int64 索引 (GH 51076)

  • 使用包含 NA 和/或 NaT 数据的数值型 numpy dtype 实例化一个 Index 现在会引发 ValueError。以前会引发 TypeError (GH 51050)

  • 使用 read_json(orient='split') 加载包含重复列的 JSON 文件时,会重命名列以避免重复,就像 read_csv() 和其他读取器所做的那样 (GH 50370)

  • Series.sparse.from_coo 返回的 Series 的索引级别现在总是具有 int32 数据类型。以前它们具有 int64 数据类型 (GH 50926)

  • to_datetime() 使用 unit 为 “Y” 或 “M” 时,如果序列包含非整数的 float 值,现在会引发错误,与 Timestamp 行为一致 (GH 50301)

  • 方法 Series.round(), DataFrame.__invert__(), Series.__invert__(), DataFrame.swapaxes(), DataFrame.first(), DataFrame.last(), Series.first(), Series.last()DataFrame.align() 现在将始终返回新对象 (GH 51032)

  • DataFrameDataFrameGroupBy 聚合(例如“sum”)对于对象类型的列不再推断非对象类型的结果,请在结果上显式调用 result.infer_objects(copy=False) 以获得旧的行为(GH 51205, GH 49603

  • 使用 ArrowDtype 数据类型进行除以零操作会根据分子返回 -infnaninf,而不是引发异常 (GH 51541)

  • 添加了 pandas.api.types.is_any_real_numeric_dtype() 以检查实数数据类型 (GH 51152)

  • value_counts() 现在返回带有 ArrowDtype 的数据,类型为 pyarrow.int64 而不是 "Int64" 类型 (GH 51462)

  • factorize()unique() 在传递非纳秒分辨率的 numpy timedelta64 或 datetime64 时保留原始数据类型 (GH 48670)

备注

当前的 PDEP 提议弃用并移除 pandas API 中除少数方法外的所有 inplacecopy 关键字。当前的讨论正在进行 这里。在写时复制(Copy-on-Write)的背景下,这些关键字将不再必要。如果该提议被接受,这两个关键字将在 pandas 的下一个版本中被弃用,并在 pandas 3.0 中被移除。

弃用#

移除先前版本的弃用/更改#

性能提升#

错误修复#

Categorical#

Datetimelike#

Timedelta#

  • 在输入具有可空类型 Float64 时,to_timedelta() 中的错误 (GH 48796)

  • Timedelta 构造函数中的错误在给定 np.timedelta64("nat") 时错误地引发而不是返回 NaT (GH 48898)

  • Timedelta 构造函数在同时传递 Timedelta 对象和关键字(例如 days, seconds)时未能引发错误的 Bug (GH 48898)

  • Timedelta 与非常大的 datetime.timedelta 对象进行比较时出现错误,引发 OutOfBoundsTimedelta (GH 49021)

时区#

Numeric#

转换#

字符串#

  • pandas.api.types.is_string_dtype() 中的一个错误,对于 StringDtypeArrowDtype 使用 pyarrow.string() 不会返回 True (GH 15585)

  • 在将字符串dtypes转换为“datetime64[ns]”或“timedelta64[ns]”时错误地引发``TypeError``的Bug (GH 36153)

  • 在字符串数据类型列中设置值时存在错误,当数组包含缺失值时,作为副作用会修改数组 (GH 51299)

Interval#

索引#

缺失#

MultiIndex#

I/O#

周期#

  • Period.strftime()PeriodIndex.strftime() 中的错误,当传递特定于区域设置的指令时引发 UnicodeDecodeError (GH 46319)

  • 在将 Period 对象添加到 DateOffset 对象数组时错误地引发 TypeError (GH 50162)

  • Period 中的一个错误,当传递一个分辨率比纳秒更细的字符串时,会导致 KeyError 而不是丢弃额外的精度 (GH 50417)

  • 解析表示周期的字符串(例如“2017-01-23/2017-01-29”)时出现错误,将其解析为分钟频率而不是周频率 (GH 50803)

  • DataFrameGroupBy.sum()DataFrameGroupByGroupBy.cumsum()DataFrameGroupByGroupBy.prod()DataFrameGroupByGroupBy.cumprod() 中存在一个错误,当使用 PeriodDtype 时未能引发 TypeError (GH 51040)

  • 在解析空字符串时,Period 错误地引发 ValueError 而不是返回 NaT (GH 51349)

绘图#

  • DataFrame.plot.hist() 中的错误,未删除 weights 中对应 dataNaN 值的元素 (GH 48884)

  • ax.set_xlim 有时会引发 UserWarning,由于 set_xlim 不接受解析参数,用户无法解决此问题 - 转换器现在使用 Timestamp() 代替 (GH 49148)

分组/重采样/滚动#

Reshaping#

Sparse#

ExtensionArray#

Styler#

元数据#

其他#

贡献者#

总共有260人为此版本贡献了补丁。名字后面带有“+”的人首次贡献了补丁。

  • 5j9 +

  • ABCPAN-rank +

  • Aarni Koskela +

  • Aashish KC +

  • Abubeker Mohammed +

  • Adam Mróz +

  • Adam Ormondroyd +

  • Aditya Anulekh +

  • Ahmed Ibrahim

  • Akshay Babbar +

  • Aleksa Radojicic +

  • Alex +

  • Alex Buzenet +

  • Alex Kirko

  • Allison Kwan +

  • Amay Patel +

  • Ambuj Pawar +

  • Amotz +

  • Andreas Schwab +

  • Andrew Chen +

  • Anton Shevtsov

  • Antonio Ossa Guerra +

  • Antonio Ossa-Guerra +

  • Anushka Bishnoi +

  • Arda Kosar

  • Armin Berres

  • Asadullah Naeem +

  • Asish Mahapatra

  • Bailey Lissington +

  • BarkotBeyene

  • Ben Beasley

  • Bhavesh Rajendra Patil +

  • Bibek Jha +

  • Bill +

  • Bishwas +

  • CarlosGDCJ +

  • Carlotta Fabian +

  • Chris Roth +

  • Chuck Cadman +

  • Corralien +

  • DG +

  • Dan Hendry +

  • Daniel Isaac

  • David Kleindienst +

  • David Poznik +

  • David Rudel +

  • DavidKleindienst +

  • Dea María Léon +

  • Deepak Sirohiwal +

  • Dennis Chukwunta

  • Douglas Lohmann +

  • Dries Schaumont

  • Dustin K +

  • Edoardo Abati +

  • Eduardo Chaves +

  • Ege Özgüroğlu +

  • Ekaterina Borovikova +

  • Eli Schwartz +

  • Elvis Lim +

  • Emily Taylor +

  • Emma Carballal Haire +

  • Erik Welch +

  • Fangchen Li

  • Florian Hofstetter +

  • Flynn Owen +

  • Fredrik Erlandsson +

  • Gaurav Sheni

  • Georeth Chow +

  • George Munyoro +

  • Guilherme Beltramini

  • Gulnur Baimukhambetova +

  • H L +

  • Hans

  • Hatim Zahid +

  • HighYoda +

  • Hiki +

  • Himanshu Wagh +

  • Hugo van Kemenade +

  • Idil Ismiguzel +

  • Irv Lustig

  • Isaac Chung

  • Isaac Virshup

  • JHM Darbyshire

  • JHM Darbyshire (iMac)

  • JMBurley

  • Jaime Di Cristina

  • Jan Koch

  • JanVHII +

  • Janosh Riebesell

  • JasmandeepKaur +

  • Jeremy Tuloup

  • Jessica M +

  • Jonas Haag

  • Joris Van den Bossche

  • João Meirelles +

  • Julia Aoun +

  • Justus Magin +

  • Kang Su Min +

  • Kevin Sheppard

  • Khor Chean Wei

  • Kian Eliasi

  • Kostya Farber +

  • KotlinIsland +

  • Lakmal Pinnaduwage +

  • Lakshya A Agrawal +

  • Lawrence Mitchell +

  • Levi Ob +

  • Loic Diridollou

  • Lorenzo Vainigli +

  • Luca Pizzini +

  • Lucas Damo +

  • Luke Manley

  • Madhuri Patil +

  • Marc Garcia

  • Marco Edward Gorelli

  • Marco Gorelli

  • MarcoGorelli

  • Maren Westermann +

  • Maria Stazherova +

  • Marie K +

  • Marielle +

  • Mark Harfouche +

  • Marko Pacak +

  • Martin +

  • Matheus Cerqueira +

  • Matheus Pedroni +

  • Matteo Raso +

  • Matthew Roeschke

  • MeeseeksMachine +

  • Mehdi Mohammadi +

  • Michael Harris +

  • Michael Mior +

  • Natalia Mokeeva +

  • Neal Muppidi +

  • Nick Crews

  • Nishu Choudhary +

  • Noa Tamir

  • Noritada Kobayashi

  • Omkar Yadav +

  • P. Talley +

  • Pablo +

  • Pandas Development Team

  • Parfait Gasana

  • Patrick Hoefler

  • Pedro Nacht +

  • Philip +

  • Pietro Battiston

  • Pooja Subramaniam +

  • Pranav Saibhushan Ravuri +

  • Pranav. P. A +

  • Ralf Gommers +

  • RaphSku +

  • Richard Shadrach

  • Robsdedude +

  • Roger

  • Roger Thomas

  • RogerThomas +

  • SFuller4 +

  • Salahuddin +

  • Sam Rao

  • Sean Patrick Malloy +

  • Sebastian Roll +

  • Shantanu

  • Shashwat +

  • Shashwat Agrawal +

  • Shiko Wamwea +

  • Shoham Debnath

  • Shubhankar Lohani +

  • Siddhartha Gandhi +

  • Simon Hawkins

  • Soumik Dutta +

  • Sowrov Talukder +

  • Stefanie Molin

  • Stefanie Senger +

  • Stepfen Shawn +

  • Steven Rotondo

  • Stijn Van Hoey

  • Sudhansu +

  • Sven

  • Sylvain MARIE

  • Sylvain Marié

  • Tabea Kossen +

  • Taylor Packard

  • Terji Petersen

  • Thierry Moisan

  • Thomas H +

  • Thomas Li

  • Torsten Wörtwein

  • Tsvika S +

  • Tsvika Shapira +

  • Vamsi Verma +

  • Vinicius Akira +

  • William Andrea

  • William Ayd

  • William Blum +

  • Wilson Xing +

  • Xiao Yuan +

  • Xnot +

  • Yasin Tatar +

  • Yuanhao Geng

  • Yvan Cywan +

  • Zachary Moon +

  • Zhengbo Wang +

  • abonte +

  • adrienpacifico +

  • alm

  • amotzop +

  • andyjessen +

  • anonmouse1 +

  • bang128 +

  • bishwas jha +

  • calhockemeyer +

  • carla-alves-24 +

  • carlotta +

  • casadipietra +

  • catmar22 +

  • cfabian +

  • codamuse +

  • dataxerik

  • davidleon123 +

  • dependabot[bot] +

  • fdrocha +

  • github-actions[bot]

  • himanshu_wagh +

  • iofall +

  • jakirkham +

  • jbrockmendel

  • jnclt +

  • joelchen +

  • joelsonoda +

  • joshuabello2550

  • joycewamwea +

  • kathleenhang +

  • krasch +

  • ltoniazzi +

  • luke396 +

  • milosz-martynow +

  • minat-hub +

  • mliu08 +

  • monosans +

  • nealxm

  • nikitaved +

  • paradox-lab +

  • partev

  • raisadz +

  • ram vikram singh +

  • rebecca-palmer

  • sarvaSanjay +

  • seljaks +

  • silviaovo +

  • smij720 +

  • soumilbaldota +

  • stellalin7 +

  • strawberry beach sandals +

  • tmoschou +

  • uzzell +

  • yqyqyq-W +

  • yun +

  • Ádám Lippai

  • 김동현 (Daniel Donghyun Kim) +