Версия 0.20.1 (5 мая 2017)#

Это основной выпуск с версии 0.19.2 и включает ряд изменений API, устареваний, новых функций, улучшений и оптимизаций производительности, а также большое количество исправлений ошибок. Мы рекомендуем всем пользователям обновиться до этой версии.

Основные моменты включают:

  • Новый .agg() API для Series/DataFrame, аналогичный API groupby-rolling-resample, см. здесь

  • Интеграция с feather-format, включая новый верхнеуровневый pd.read_feather() и DataFrame.to_feather() метод, см. здесь.

  • The .ix индексатор устарел, см. здесь

  • Panel был устаревшим, см. здесь

  • Добавление IntervalIndex и Interval скалярный тип, см. здесь

  • Улучшенный пользовательский API при группировке по уровням индекса в .groupby(), см. здесь

  • Улучшенная поддержка для UInt64 типы данных, см. здесь

  • Новая ориентация для JSON-сериализации, orient='table', который использует спецификацию Table Schema и предоставляет возможность более интерактивного repr в Jupyter Notebook, см. здесь

  • Экспериментальная поддержка экспорта стилизованных DataFrames (DataFrame.style) в Excel, см. здесь

  • Окно бинарных операций corr/cov теперь возвращает MultiIndex DataFrame а не Panel, как Panel теперь устарело, см. здесь

  • Поддержка обработки S3 теперь использует s3fs, см. здесь

  • Поддержка Google BigQuery теперь использует pandas-gbq библиотека, см. здесь

Предупреждение

pandas изменил внутреннюю структуру и организацию кодовой базы. Это может повлиять на импорты, которые не выполняются из верхнего уровня pandas.* пространство имён, пожалуйста, ознакомьтесь с изменениями здесь.

Проверьте Изменения API и устаревшие возможности перед обновлением.

Примечание

Это комбинированный выпуск для версий 0.20.0 и 0.20.1. Версия 0.20.1 содержит одно дополнительное изменение для обратной совместимости с проектами, использующими pandas' utils процедуры. (GH 16250)

Новые возможности#

Метод agg API для DataFrame/Series#

Series и DataFrame были улучшены для поддержки API агрегации. Это знакомый API из groupby, оконных операций и передискретизации. Это позволяет выполнять операции агрегации кратко с использованием agg() и transform(). Полная документация находится здесь (GH 1623).

Вот пример

In [1]: df = pd.DataFrame(np.random.randn(10, 3), columns=['A', 'B', 'C'],
   ...:                   index=pd.date_range('1/1/2000', periods=10))
   ...: 

In [2]: df.iloc[3:7] = np.nan

In [3]: df
Out[3]: 
                   A         B         C
2000-01-01  0.469112 -0.282863 -1.509059
2000-01-02 -1.135632  1.212112 -0.173215
2000-01-03  0.119209 -1.044236 -0.861849
2000-01-04       NaN       NaN       NaN
2000-01-05       NaN       NaN       NaN
2000-01-06       NaN       NaN       NaN
2000-01-07       NaN       NaN       NaN
2000-01-08  0.113648 -1.478427  0.524988
2000-01-09  0.404705  0.577046 -1.715002
2000-01-10 -1.039268 -0.370647 -1.157892

[10 rows x 3 columns]

Можно работать с именами строковых функций, вызываемыми объектами, списками или словарями этих элементов.

Использование одной функции эквивалентно .apply.

In [4]: df.agg('sum')
Out[4]: 
A   -1.068226
B   -1.387015
C   -4.892029
Length: 3, dtype: float64

Множественные агрегации со списком функций.

In [5]: df.agg(['sum', 'min'])
Out[5]: 
            A         B         C
sum -1.068226 -1.387015 -4.892029
min -1.135632 -1.478427 -1.715002

[2 rows x 3 columns]

Использование словаря позволяет применять специфические агрегации для каждого столбца. Вы получите матричный вывод всех агрегаторов. Вывод имеет один столбец на каждую уникальную функцию. Эти функции, примененные к конкретному столбцу, будут NaN:

In [6]: df.agg({'A': ['sum', 'min'], 'B': ['min', 'max']})
Out[6]: 
            A         B
sum -1.068226       NaN
min -1.135632 -1.478427
max       NaN  1.212112

[3 rows x 2 columns]

API также поддерживает .transform() функция для широковещательной передачи результатов.

In [7]: df.transform(['abs', lambda x: x - x.min()])
Out[7]: 
                   A                   B                   C          
                 abs         abs         abs  
2000-01-01  0.469112  1.604745  0.282863  1.195563  1.509059  0.205944
2000-01-02  1.135632  0.000000  1.212112  2.690539  0.173215  1.541787
2000-01-03  0.119209  1.254841  1.044236  0.434191  0.861849  0.853153
2000-01-04       NaN       NaN       NaN       NaN       NaN       NaN
2000-01-05       NaN       NaN       NaN       NaN       NaN       NaN
2000-01-06       NaN       NaN       NaN       NaN       NaN       NaN
2000-01-07       NaN       NaN       NaN       NaN       NaN       NaN
2000-01-08  0.113648  1.249281  1.478427  0.000000  0.524988  2.239990
2000-01-09  0.404705  1.540338  0.577046  2.055473  1.715002  0.000000
2000-01-10  1.039268  0.096364  0.370647  1.107780  1.157892  0.557110

[10 rows x 6 columns]

При представлении смешанных типов данных, которые не могут быть агрегированы, .agg() будет принимать только допустимые агрегации. Это похоже на то, как groupby .agg() работает. (GH 15015)

In [8]: df = pd.DataFrame({'A': [1, 2, 3],
   ...:                    'B': [1., 2., 3.],
   ...:                    'C': ['foo', 'bar', 'baz'],
   ...:                    'D': pd.date_range('20130101', periods=3)})
   ...: 

In [9]: df.dtypes
Out[9]: 
A             int64
B           float64
C            object
D    datetime64[ns]
Length: 4, dtype: object
In [10]: df.agg(['min', 'sum'])
Out[10]:
     A    B          C          D
min  1  1.0        bar 2013-01-01
sum  6  6.0  foobarbaz        NaT

Ключевой аргумент dtype для ввода-вывода данных#

The 'python' движок для read_csv(), а также read_fwf() функция для анализа файлов с фиксированной шириной текста и read_excel() для парсинга файлов Excel теперь принимают dtype ключевой аргумент для указания типов конкретных столбцов (GH 14295). См. документация io для получения дополнительной информации.

In [10]: data = "a  b\n1  2\n3  4"

In [11]: pd.read_fwf(StringIO(data)).dtypes
Out[11]: 
a    int64
b    int64
Length: 2, dtype: object

In [12]: pd.read_fwf(StringIO(data), dtype={'a': 'float64', 'b': 'object'}).dtypes
Out[12]: 
a    float64
b     object
Length: 2, dtype: object

Метод .to_datetime() приобрёл origin параметр#

to_datetime() получил новый параметр, origin, чтобы определить опорную дату от которой вычисляются результирующие временные метки при разборе числовых значений с определенным unit указано. (GH 11276, GH 11745)

Например, с 1960-01-01 в качестве начальной даты:

In [13]: pd.to_datetime([1, 2, 3], unit='D', origin=pd.Timestamp('1960-01-01'))
Out[13]: DatetimeIndex(['1960-01-02', '1960-01-03', '1960-01-04'], dtype='datetime64[ns]', freq=None)

Значение по умолчанию установлено на origin='unix', который по умолчанию равен 1970-01-01 00:00:00, которая обычно называется 'эпохой Unix' или временем POSIX. Это было предыдущим значением по умолчанию, поэтому это изменение обратно совместимо.

In [14]: pd.to_datetime([1, 2, 3], unit='D')
Out[14]: DatetimeIndex(['1970-01-02', '1970-01-03', '1970-01-04'], dtype='datetime64[ns]', freq=None)

Улучшения GroupBy#

Строки, переданные в DataFrame.groupby() как by параметр теперь может ссылаться либо на имена столбцов, либо на имена уровней индекса. Ранее можно было ссылаться только на имена столбцов. Это позволяет легко группировать по столбцу и уровню индекса одновременно. (GH 5677)

In [15]: arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
   ....:           ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]
   ....: 

In [16]: index = pd.MultiIndex.from_arrays(arrays, names=['first', 'second'])

In [17]: df = pd.DataFrame({'A': [1, 1, 1, 1, 2, 2, 3, 3],
   ....:                    'B': np.arange(8)},
   ....:                   index=index)
   ....: 

In [18]: df
Out[18]: 
              A  B
first second      
bar   one     1  0
      two     1  1
baz   one     1  2
      two     1  3
foo   one     2  4
      two     2  5
qux   one     3  6
      two     3  7

[8 rows x 2 columns]

In [19]: df.groupby(['second', 'A']).sum()
Out[19]: 
          B
second A   
one    1  2
       2  4
       3  6
two    1  4
       2  5
       3  7

[6 rows x 1 columns]

Улучшенная поддержка сжатых URL в read_csv#

Код сжатия был переработан (GH 12688). В результате чтение фреймов данных из URL-адресов в read_csv() или read_table() теперь поддерживает дополнительные методы сжатия: xz, bz2, и zip (GH 14570). Ранее только gzip поддерживалось сжатие. По умолчанию сжатие URL и путей теперь определяется по их расширениям файлов. Кроме того, улучшена поддержка сжатия bz2 в C-движке python 2 (GH 14874).

In [20]: url = ('https://github.com/{repo}/raw/{branch}/{path}'
   ....:        .format(repo='pandas-dev/pandas',
   ....:                branch='main',
   ....:                path='pandas/tests/io/parser/data/salaries.csv.bz2'))
   ....: 

# default, infer compression
In [21]: df = pd.read_csv(url, sep='\t', compression='infer')

# explicitly specify compression
In [22]: df = pd.read_csv(url, sep='\t', compression='bz2')

In [23]: df.head(2)
Out[23]: 
       S  X  E  M
0  13876  1  1  1
1  11608  1  3  0

[2 rows x 4 columns]

Ввод-вывод файлов Pickle теперь поддерживает сжатие#

read_pickle(), DataFrame.to_pickle() и Series.to_pickle() теперь может читать и записывать сжатые файлы pickle. Методы сжатия могут быть явным параметром или определяться по расширению файла. См. документацию здесь.

In [24]: df = pd.DataFrame({'A': np.random.randn(1000),
   ....:                    'B': 'foo',
   ....:                    'C': pd.date_range('20130101', periods=1000, freq='s')})
   ....: 

Использование явного типа сжатия

In [25]: df.to_pickle("data.pkl.compress", compression="gzip")

In [26]: rt = pd.read_pickle("data.pkl.compress", compression="gzip")

In [27]: rt.head()
Out[27]: 
          A    B                   C
0 -1.344312  foo 2013-01-01 00:00:00
1  0.844885  foo 2013-01-01 00:00:01
2  1.075770  foo 2013-01-01 00:00:02
3 -0.109050  foo 2013-01-01 00:00:03
4  1.643563  foo 2013-01-01 00:00:04

[5 rows x 3 columns]

По умолчанию тип сжатия определяется по расширению (compression='infer'):

In [28]: df.to_pickle("data.pkl.gz")

In [29]: rt = pd.read_pickle("data.pkl.gz")

In [30]: rt.head()
Out[30]: 
          A    B                   C
0 -1.344312  foo 2013-01-01 00:00:00
1  0.844885  foo 2013-01-01 00:00:01
2  1.075770  foo 2013-01-01 00:00:02
3 -0.109050  foo 2013-01-01 00:00:03
4  1.643563  foo 2013-01-01 00:00:04

[5 rows x 3 columns]

In [31]: df["A"].to_pickle("s1.pkl.bz2")

In [32]: rt = pd.read_pickle("s1.pkl.bz2")

In [33]: rt.head()
Out[33]: 
0   -1.344312
1    0.844885
2    1.075770
3   -0.109050
4    1.643563
Name: A, Length: 5, dtype: float64

Поддержка UInt64 улучшена#

pandas значительно улучшил поддержку операций с беззнаковыми или строго неотрицательными целыми числами. Ранее работа с такими числами приводила к неправильному округлению или приведению типов данных, что давало некорректные результаты. В частности, новый числовой индекс, UInt64Index, был создан (GH 14937)

In [1]: idx = pd.UInt64Index([1, 2, 3])
In [2]: df = pd.DataFrame({'A': ['a', 'b', 'c']}, index=idx)
In [3]: df.index
Out[3]: UInt64Index([1, 2, 3], dtype='uint64')
  • Ошибка при преобразовании объектных элементов массивоподобных объектов в 64-битные беззнаковые целые числа (GH 4471, GH 14982)

  • Ошибка в Series.unique() в котором беззнаковые 64-битные целые числа вызывали переполнение (GH 14721)

  • Ошибка в DataFrame конструкция, в которой элементы беззнаковых 64-битных целых чисел преобразовывались в объекты (GH 14881)

  • Ошибка в pd.read_csv() в котором элементы беззнаковых 64-битных целых чисел неправильно преобразовывались в неверные типы данных (GH 14983)

  • Ошибка в pd.unique() в котором беззнаковые 64-битные целые числа вызывали переполнение (GH 14915)

  • Ошибка в pd.value_counts() в котором беззнаковые 64-битные целые числа ошибочно обрезались в выводе (GH 14934)

GroupBy по категориальным данным#

В предыдущих версиях, .groupby(..., sort=False) завершится с ошибкой ValueError при группировке по категориальному ряду, где некоторые категории не встречаются в данных. (GH 13179)

In [34]: chromosomes = np.r_[np.arange(1, 23).astype(str), ['X', 'Y']]

In [35]: df = pd.DataFrame({
   ....:     'A': np.random.randint(100),
   ....:     'B': np.random.randint(100),
   ....:     'C': np.random.randint(100),
   ....:     'chromosomes': pd.Categorical(np.random.choice(chromosomes, 100),
   ....:                                   categories=chromosomes,
   ....:                                   ordered=True)})
   ....: 

In [36]: df
Out[36]: 
     A   B   C chromosomes
0   87  22  81           4
1   87  22  81          13
2   87  22  81          22
3   87  22  81           2
4   87  22  81           6
..  ..  ..  ..         ...
95  87  22  81           8
96  87  22  81          11
97  87  22  81           X
98  87  22  81           1
99  87  22  81          19

[100 rows x 4 columns]

Предыдущее поведение:

In [3]: df[df.chromosomes != '1'].groupby('chromosomes', observed=False, sort=False).sum()
---------------------------------------------------------------------------
ValueError: items in new_categories are not the same as in old categories

Новое поведение:

In [37]: df[df.chromosomes != '1'].groupby('chromosomes', observed=False, sort=False).sum()
Out[37]: 
               A   B    C
chromosomes              
4            348  88  324
13           261  66  243
22           348  88  324
2            348  88  324
6            174  44  162
...          ...  ..  ...
3            348  88  324
11           348  88  324
19           174  44  162
1              0   0    0
21             0   0    0

[24 rows x 3 columns]

Вывод схемы таблицы#

Новая ориентация 'table' для DataFrame.to_json() сгенерирует Схема таблицы совместимое строковое представление данных.

In [38]: df = pd.DataFrame(
   ....:     {'A': [1, 2, 3],
   ....:      'B': ['a', 'b', 'c'],
   ....:      'C': pd.date_range('2016-01-01', freq='d', periods=3)},
   ....:     index=pd.Index(range(3), name='idx'))
   ....: 

In [39]: df
Out[39]: 
     A  B          C
idx                 
0    1  a 2016-01-01
1    2  b 2016-01-02
2    3  c 2016-01-03

[3 rows x 3 columns]

In [40]: df.to_json(orient='table')
Out[40]: '{"schema":{"fields":[{"name":"idx","type":"integer"},{"name":"A","type":"integer"},{"name":"B","type":"string"},{"name":"C","type":"datetime"}],"primaryKey":["idx"],"pandas_version":"1.4.0"},"data":[{"idx":0,"A":1,"B":"a","C":"2016-01-01T00:00:00.000"},{"idx":1,"A":2,"B":"b","C":"2016-01-02T00:00:00.000"},{"idx":2,"A":3,"B":"c","C":"2016-01-03T00:00:00.000"}]}'

См. Ввод-вывод: Схема таблицы для получения дополнительной информации.

Кроме того, repr для DataFrame и Series теперь может публиковать это представление схемы JSON Table для Series или DataFrame, если вы используете IPython (или другой интерфейс, такой как nteract используя протокол обмена сообщениями Jupyter. Это позволяет фронтендам, таким как Jupyter notebook и nteract больше гибкости в отображении объектов pandas, поскольку они имеют больше информации о данных. Вы должны включить это, установив display.html.table_schema опция для True.

Разреженная матрица SciPy из/в SparseDataFrame#

pandas теперь поддерживает создание разреженных датафреймов непосредственно из scipy.sparse.spmatrix экземпляры. См. документация для получения дополнительной информации. (GH 4343)

Все разреженные форматы поддерживаются, но матрицы, которые не находятся в COOrdinate формат будет преобразован, копируя данные по мере необходимости.

from scipy.sparse import csr_matrix
arr = np.random.random(size=(1000, 5))
arr[arr < .9] = 0
sp_arr = csr_matrix(arr)
sp_arr
sdf = pd.SparseDataFrame(sp_arr)
sdf

Чтобы преобразовать SparseDataFrame обратно в разреженную матрицу SciPy в формате COO можно использовать:

sdf.to_coo()

Вывод в Excel для стилизованных DataFrame#

Добавлена экспериментальная поддержка экспорта DataFrame.style форматы в Excel с использованием openpyxl движок. (GH 15530)

Например, после выполнения следующего, styled.xlsx отображается как ниже:

In [41]: np.random.seed(24)

In [42]: df = pd.DataFrame({'A': np.linspace(1, 10, 10)})

In [43]: df = pd.concat([df, pd.DataFrame(np.random.RandomState(24).randn(10, 4),
   ....:                                  columns=list('BCDE'))],
   ....:                axis=1)
   ....: 

In [44]: df.iloc[0, 2] = np.nan

In [45]: df
Out[45]: 
      A         B         C         D         E
0   1.0  1.329212       NaN -0.316280 -0.990810
1   2.0 -1.070816 -1.438713  0.564417  0.295722
2   3.0 -1.626404  0.219565  0.678805  1.889273
3   4.0  0.961538  0.104011 -0.481165  0.850229
4   5.0  1.453425  1.057737  0.165562  0.515018
5   6.0 -1.336936  0.562861  1.392855 -0.063328
6   7.0  0.121668  1.207603 -0.002040  1.627796
7   8.0  0.354493  1.037528 -0.385684  0.519818
8   9.0  1.686583 -1.325963  1.428984 -2.089354
9  10.0 -0.129820  0.631523 -0.586538  0.290720

[10 rows x 5 columns]

In [46]: styled = (df.style
   ....:           .applymap(lambda val: 'color:red;' if val < 0 else 'color:black;')
   ....:           .highlight_max())
   ....: 

In [47]: styled.to_excel('styled.xlsx', engine='openpyxl')
../_images/style-excel.png

См. Документация по стилю для более подробной информации.

IntervalIndex#

pandas получил IntervalIndex со своим собственным типом данных, interval а также Interval скалярного типа. Это обеспечивает первоклассную поддержку интервальной нотации, в частности, как тип возвращаемого значения для категорий в cut() и qcut(). IntervalIndex позволяет уникальную индексацию, см. документация. (GH 7640, GH 8625)

Предупреждение

Эти особенности индексирования IntervalIndex являются временными и могут измениться в будущих версиях pandas. Отзывы об использовании приветствуются.

Предыдущее поведение:

Возвращенные категории были строками, представляющими интервалы

In [1]: c = pd.cut(range(4), bins=2)

In [2]: c
Out[2]:
[(-0.003, 1.5], (-0.003, 1.5], (1.5, 3], (1.5, 3]]
Categories (2, object): [(-0.003, 1.5] < (1.5, 3]]

In [3]: c.categories
Out[3]: Index(['(-0.003, 1.5]', '(1.5, 3]'], dtype='object')

Новое поведение:

In [48]: c = pd.cut(range(4), bins=2)

In [49]: c
Out[49]: 
[(-0.003, 1.5], (-0.003, 1.5], (1.5, 3.0], (1.5, 3.0]]
Categories (2, interval[float64, right]): [(-0.003, 1.5] < (1.5, 3.0]]

In [50]: c.categories
Out[50]: IntervalIndex([(-0.003, 1.5], (1.5, 3.0]], dtype='interval[float64, right]')

Кроме того, это позволяет группировать other данные с этими же интервалами, с NaN представляющий отсутствующее значение, аналогично другим типам данных.

In [51]: pd.cut([0, 3, 5, 1], bins=c.categories)
Out[51]: 
[(-0.003, 1.5], (1.5, 3.0], NaN, (-0.003, 1.5]]
Categories (2, interval[float64, right]): [(-0.003, 1.5] < (1.5, 3.0]]

An IntervalIndex также может использоваться в Series и DataFrame в качестве индекса.

In [52]: df = pd.DataFrame({'A': range(4),
   ....:                    'B': pd.cut([0, 3, 1, 1], bins=c.categories)
   ....:                    }).set_index('B')
   ....: 

In [53]: df
Out[53]: 
               A
B               
(-0.003, 1.5]  0
(1.5, 3.0]     1
(-0.003, 1.5]  2
(-0.003, 1.5]  3

[4 rows x 1 columns]

Выбор через определенный интервал:

In [54]: df.loc[pd.Interval(1.5, 3.0)]
Out[54]: 
A    1
Name: (1.5, 3.0], Length: 1, dtype: int64

Выбор через скалярное значение, которое содержится в интервалы.

In [55]: df.loc[0]
Out[55]: 
               A
B               
(-0.003, 1.5]  0
(-0.003, 1.5]  2
(-0.003, 1.5]  3

[3 rows x 1 columns]

Другие улучшения#

  • DataFrame.rolling() теперь принимает параметр closed='right'|'left'|'both'|'neither' для выбора закрытости конечной точки скользящего окна. См. документация (GH 13965)

  • Интеграция с feather-format, включая новый верхнеуровневый pd.read_feather() и DataFrame.to_feather() метод, см. здесь.

  • Series.str.replace() теперь принимает вызываемый объект в качестве замены, который передается в re.sub (GH 15055)

  • Series.str.replace() теперь принимает скомпилированное регулярное выражение в качестве шаблона (GH 15446)

  • Series.sort_index принимает параметры kind и na_position (GH 13589, GH 14444)

  • DataFrame и DataFrame.groupby() получили nunique() метод для подсчёта уникальных значений по оси (GH 14336, GH 15197).

  • DataFrame получил melt() метод, эквивалентный pd.melt(), для преобразования из широкого в длинный формат (GH 12640).

  • pd.read_excel() теперь сохраняет порядок листов при использовании sheetname=None (GH 9930)

  • Теперь поддерживаются множественные псевдонимы смещений с десятичными точками (например, 0.5min парсится как 30s) (GH 8419)

  • .isnull() и .notnull() были добавлены в Index объект, чтобы сделать их более согласованными с Series API (GH 15300)

  • Новый UnsortedIndexError (подкласс KeyError) возникает при индексировании/срезе в несортированном MultiIndex (GH 11897). Это позволяет различать ошибки из-за отсутствия сортировки или некорректного ключа. См. здесь

  • MultiIndex получил .to_frame() метод для преобразования в DataFrame (GH 12397)

  • pd.cut и pd.qcut теперь поддерживают типы данных datetime64 и timedelta64 (GH 14714, GH 14798)

  • pd.qcut получил duplicates='raise'|'drop' опцию для управления вызовом ошибки при дублировании границ (GH 7751)

  • Series предоставляет to_excel метод для вывода файлов Excel (GH 8825)

  • The usecols аргумент в pd.read_csv() теперь принимает вызываемую функцию в качестве значения (GH 14154)

  • The skiprows аргумент в pd.read_csv() теперь принимает вызываемую функцию в качестве значения (GH 10882)

  • The nrows и chunksize аргументы в pd.read_csv() поддерживаются, если оба переданы (GH 6774, GH 15755)

  • DataFrame.plot теперь выводит заголовок над каждым подграфиком, если suplots=True и title является списком строк (GH 14753)

  • DataFrame.plot можно передать цветовой цикл по умолчанию matplotlib 2.0 в виде одной строки в качестве параметра color, см. здесь. (GH 15516)

  • Series.interpolate() теперь поддерживает timedelta в качестве типа индекса с method='time' (GH 6424)

  • Добавление level ключевое слово для DataFrame/Series.rename для переименования меток в указанном уровне MultiIndex (GH 4160).

  • DataFrame.reset_index() теперь будет интерпретировать кортеж index.name в качестве ключа, охватывающего уровни columns, если это MultiIndex (GH 16164)

  • Timedelta.isoformat метод добавлен для форматирования Timedelta как ISO 8601 длительность. См. Документация по Timedelta (GH 15136)

  • .select_dtypes() теперь позволяет строку datetimetz для универсального выбора дат с tz (GH 14910)

  • The .to_latex() метод теперь будет принимать multicolumn и multirow аргументы для использования сопутствующих улучшений LaTeX

  • pd.merge_asof() получил опцию direction='backward'|'forward'|'nearest' (GH 14887)

  • Series/DataFrame.asfreq() получили fill_value параметр для заполнения пропущенных значений (GH 3715).

  • Series/DataFrame.resample.asfreq получили fill_value параметр, для заполнения пропущенных значений при ресемплинге (GH 3715).

  • pandas.util.hash_pandas_object() получил возможность хэшировать MultiIndex (GH 15224)

  • Series/DataFrame.squeeze() получили axis параметр. (GH 15339)

  • DataFrame.to_excel() имеет новый freeze_panes параметр для включения закрепления областей при экспорте в Excel (GH 15160)

  • pd.read_html() будет парсить несколько строк заголовков, создавая заголовок MultiIndex. (GH 13434).

  • Вывод HTML таблицы пропускает colspan или rowspan атрибут, если равен 1. (GH 15403)

  • pandas.io.formats.style.Styler шаблон теперь содержит блоки для более простого расширения, см. пример ноутбука (GH 15649)

  • Styler.render() теперь принимает **kwargs чтобы разрешить пользовательские переменные в шаблоне (GH 15649)

  • Совместимость с Jupyter notebook 5.0; Метки столбцов MultiIndex выровнены по левому краю, а метки строк MultiIndex — по верхнему краю (GH 15379)

  • TimedeltaIndex теперь имеет пользовательский форматтер даты, специально разработанный для точности на уровне наносекунд (GH 8711)

  • pd.api.types.union_categoricals получил ignore_ordered аргумент для игнорирования упорядоченного атрибута объединенных категориальных данных (GH 13410). См. документация по объединению категориальных данных для получения дополнительной информации.

  • DataFrame.to_latex() и DataFrame.to_string() теперь допускают необязательные псевдонимы заголовков. (GH 15536)

  • Повторно включить parse_dates ключевое слово pd.read_excel() для парсинга строковых столбцов как дат (GH 14326)

  • Добавлен .empty свойство для подклассов Index. (GH 15270)

  • Включено целочисленное деление для Timedelta и TimedeltaIndex (GH 15828)

  • pandas.io.json.json_normalize() получил опцию errors='ignore'|'raise'; по умолчанию errors='raise' что обратно совместимо. (GH 14583)

  • pandas.io.json.json_normalize() с пустым list вернет пустой DataFrame (GH 15534)

  • pandas.io.json.json_normalize() получил sep опция, которая принимает str для разделения объединённых полей; по умолчанию используется “.”, что обратно совместимо. (GH 14883)

  • MultiIndex.remove_unused_levels() был добавлен для облегчения удаление неиспользуемых уровней. (GH 15694)

  • pd.read_csv() теперь вызовет ParserError ошибка при возникновении любой ошибки парсинга (GH 15913, GH 15925)

  • pd.read_csv() теперь поддерживает error_bad_lines и warn_bad_lines аргументы для парсера Python (GH 15925)

  • The display.show_dimensions опция теперь также может использоваться для указания длины Series должен отображаться в его repr (GH 7117).

  • parallel_coordinates() получил sort_labels аргумент ключевого слова, который сортирует метки классов и назначенные им цвета (GH 15908)

  • Добавлены опции для включения/отключения использования bottleneck и numexpr, см. здесь (GH 16157)

  • DataFrame.style.bar() теперь принимает два дополнительных параметра для дальнейшей настройки гистограммы. Выравнивание столбцов устанавливается с помощью align='left'|'mid'|'zero', по умолчанию используется "left", что обратно совместимо; Теперь можно передать список color=[color_negative, color_positive]. (GH 14757)

Обратно несовместимые изменения API#

Возможная несовместимость для форматов HDF5, созданных с pandas < 0.13.0#

pd.TimeSeries был официально устаревшим в 0.17.0, хотя уже был псевдонимом с 0.13.0. Он был заменён на pd.Series. (GH 15098).

Это может приводит к тому, что файлы HDF5, созданные в предыдущих версиях, становятся нечитаемыми, если pd.TimeSeries использовался. Это, скорее всего, относится к pandas < 0.13.0. Если вы оказались в такой ситуации, вы можете использовать более раннюю версию pandas для чтения файлов HDF5, а затем записать их снова после применения процедуры ниже.

In [2]: s = pd.TimeSeries([1, 2, 3], index=pd.date_range('20130101', periods=3))

In [3]: s
Out[3]:
2013-01-01    1
2013-01-02    2
2013-01-03    3
Freq: D, dtype: int64

In [4]: type(s)
Out[4]: pandas.core.series.TimeSeries

In [5]: s = pd.Series(s)

In [6]: s
Out[6]:
2013-01-01    1
2013-01-02    2
2013-01-03    3
Freq: D, dtype: int64

In [7]: type(s)
Out[7]: pandas.core.series.Series

Map на типах Index теперь возвращает другие типы Index#

map на Index теперь возвращает Index, а не массив numpy (GH 12766)

In [56]: idx = pd.Index([1, 2])

In [57]: idx
Out[57]: Index([1, 2], dtype='int64')

In [58]: mi = pd.MultiIndex.from_tuples([(1, 2), (2, 4)])

In [59]: mi
Out[59]: 
MultiIndex([(1, 2),
            (2, 4)],
           )

Предыдущее поведение:

In [5]: idx.map(lambda x: x * 2)
Out[5]: array([2, 4])

In [6]: idx.map(lambda x: (x, x * 2))
Out[6]: array([(1, 2), (2, 4)], dtype=object)

In [7]: mi.map(lambda x: x)
Out[7]: array([(1, 2), (2, 4)], dtype=object)

In [8]: mi.map(lambda x: x[0])
Out[8]: array([1, 2])

Новое поведение:

In [60]: idx.map(lambda x: x * 2)
Out[60]: Index([2, 4], dtype='int64')

In [61]: idx.map(lambda x: (x, x * 2))
Out[61]: 
MultiIndex([(1, 2),
            (2, 4)],
           )

In [62]: mi.map(lambda x: x)
Out[62]: 
MultiIndex([(1, 2),
            (2, 4)],
           )

In [63]: mi.map(lambda x: x[0])
Out[63]: Index([1, 2], dtype='int64')

map на Series с datetime64 значения могут возвращать int64 dtypes, а не int32

In [64]: s = pd.Series(pd.date_range('2011-01-02T00:00', '2011-01-02T02:00', freq='H')
   ....:               .tz_localize('Asia/Tokyo'))
   ....:

In [65]: s
Out[65]:
0   2011-01-02 00:00:00+09:00
1   2011-01-02 01:00:00+09:00
2   2011-01-02 02:00:00+09:00
Length: 3, dtype: datetime64[ns, Asia/Tokyo]

Предыдущее поведение:

In [9]: s.map(lambda x: x.hour)
Out[9]:
0    0
1    1
2    2
dtype: int32

Новое поведение:

In [66]: s.map(lambda x: x.hour)
Out[66]:
0    0
1    1
2    2
Length: 3, dtype: int64

Доступ к полям даты и времени Index теперь возвращает Index#

Атрибуты, связанные с датой и временем (см. здесь для обзора) из DatetimeIndex, PeriodIndex и TimedeltaIndex ранее возвращаемые массивы numpy. Теперь они будут возвращать новый Index объект, за исключением случая булевого поля, где результат всё равно будет булевым ndarray. (GH 15022)

Предыдущее поведение:

In [1]: idx = pd.date_range("2015-01-01", periods=5, freq='10H')

In [2]: idx.hour
Out[2]: array([ 0, 10, 20,  6, 16], dtype=int32)

Новое поведение:

In [67]: idx = pd.date_range("2015-01-01", periods=5, freq='10H')

In [68]: idx.hour
Out[68]: Index([0, 10, 20, 6, 16], dtype='int32')

Это имеет преимущество в том, что конкретные Index методы все еще доступны для результата. С другой стороны, это может иметь обратную несовместимость: например, по сравнению с массивами numpy, Index объекты не изменяемы. Чтобы получить исходный ndarray, вы всегда можете явно преобразовать, используя np.asarray(idx.hour).

pd.unique теперь будет согласован с типами расширений#

В предыдущих версиях, использование Series.unique() и pandas.unique() на Categorical и типы данных с учетом часового пояса давали бы разные типы возвращаемых значений. Теперь они приведены к единообразию. (GH 15903)

  • Datetime с учетом часового пояса

    Предыдущее поведение:

    # Series
    In [5]: pd.Series([pd.Timestamp('20160101', tz='US/Eastern'),
       ...:            pd.Timestamp('20160101', tz='US/Eastern')]).unique()
    Out[5]: array([Timestamp('2016-01-01 00:00:00-0500', tz='US/Eastern')], dtype=object)
    
    In [6]: pd.unique(pd.Series([pd.Timestamp('20160101', tz='US/Eastern'),
       ...:                      pd.Timestamp('20160101', tz='US/Eastern')]))
    Out[6]: array(['2016-01-01T05:00:00.000000000'], dtype='datetime64[ns]')
    
    # Index
    In [7]: pd.Index([pd.Timestamp('20160101', tz='US/Eastern'),
       ...:           pd.Timestamp('20160101', tz='US/Eastern')]).unique()
    Out[7]: DatetimeIndex(['2016-01-01 00:00:00-05:00'], dtype='datetime64[ns, US/Eastern]', freq=None)
    
    In [8]: pd.unique([pd.Timestamp('20160101', tz='US/Eastern'),
       ...:            pd.Timestamp('20160101', tz='US/Eastern')])
    Out[8]: array(['2016-01-01T05:00:00.000000000'], dtype='datetime64[ns]')
    

    Новое поведение:

    # Series, returns an array of Timestamp tz-aware
    In [64]: pd.Series([pd.Timestamp(r'20160101', tz=r'US/Eastern'),
       ....:            pd.Timestamp(r'20160101', tz=r'US/Eastern')]).unique()
       ....: 
    Out[64]: 
    
    ['2016-01-01 00:00:00-05:00']
    Length: 1, dtype: datetime64[ns, US/Eastern]
    
    In [65]: pd.unique(pd.Series([pd.Timestamp('20160101', tz='US/Eastern'),
       ....:           pd.Timestamp('20160101', tz='US/Eastern')]))
       ....: 
    Out[65]: 
    
    ['2016-01-01 00:00:00-05:00']
    Length: 1, dtype: datetime64[ns, US/Eastern]
    
    # Index, returns a DatetimeIndex
    In [66]: pd.Index([pd.Timestamp('20160101', tz='US/Eastern'),
       ....:           pd.Timestamp('20160101', tz='US/Eastern')]).unique()
       ....: 
    Out[66]: DatetimeIndex(['2016-01-01 00:00:00-05:00'], dtype='datetime64[ns, US/Eastern]', freq=None)
    
    In [67]: pd.unique(pd.Index([pd.Timestamp('20160101', tz='US/Eastern'),
       ....:                     pd.Timestamp('20160101', tz='US/Eastern')]))
       ....: 
    Out[67]: DatetimeIndex(['2016-01-01 00:00:00-05:00'], dtype='datetime64[ns, US/Eastern]', freq=None)
    
  • Категориальные данные

    Предыдущее поведение:

    In [1]: pd.Series(list('baabc'), dtype='category').unique()
    Out[1]:
    [b, a, c]
    Categories (3, object): [b, a, c]
    
    In [2]: pd.unique(pd.Series(list('baabc'), dtype='category'))
    Out[2]: array(['b', 'a', 'c'], dtype=object)
    

    Новое поведение:

    # returns a Categorical
    In [68]: pd.Series(list('baabc'), dtype='category').unique()
    Out[68]: 
    ['b', 'a', 'c']
    Categories (3, object): ['a', 'b', 'c']
    
    In [69]: pd.unique(pd.Series(list('baabc'), dtype='category'))
    Out[69]: 
    ['b', 'a', 'c']
    Categories (3, object): ['a', 'b', 'c']
    

Обработка файлов S3#

pandas теперь использует s3fs для обработки соединений S3. Это не должно нарушать никакой код. Однако, поскольку s3fs не является обязательной зависимостью, вам нужно будет установить её отдельно, например boto в предыдущих версиях pandas. (GH 11915).

Изменения частичного строкового индексирования#

Частичная строковая индексация DatetimeIndex теперь работает как точное совпадение, при условии, что разрешение строки совпадает с разрешением индекса, включая случай, когда оба являются секундами (GH 14826). См. Срез против точного совпадения подробности.

In [70]: df = pd.DataFrame({'a': [1, 2, 3]}, pd.DatetimeIndex(['2011-12-31 23:59:59',
   ....:                                                       '2012-01-01 00:00:00',
   ....:                                                       '2012-01-01 00:00:01']))
   ....: 

Предыдущее поведение:

In [4]: df['2011-12-31 23:59:59']
Out[4]:
                       a
2011-12-31 23:59:59  1

In [5]: df['a']['2011-12-31 23:59:59']
Out[5]:
2011-12-31 23:59:59    1
Name: a, dtype: int64

Новое поведение:

In [4]: df['2011-12-31 23:59:59']
KeyError: '2011-12-31 23:59:59'

In [5]: df['a']['2011-12-31 23:59:59']
Out[5]: 1

Конкатенация разных типов float не будет автоматически повышать тип#

Ранее, concat нескольких объектов с разными float dtypes автоматически повышали бы результаты до dtype float64. Теперь будет использоваться наименьший допустимый тип данных (GH 13247)

In [71]: df1 = pd.DataFrame(np.array([1.0], dtype=np.float32, ndmin=2))

In [72]: df1.dtypes
Out[72]: 
0    float32
Length: 1, dtype: object

In [73]: df2 = pd.DataFrame(np.array([np.nan], dtype=np.float32, ndmin=2))

In [74]: df2.dtypes
Out[74]: 
0    float32
Length: 1, dtype: object

Предыдущее поведение:

In [7]: pd.concat([df1, df2]).dtypes
Out[7]:
0    float64
dtype: object

Новое поведение:

In [75]: pd.concat([df1, df2]).dtypes
Out[75]: 
0    float32
Length: 1, dtype: object

поддержка pandas Google BigQuery перемещена#

pandas выделил поддержку Google BigQuery в отдельный пакет pandas-gbq. Вы можете conda install pandas-gbq -c conda-forge или pip install pandas-gbq чтобы получить его. Функциональность read_gbq() и DataFrame.to_gbq() остаются такими же, как в текущей выпущенной версии pandas-gbq=0.1.4. Документация теперь размещена здесь (GH 15347)

Использование памяти для Index стало более точным#

В предыдущих версиях отображение .memory_usage() в структуре pandas с индексом включало бы только фактические значения индекса, а не структуры, обеспечивающие быстрое индексирование. Обычно это различается для Index и MultiIndex и менее для других типов индексов. (GH 15237)

Предыдущее поведение:

In [8]: index = pd.Index(['foo', 'bar', 'baz'])

In [9]: index.memory_usage(deep=True)
Out[9]: 180

In [10]: index.get_loc('foo')
Out[10]: 0

In [11]: index.memory_usage(deep=True)
Out[11]: 180

Новое поведение:

In [8]: index = pd.Index(['foo', 'bar', 'baz'])

In [9]: index.memory_usage(deep=True)
Out[9]: 180

In [10]: index.get_loc('foo')
Out[10]: 0

In [11]: index.memory_usage(deep=True)
Out[11]: 260

Изменения в DataFrame.sort_index#

В некоторых случаях вызов .sort_index() на DataFrame с MultiIndex вернет тот же DataFrame без видимой сортировки. Это может произойти с lexsorted, но не монотонные уровни. (GH 15622, GH 15687, GH 14015, GH 13431, GH 15797)

Это неизмененным из предыдущих версий, но показаны для иллюстрации:

In [81]: df = pd.DataFrame(np.arange(6), columns=['value'],
   ....:                   index=pd.MultiIndex.from_product([list('BA'), range(3)]))
   ....:
In [82]: df

Out[82]:
     value
B 0      0
  1      1
  2      2
A 0      3
  1      4
  2      5

[6 rows x 1 columns]
In [87]: df.index.is_lexsorted()
Out[87]: False

In [88]: df.index.is_monotonic
Out[88]: False

Сортировка работает как ожидается

In [76]: df.sort_index()
Out[76]: 
                     a
2011-12-31 23:59:59  1
2012-01-01 00:00:00  2
2012-01-01 00:00:01  3

[3 rows x 1 columns]
In [90]: df.sort_index().index.is_lexsorted()
Out[90]: True

In [91]: df.sort_index().index.is_monotonic
Out[91]: True

Однако этот пример, имеющий немонотонный 2-й уровень, не ведёт себя как ожидалось.

In [77]: df = pd.DataFrame({'value': [1, 2, 3, 4]},
   ....:                   index=pd.MultiIndex([['a', 'b'], ['bb', 'aa']],
   ....:                                       [[0, 0, 1, 1], [0, 1, 0, 1]]))
   ....: 

In [78]: df
Out[78]: 
      value
a bb      1
  aa      2
b bb      3
  aa      4

[4 rows x 1 columns]

Предыдущее поведение:

In [11]: df.sort_index()
Out[11]:
      value
a bb      1
  aa      2
b bb      3
  aa      4

In [14]: df.sort_index().index.is_lexsorted()
Out[14]: True

In [15]: df.sort_index().index.is_monotonic
Out[15]: False

Новое поведение:

In [94]: df.sort_index()
Out[94]:
      value
a aa      2
  bb      1
b aa      4
  bb      3

[4 rows x 1 columns]

In [95]: df.sort_index().index.is_lexsorted()
Out[95]: True

In [96]: df.sort_index().index.is_monotonic
Out[96]: True

Форматирование GroupBy describe#

Форматирование вывода groupby.describe() теперь помечает describe() метрики в столбцах вместо индекса. Этот формат согласуется с groupby.agg() при применении нескольких функций одновременно. (GH 4792)

Предыдущее поведение:

In [1]: df = pd.DataFrame({'A': [1, 1, 2, 2], 'B': [1, 2, 3, 4]})

In [2]: df.groupby('A').describe()
Out[2]:
                B
A
1 count  2.000000
  mean   1.500000
  std    0.707107
  min    1.000000
  25%    1.250000
  50%    1.500000
  75%    1.750000
  max    2.000000
2 count  2.000000
  mean   3.500000
  std    0.707107
  min    3.000000
  25%    3.250000
  50%    3.500000
  75%    3.750000
  max    4.000000

In [3]: df.groupby('A').agg(["mean", "std", "min", "max"])
Out[3]:
     B
  mean       std amin amax
A
1  1.5  0.707107    1    2
2  3.5  0.707107    3    4

Новое поведение:

In [79]: df = pd.DataFrame({'A': [1, 1, 2, 2], 'B': [1, 2, 3, 4]})

In [80]: df.groupby('A').describe()
Out[80]: 
      B                                          
  count mean       std  min   25%  50%   75%  max
A                                                
1   2.0  1.5  0.707107  1.0  1.25  1.5  1.75  2.0
2   2.0  3.5  0.707107  3.0  3.25  3.5  3.75  4.0

[2 rows x 8 columns]

In [81]: df.groupby('A').agg(["mean", "std", "min", "max"])
Out[81]: 
     B                  
  mean       std min max
A                       
1  1.5  0.707107   1   2
2  3.5  0.707107   3   4

[2 rows x 4 columns]

Бинарные операции окна corr/cov возвращают DataFrame с MultiIndex#

Бинарная операция окна, например, .corr() или .cov(), при работе с .rolling(..), .expanding(..), или .ewm(..) object, теперь будет возвращать 2-уровневый MultiIndexed DataFrame а не Panel, как Panel теперь устарел, см. здесь. Они эквивалентны по функции, но MultiIndexed DataFrame имеет большую поддержку в pandas. См. раздел о Оконные бинарные операции для получения дополнительной информации. (GH 15677)

In [82]: np.random.seed(1234)

In [83]: df = pd.DataFrame(np.random.rand(100, 2),
   ....:                   columns=pd.Index(['A', 'B'], name='bar'),
   ....:                   index=pd.date_range('20160101',
   ....:                                       periods=100, freq='D', name='foo'))
   ....: 

In [84]: df.tail()
Out[84]: 
bar                A         B
foo                           
2016-04-05  0.640880  0.126205
2016-04-06  0.171465  0.737086
2016-04-07  0.127029  0.369650
2016-04-08  0.604334  0.103104
2016-04-09  0.802374  0.945553

[5 rows x 2 columns]

Предыдущее поведение:

In [2]: df.rolling(12).corr()
Out[2]:

Dimensions: 100 (items) x 2 (major_axis) x 2 (minor_axis)
Items axis: 2016-01-01 00:00:00 to 2016-04-09 00:00:00
Major_axis axis: A to B
Minor_axis axis: A to B

Новое поведение:

In [85]: res = df.rolling(12).corr()

In [86]: res.tail()
Out[86]: 
bar                    A         B
foo        bar                    
2016-04-07 B   -0.132090  1.000000
2016-04-08 A    1.000000 -0.145775
           B   -0.145775  1.000000
2016-04-09 A    1.000000  0.119645
           B    0.119645  1.000000

[5 rows x 2 columns]

Получение матрицы корреляций для поперечного сечения

In [87]: df.rolling(12).corr().loc['2016-04-07']
Out[87]: 
bar        A        B
bar                  
A    1.00000 -0.13209
B   -0.13209  1.00000

[2 rows x 2 columns]

HDFStore, где сравнение строк#

В предыдущих версиях большинство типов можно было сравнивать со строковым столбцом в HDFStore обычно приводящее к недопустимому сравнению, возвращающему пустой фрейм результатов. Такие сравнения теперь будут вызывать TypeError (GH 15492)

In [88]: df = pd.DataFrame({'unparsed_date': ['2014-01-01', '2014-01-01']})

In [89]: df.to_hdf('store.h5', key='key', format='table', data_columns=True)

In [90]: df.dtypes
Out[90]: 
unparsed_date    object
Length: 1, dtype: object

Предыдущее поведение:

In [4]: pd.read_hdf('store.h5', 'key', where='unparsed_date > ts')
File "", line 1
  (unparsed_date > 1970-01-01 00:00:01.388552400)
                        ^
SyntaxError: invalid token

Новое поведение:

In [18]: ts = pd.Timestamp('2014-01-01')

In [19]: pd.read_hdf('store.h5', 'key', where='unparsed_date > ts')
TypeError: Cannot compare 2014-01-01 00:00:00 of
type  to string column

Index.intersection и внутреннее соединение теперь сохраняют порядок левого индекса#

Index.intersection() теперь сохраняет порядок вызова Index (слева) вместо другого Index (справа) (GH 15582). Это влияет на внутренние объединения, DataFrame.join() и merge()должны быть включены в старые категории. Значения, которые были в удаленных категориях, будут установлены в NaN .align метод.

  • Index.intersection

    In [91]: left = pd.Index([2, 1, 0])
    
    In [92]: left
    Out[92]: Index([2, 1, 0], dtype='int64')
    
    In [93]: right = pd.Index([1, 2, 3])
    
    In [94]: right
    Out[94]: Index([1, 2, 3], dtype='int64')
    

    Предыдущее поведение:

    In [4]: left.intersection(right)
    Out[4]: Int64Index([1, 2], dtype='int64')
    

    Новое поведение:

    In [95]: left.intersection(right)
    Out[95]: Index([2, 1], dtype='int64')
    
  • DataFrame.join и pd.merge

    In [96]: left = pd.DataFrame({'a': [20, 10, 0]}, index=[2, 1, 0])
    
    In [97]: left
    Out[97]: 
        a
    2  20
    1  10
    0   0
    
    [3 rows x 1 columns]
    
    In [98]: right = pd.DataFrame({'b': [100, 200, 300]}, index=[1, 2, 3])
    
    In [99]: right
    Out[99]: 
         b
    1  100
    2  200
    3  300
    
    [3 rows x 1 columns]
    

    Предыдущее поведение:

    In [4]: left.join(right, how='inner')
    Out[4]:
       a    b
    1  10  100
    2  20  200
    

    Новое поведение:

    In [100]: left.join(right, how='inner')
    Out[100]: 
        a    b
    2  20  200
    1  10  100
    
    [2 rows x 2 columns]
    

Сводная таблица всегда возвращает DataFrame#

Документация для pivot_table() утверждает, что DataFrame является всегда возвращена. Здесь исправлена ошибка, которая позволяла возвращать Series при определенных обстоятельствах. (GH 4386)

In [101]: df = pd.DataFrame({'col1': [3, 4, 5],
   .....:                    'col2': ['C', 'D', 'E'],
   .....:                    'col3': [1, 3, 9]})
   .....: 

In [102]: df
Out[102]: 
   col1 col2  col3
0     3    C     1
1     4    D     3
2     5    E     9

[3 rows x 3 columns]

Предыдущее поведение:

In [2]: df.pivot_table('col1', index=['col3', 'col2'], aggfunc="sum")
Out[2]:
col3  col2
1     C       3
3     D       4
9     E       5
Name: col1, dtype: int64

Новое поведение:

In [103]: df.pivot_table('col1', index=['col3', 'col2'], aggfunc="sum")
Out[103]: 
           col1
col3 col2      
1    C        3
3    D        4
9    E        5

[3 rows x 1 columns]

Другие изменения API#

  • numexpr теперь требуется версия >= 2.4.6, и она не будет использоваться вообще, если это требование не выполнено (GH 15213).

  • CParserError был переименован в ParserError в pd.read_csv() и будет удалено в будущем (GH 12665)

  • SparseArray.cumsum() и SparseSeries.cumsum() теперь всегда будет возвращать SparseArray и SparseSeries соответственно (GH 12855)

  • DataFrame.applymap() с пустым DataFrame вернёт копию пустого DataFrame вместо Series (GH 8222)

  • Series.map() теперь учитывает значения по умолчанию подклассов словаря с __missing__ метод, такой как collections.Counter (GH 15999)

  • .loc имеет совместимость с .ix для принятия итераторов и NamedTuples (GH 15120)

  • interpolate() и fillna() вызовет ValueError если limit аргумент ключевого слова не больше 0. (GH 9217)

  • pd.read_csv() теперь будет выдавать ParserWarning всякий раз, когда есть конфликтующие значения, предоставленные dialect параметр и пользователь (GH 14898)

  • pd.read_csv() теперь вызовет ValueError для движка C, если символ кавычки больше одного байта (GH 11592)

  • inplace аргументы теперь требуют булево значение, иначе ValueError выбрасывается (GH 14189)

  • pandas.api.types.is_datetime64_ns_dtype теперь будет сообщать True на tz-aware dtype, аналогично pandas.api.types.is_datetime64_any_dtype

  • DataFrame.asof() вернёт заполненный null Series вместо скаляра NaN если совпадение не найдено (GH 15118)

  • Специальная поддержка для copy.copy() и copy.deepcopy() функции на объектах NDFrame (GH 15444)

  • Series.sort_values() принимает список из одного логического значения для согласованности с поведением DataFrame.sort_values() (GH 15604)

  • .merge() и .join() на category столбцы dtype теперь будут сохранять категориальный dtype, когда это возможно (GH 10409)

  • SparseDataFrame.default_fill_value будет 0, ранее было nan в возвращаемом значении из pd.get_dummies(..., sparse=True) (GH 15594)

  • Поведение по умолчанию Series.str.match изменилось с извлечения групп на сопоставление с шаблоном. Поведение извлечения было устаревшим начиная с версии pandas 0.13.0 и может быть выполнено с помощью Series.str.extract метод (GH 5224). Как следствие, as_indexer ключевое слово игнорируется (больше не нужно указывать новое поведение) и устарело.

  • NaT теперь будет корректно сообщать False для логических операций с датами и временем, таких как is_month_start (GH 15781)

  • NaT теперь будет корректно возвращать np.nan для Timedelta и Period аксессоры, такие как days и quarter (GH 15782)

  • NaT теперь возвращает NaT для tz_localize и tz_convert методы (GH 15830)

  • DataFrame и Panel конструкторы с недопустимыми входными данными теперь будут вызывать ValueError вместо PandasError, если вызывается со скалярными входами и без осей (GH 15541)

  • DataFrame и Panel конструкторы с недопустимыми входными данными теперь будут вызывать ValueError вместо pandas.core.common.PandasError, если вызывается со скалярными входами и не осями; Исключение PandasError также удален. (GH 15541)

  • Исключение pandas.core.common.AmbiguousIndexError удален, так как на него нет ссылок (GH 15541)

Реорганизация библиотеки: изменения конфиденциальности#

Изменена приватность модулей#

Некоторые ранее публичные модули расширений python/c/c++/cython были перемещены и/или переименованы. Все они удалены из публичного API. Кроме того, pandas.core, pandas.compat, и pandas.util модули верхнего уровня теперь считаются ПРИВАТНЫМИ. Если указано, будет выдано предупреждение об устаревании при обращении к этим модулям. (GH 12588)

Предыдущее местоположение

Новое местоположение

Устаревший

pandas.lib

pandas._libs.lib

X

pandas.tslib

pandas._libs.tslib

X

pandas.computation

pandas.core.computation

X

pandas.msgpack

pandas.io.msgpack

pandas.index

pandas._libs.index

pandas.algos

pandas._libs.algos

pandas.hashtable

pandas._libs.hashtable

pandas.indexes

pandas.core.indexes

pandas.json

pandas._libs.json / pandas.io.json

X

pandas.parser

pandas._libs.parsers

X

pandas.formats

pandas.io.formats

pandas.sparse

pandas.core.sparse

pandas.tools

pandas.core.reshape

X

pandas.types

pandas.core.dtypes

X

pandas.io.sas.saslib

pandas.io.sas._sas

pandas._join

pandas._libs.join

pandas._hash

pandas._libs.hashing

pandas._period

pandas._libs.period

pandas._sparse

pandas._libs.sparse

pandas._testing

pandas._libs.testing

pandas._window

pandas._libs.window

Некоторые новые подпакеты созданы с публичной функциональностью, которая не представлена напрямую в пространстве имен верхнего уровня: pandas.errors, pandas.plotting и pandas.testing (подробнее ниже). Вместе с pandas.api.types и определенные функции в pandas.io и pandas.tseries подмодули, теперь это публичные подпакеты.

Дополнительные изменения:

  • Функция union_categoricals() теперь импортируется из pandas.api.types, ранее из pandas.types.concat (GH 15998)

  • Импорт типа pandas.tslib.NaTType устарел и может быть заменен использованием type(pandas.NaT) (GH 16146)

  • Публичные функции в pandas.tools.hashing устарели в этих местах, но теперь импортируются из pandas.util (GH 16223)

  • Модули в pandas.util: decorators, print_versions, doctools, validators, depr_module теперь являются приватными. Только функции, представленные в pandas.util сами являются публичными (GH 16223)

pandas.errors#

Мы добавляем стандартный публичный модуль для всех исключений и предупреждений pandas pandas.errors. (GH 14800). Ранее эти исключения и предупреждения можно было импортировать из pandas.core.common или pandas.io.common. Эти исключения и предупреждения будут удалены из *.common местоположения в будущем выпуске. (GH 15541)

Следующие элементы теперь являются частью этого API:

['DtypeWarning',
 'EmptyDataError',
 'OutOfBoundsDatetime',
 'ParserError',
 'ParserWarning',
 'PerformanceWarning',
 'UnsortedIndexError',
 'UnsupportedFunctionCall']

pandas.testing#

Мы добавляем стандартный модуль, который предоставляет публичные тестовые функции в pandas.testing (GH 9895). Эти функции можно использовать при написании тестов для функциональности, использующей объекты pandas.

Следующие тестовые функции теперь являются частью этого API:

pandas.plotting#

Новый публичный pandas.plotting модуль был добавлен, содержащий функциональность построения графиков, которая ранее находилась либо в pandas.tools.plotting или в пространстве имен верхнего уровня. См. разделы об устаревании для получения дополнительной информации.

Другие изменения в разработке#

  • Сборка pandas для разработки теперь требует cython >= 0.23 (GH 14831)

  • Требуется как минимум версия 0.23 cython, чтобы избежать проблем с кодировками символов (GH 14699)

  • Переключил тестовый фреймворк на использование pytest (GH 13097)

  • Реорганизация структуры каталога тестов (GH 14854, GH 15707).

Устаревшие функции#

Устарело .ix#

The .ix indexer устарел, в пользу более строгого .iloc и .loc индексаторы. .ix предлагает много магии в определении того, что пользователь хочет сделать. Более конкретно, .ix может решить индексировать позиционно ИЛИ через метки, в зависимости от типа данных индекса. Это вызывало значительную путаницу у пользователей на протяжении многих лет. Полная документация по индексированию находится здесь. (GH 14218)

Рекомендуемые методы индексации:

  • .loc если вы хотите метка index

  • .iloc если вы хотите позиционно index.

Используя .ix теперь будет показывать DeprecationWarning со ссылкой на некоторые примеры преобразования кода здесь.

In [104]: df = pd.DataFrame({'A': [1, 2, 3],
   .....:                    'B': [4, 5, 6]},
   .....:                   index=list('abc'))
   .....: 

In [105]: df
Out[105]: 
   A  B
a  1  4
b  2  5
c  3  6

[3 rows x 2 columns]

Предыдущее поведение, когда вы хотите получить 0-й и 2-й элементы из индекса в столбце 'A'.

In [3]: df.ix[[0, 2], 'A']
Out[3]:
a    1
c    3
Name: A, dtype: int64

Используя .loc. Здесь мы выберем соответствующие индексы из индекса, затем используем метка индексация.

In [106]: df.loc[df.index[[0, 2]], 'A']
Out[106]: 
a    1
c    3
Name: A, Length: 2, dtype: int64

Используя .iloc. Здесь мы получим расположение столбца 'A', затем используем позиционный индексация для выбора элементов.

In [107]: df.iloc[[0, 2], df.columns.get_loc('A')]
Out[107]: 
a    1
c    3
Name: A, Length: 2, dtype: int64

Устаревание Panel#

Panel устарело и будет удалено в будущей версии. Рекомендуемый способ представления 3-D данных — MultiIndex на DataFrame через to_frame() или с пакет xarray. pandas предоставляет to_xarray() метод для автоматизации этого преобразования (GH 13563).

In [133]: import pandas._testing as tm

In [134]: p = tm.makePanel()

In [135]: p
Out[135]:

Dimensions: 3 (items) x 3 (major_axis) x 4 (minor_axis)
Items axis: ItemA to ItemC
Major_axis axis: 2000-01-03 00:00:00 to 2000-01-05 00:00:00
Minor_axis axis: A to D

Преобразовать в DataFrame с MultiIndex

In [136]: p.to_frame()
Out[136]:
                     ItemA     ItemB     ItemC
major      minor
2000-01-03 A      0.628776 -1.409432  0.209395
           B      0.988138 -1.347533 -0.896581
           C     -0.938153  1.272395 -0.161137
           D     -0.223019 -0.591863 -1.051539
2000-01-04 A      0.186494  1.422986 -0.592886
           B     -0.072608  0.363565  1.104352
           C     -1.239072 -1.449567  0.889157
           D      2.123692 -0.414505 -0.319561
2000-01-05 A      0.952478 -2.147855 -1.473116
           B     -0.550603 -0.014752 -0.431550
           C      0.139683 -1.195524  0.288377
           D      0.122273 -1.425795 -0.619993

[12 rows x 3 columns]

Преобразовать в DataArray xarray

In [137]: p.to_xarray()
Out[137]:

array([[[ 0.628776,  0.988138, -0.938153, -0.223019],
        [ 0.186494, -0.072608, -1.239072,  2.123692],
        [ 0.952478, -0.550603,  0.139683,  0.122273]],

       [[-1.409432, -1.347533,  1.272395, -0.591863],
        [ 1.422986,  0.363565, -1.449567, -0.414505],
        [-2.147855, -0.014752, -1.195524, -1.425795]],

       [[ 0.209395, -0.896581, -0.161137, -1.051539],
        [-0.592886,  1.104352,  0.889157, -0.319561],
        [-1.473116, -0.43155 ,  0.288377, -0.619993]]])
Coordinates:
  * items       (items) object 'ItemA' 'ItemB' 'ItemC'
  * major_axis  (major_axis) datetime64[ns] 2000-01-03 2000-01-04 2000-01-05
  * minor_axis  (minor_axis) object 'A' 'B' 'C' 'D'

Устаревание groupby.agg() со словарём при переименовании#

The .groupby(..).agg(..), .rolling(..).agg(..), и .resample(..).agg(..) синтаксис может принимать переменное количество входных данных, включая скаляры, списки и словарь имен столбцов к скалярам или спискам. Это предоставляет полезный синтаксис для построения нескольких (потенциально различных) агрегаций.

Однако, .agg(..) может также принимает словарь, позволяющий 'переименовать' результирующие столбцы. Это сложный и запутанный синтаксис, а также не согласованный между Series и DataFrame. Мы устареваем эту функциональность 'переименования'.

  • Мы устареваем передачу словаря в сгруппированный/скользящий/передискретизированный Series. Это позволяло rename результирующая агрегация, но это имело совершенно другое значение, чем передача словаря в сгруппированный DataFrame, который принимает столбцы для агрегации.

  • Мы устареваем передачу словаря-словарей в сгруппированный/скользящий/передискретизированный DataFrame аналогичным образом.

Это иллюстративный пример:

In [108]: df = pd.DataFrame({'A': [1, 1, 1, 2, 2],
   .....:                    'B': range(5),
   .....:                    'C': range(5)})
   .....: 

In [109]: df
Out[109]: 
   A  B  C
0  1  0  0
1  1  1  1
2  1  2  2
3  2  3  3
4  2  4  4

[5 rows x 3 columns]

Вот типичный полезный синтаксис для вычисления различных агрегаций для разных столбцов. Это естественный и полезный синтаксис. Мы агрегируем из словаря в список, беря указанные столбцы и применяя список функций. Это возвращает MultiIndex для столбцов (это не устарело).

In [110]: df.groupby('A').agg({'B': 'sum', 'C': 'min'})
Out[110]: 
   B  C
A      
1  3  0
2  7  3

[2 rows x 2 columns]

Вот пример первого устаревания, передача словаря в сгруппированный Series. Это комбинация агрегации и переименования:

In [6]: df.groupby('A').B.agg({'foo': 'count'})
FutureWarning: using a dict on a Series for aggregation
is deprecated and will be removed in a future version

Out[6]:
   foo
A
1    3
2    2

Вы можете выполнить ту же операцию более идиоматично:

In [111]: df.groupby('A').B.agg(['count']).rename(columns={'count': 'foo'})
Out[111]: 
   foo
A     
1    3
2    2

[2 rows x 1 columns]

Вот пример второго устаревания, передача словаря-из-словарей в сгруппированный DataFrame:

In [23]: (df.groupby('A')
    ...:    .agg({'B': {'foo': 'sum'}, 'C': {'bar': 'min'}})
    ...:  )
FutureWarning: using a dict with renaming is deprecated and
will be removed in a future version

Out[23]:
     B   C
   foo bar
A
1   3   0
2   7   3

Вы можете достичь почти того же результата с помощью:

In [112]: (df.groupby('A')
   .....:    .agg({'B': 'sum', 'C': 'min'})
   .....:    .rename(columns={'B': 'foo', 'C': 'bar'})
   .....:  )
   .....: 
Out[112]: 
   foo  bar
A          
1    3    0
2    7    3

[2 rows x 2 columns]

Устаревание .plotting#

The pandas.tools.plotting модуль устарел, в пользу верхнего уровня pandas.plotting модуль. Все публичные функции построения графиков теперь доступны из pandas.plotting (GH 12548).

Кроме того, верхнеуровневый pandas.scatter_matrix и pandas.plot_params устарели. Пользователи могут импортировать их из pandas.plotting также.

Предыдущий скрипт:

pd.tools.plotting.scatter_matrix(df)
pd.scatter_matrix(df)

Следует изменить на:

pd.plotting.scatter_matrix(df)

Другие устаревшие функции#

  • SparseArray.to_dense() устарел fill параметр, так как этот параметр не учитывался (GH 14647)

  • SparseSeries.to_dense() устарел sparse_only параметр (GH 14647)

  • Series.repeat() устарел reps параметр в пользу repeats (GH 12662)

  • The Series конструкторе и .astype метод устарел для приёма timestamp dtypes без частоты (например, np.datetime64) для dtype параметр (GH 15524)

  • Index.repeat() и MultiIndex.repeat() устарели n параметр в пользу repeats (GH 12662)

  • Categorical.searchsorted() и Series.searchsorted() устарели v параметр в пользу value (GH 12662)

  • TimedeltaIndex.searchsorted(), DatetimeIndex.searchsorted(), и PeriodIndex.searchsorted() устарели key параметр в пользу value (GH 12662)

  • DataFrame.astype() устарел raise_on_error параметр в пользу errors (GH 14878)

  • Series.sortlevel и DataFrame.sortlevel устарели в пользу Series.sort_index и DataFrame.sort_index (GH 15099)

  • импорт concat из pandas.tools.merge был объявлен устаревшим в пользу импорта из pandas пространство имён. Это должно затрагивать только явные импорты (GH 15358)

  • Series/DataFrame/Panel.consolidate() был устаревшим как публичный метод. (GH 15483)

  • The as_indexer ключевое слово Series.str.match() был устаревшим (игнорируемое ключевое слово) (GH 15257).

  • Следующие функции верхнего уровня pandas устарели и будут удалены в будущей версии (GH 13790, GH 15940)

    • pd.pnow(), заменено на Period.now()

    • pd.Term, удален, так как он не применим к пользовательскому коду. Вместо этого используйте встроенные строковые выражения в условии where при поиске в HDFStore

    • pd.Expr, удален, так как не применим к пользовательскому коду.

    • pd.match(), удаляется.

    • pd.groupby(), заменено использованием .groupby() метод непосредственно на Series/DataFrame

    • pd.get_store(), заменено прямым вызовом pd.HDFStore(...)

  • is_any_int_dtype, is_floating_dtype, и is_sequence устарели с pandas.api.types (GH 16042)

Удаление устаревших функций/изменений предыдущих версий#

  • The pandas.rpy модуль удален. Похожий функционал можно получить через rpy2 проект. См. Документация по интерфейсу с R для получения дополнительной информации.

  • The pandas.io.ga модуль с google-analytics интерфейс удалён (GH 11308). Аналогичную функциональность можно найти в Google2Pandas пакет.

  • pd.to_datetime и pd.to_timedelta удалили coerce параметр в пользу errors (GH 13602)

  • pandas.stats.fama_macbeth, pandas.stats.ols, pandas.stats.plm и pandas.stats.var, а также на верхнем уровне pandas.fama_macbeth и pandas.ols процедуры удалены. Аналогичную функциональность можно найти в statsmodels пакет. (GH 11898)

  • The TimeSeries и SparseTimeSeries классы, псевдонимы Series и SparseSeries, удалены (GH 10890, GH 15098).

  • Series.is_time_series удалено в пользу Series.index.is_all_dates (GH 15098)

  • Устаревший irow, icol, iget и iget_value методы удалены в пользу iloc и iat как объяснено здесь (GH 10711).

  • Устаревший DataFrame.iterkv() был удалён в пользу DataFrame.iteritems() (GH 10711)

  • The Categorical конструктор удалил name параметр (GH 10632)

  • Categorical прекратил поддержку NaN категории (GH 10748)

  • The take_last параметр был удалён из duplicated(), drop_duplicates(), nlargest(), и nsmallest() методы (GH 10236, GH 10792, GH 10920)

  • Series, Index, и DataFrame удалили sort и order методы (GH 10726)

  • Предложения WHERE в pytables принимаются только как строки и типы выражений, а не другие типы данных (GH 12027)

  • DataFrame удалил combineAdd и combineMult методы в пользу add и mul соответственно (GH 10735)

Улучшения производительности#

  • Улучшена производительность pd.wide_to_long() (GH 14779)

  • Улучшена производительность pd.factorize() путем освобождения GIL с помощью object тип данных, когда выводится как строки (GH 14859, GH 16057)

  • Улучшена производительность построения временных рядов с нерегулярным DatetimeIndex (или с compat_x=True) (GH 15073).

  • Улучшена производительность groupby().cummin() и groupby().cummax() (GH 15048, GH 15109, GH 15561, GH 15635)

  • Улучшена производительность и уменьшено использование памяти при индексации с помощью MultiIndex (GH 15245)

  • При чтении буферного объекта в read_sas() метод без указанного формата, строка пути к файлу выводится, а не объект буфера. (GH 14947)

  • Улучшена производительность .rank() для категориальных данных (GH 15498)

  • Улучшенная производительность при использовании .unstack() (GH 15503)

  • Улучшена производительность слияния/объединения category столбцы (GH 10409)

  • Улучшена производительность drop_duplicates() на bool столбцы (GH 12963)

  • Улучшена производительность pd.core.groupby.GroupBy.apply когда применённая функция использовала .name атрибут группового DataFrame (GH 15062).

  • Улучшена производительность iloc индексирование списком или массивом (GH 15504).

  • Улучшена производительность Series.sort_index() с монотонным индексом (GH 15694)

  • Улучшена производительность в pd.read_csv() на некоторых платформах с буферизованным чтением (GH 16039)

Исправления ошибок#

Преобразование#

  • Ошибка в Timestamp.replace теперь вызывает TypeError при указании некорректных имен аргументов; ранее это вызывало ValueError (GH 15240)

  • Ошибка в Timestamp.replace с совместимостью для передачи длинных целых чисел (GH 15030)

  • Ошибка в Timestamp возвращая атрибуты времени/даты на основе UTC, когда был предоставлен часовой пояс (GH 13303, GH 6538)

  • Ошибка в Timestamp неправильная локализация часовых поясов при создании (GH 11481, GH 15777)

  • Ошибка в TimedeltaIndex сложение, где переполнение допускалось без ошибки (GH 14816)

  • Ошибка в TimedeltaIndex вызов ValueError при булевом индексировании с loc (GH 14946)

  • Ошибка в перехвате переполнения в Timestamp + Timedelta/Offset операции (GH 15126)

  • Ошибка в DatetimeIndex.round() и Timestamp.round() точность с плавающей запятой при округлении на миллисекунды или меньше (GH 14440, GH 15578)

  • Ошибка в astype() где inf значения были некорректно преобразованы в целые числа. Теперь выдает ошибку с astype() для Series и DataFrames (GH 14265)

  • Ошибка в DataFrame(..).apply(to_numeric) когда значения имеют тип decimal.Decimal. (GH 14827)

  • Ошибка в describe() при передаче массива numpy, который не содержит медиану, в percentiles именованный аргумент (GH 14908)

  • Очищено PeriodIndex конструктора, включая более последовательное возбуждение исключений для чисел с плавающей точкой (GH 13277)

  • Ошибка при использовании __deepcopy__ на пустых объектах NDFrame (GH 15370)

  • Ошибка в .replace() может привести к неверным типам данных. (GH 12747, GH 15765)

  • Ошибка в Series.replace и DataFrame.replace который не работал с пустыми словарями замены (GH 15289)

  • Ошибка в Series.replace который заменил числовое значение строковым (GH 15743)

  • Ошибка в Index создание с NaN элементы и указанный целочисленный тип данных (GH 15187)

  • Ошибка в Series конструкция с datetimetz (GH 14928)

  • Ошибка в Series.dt.round() непоследовательное поведение на NaT ‘s с разными аргументами (GH 14940)

  • Ошибка в Series конструктор, когда оба copy=True и dtype предоставлены аргументы (GH 15125)

  • Некорректный тип данных Series возвращался методами сравнения (например, lt, gt, …) против константы для пустого DataFrame (GH 15077)

  • Ошибка в Series.ffill() со смешанными типами данных, содержащими даты с учетом часового пояса. (GH 14956)

  • Ошибка в DataFrame.fillna() где аргумент downcast игнорировалось, когда значение fillna было типа dict (GH 15277)

  • Ошибка в .asfreq(), где частота не была установлена для пустого Series (GH 14320)

  • Ошибка в DataFrame конструкция с null и датами в спискообразном (GH 15869)

  • Ошибка в DataFrame.fillna() с датами с учетом часового пояса (GH 15855)

  • Ошибка в is_string_dtype, is_timedelta64_ns_dtype, и is_string_like_dtype в котором возникала ошибка, когда None был передан (GH 15941)

  • Ошибка в типе возвращаемого значения pd.unique на Categorical, который возвращал ndarray, а не Categorical (GH 15903)

  • Ошибка в Index.to_series() где индекс не был скопирован (и последующее изменение изменило бы оригинал), (GH 15949)

  • Ошибка при индексировании с частичным строковым индексированием с DataFrame длины 1 (GH 16071)

  • Ошибка в Series создание, при котором передача недопустимого dtype не вызывала ошибку. (GH 15520)

Индексирование#

  • Ошибка в Index операции возведения в степень с обратными операндами (GH 14973)

  • Ошибка в DataFrame.sort_values() при сортировке по нескольким столбцам, где один столбец имеет тип int64 и содержит NaT (GH 14922)

  • Ошибка в DataFrame.reindex() в котором method игнорировалось при передаче columns (GH 14992)

  • Ошибка в DataFrame.loc при индексации MultiIndex с Series индексатор (GH 14730, GH 15424)

  • Ошибка в DataFrame.loc при индексации MultiIndex с массивом numpy (GH 15434)

  • Ошибка в Series.asof которая возникала, если ряд содержал все np.nan (GH 15713)

  • Ошибка в .at при выборе из столбца с информацией о часовом поясе (GH 15822)

  • Ошибка в Series.where() и DataFrame.where() где условные выражения в виде массивов отклонялись (GH 15414)

  • Ошибка в Series.where() где данные с учетом часового пояса были преобразованы в представление с плавающей запятой (GH 15701)

  • Ошибка в .loc что не вернёт правильный dtype для скалярного доступа к DataFrame (GH 11617)

  • Ошибка в форматировании вывода MultiIndex когда имена являются целыми числами (GH 12223, GH 15262)

  • Ошибка в Categorical.searchsorted() где использовался алфавитный порядок вместо предоставленного категориального (GH 14522)

  • Ошибка в Series.iloc где Categorical объект для ввода индексов в виде списка был возвращен, где Series ожидалось. (GH 14580)

  • Ошибка в DataFrame.isin сравнение дат/времени с пустым фреймом (GH 15473)

  • Ошибка в .reset_index() когда все NaN уровень MultiIndex завершится неудачей (GH 6322)

  • Ошибка в .reset_index() при вызове ошибки для имени индекса, уже присутствующего в MultiIndex столбцы (GH 16120)

  • Ошибка при создании MultiIndex с кортежами без передачи списка имен; теперь это будет вызывать ошибку ValueError (GH 15110)

  • Ошибка в HTML отображении с MultiIndex и усечение (GH 14882)

  • Ошибка в отображении .info() где квалификатор (+) всегда отображался бы с MultiIndex который содержит только нестроковые значения (GH 15245)

  • Ошибка в pd.concat() где имена MultiIndex результирующего DataFrame не обрабатываются корректно, когда None представлено в названиях MultiIndex ввода DataFrame (GH 15787)

  • Ошибка в DataFrame.sort_index() и Series.sort_index() где na_position не работает с MultiIndex (GH 14784, GH 16604)

  • Ошибка в pd.concat() при объединении объектов с CategoricalIndex (GH 16111)

  • Ошибка при индексации со скаляром и CategoricalIndex (GH 16123)

Ввод-вывод#

  • Ошибка в pd.to_numeric() в котором элементы с плавающей точкой и беззнаковые целые числа неправильно приводились (GH 14941, GH 15005)

  • Ошибка в pd.read_fwf() где параметр skiprows не учитывался при определении ширины столбцов (GH 11256)

  • Ошибка в pd.read_csv() в котором dialect параметр не проверялся перед обработкой (GH 14898)

  • Ошибка в pd.read_csv() в котором отсутствующие данные неправильно обрабатывались с usecols (GH 6710)

  • Ошибка в pd.read_csv() в котором файл, содержащий строку со многими столбцами, за которой следуют строки с меньшим количеством столбцов, вызывал сбой (GH 14125)

  • Ошибка в pd.read_csv() для движка C, где usecols индексировались некорректно с parse_dates (GH 14792)

  • Ошибка в pd.read_csv() с parse_dates когда указаны многострочные заголовки (GH 15376)

  • Ошибка в pd.read_csv() с float_precision='round_trip' что вызывало ошибку сегментации при разборе текстовой записи (GH 15140)

  • Ошибка в pd.read_csv() когда был указан индекс и никакие значения не были указаны как нулевые значения (GH 15835)

  • Ошибка в pd.read_csv() в котором некоторые недопустимые файловые объекты вызывали сбой интерпретатора Python (GH 15337)

  • Ошибка в pd.read_csv() в котором недопустимые значения для nrows и chunksize были разрешены (GH 15767)

  • Ошибка в pd.read_csv() для движка Python, в котором выводились бесполезные сообщения об ошибках при возникновении ошибок парсинга (GH 15910)

  • Ошибка в pd.read_csv() в котором skipfooter параметр не проходил должную проверку (GH 15925)

  • Ошибка в pd.to_csv() в котором происходило числовое переполнение при записи временного индекса (GH 15982)

  • Ошибка в pd.util.hashing.hash_pandas_object() в котором хеширование категориальных данных зависело от порядка категорий, а не только от их значений. (GH 15143)

  • Ошибка в .to_json() где lines=True и содержимое (ключи или значения) содержит экранированные символы (GH 15096)

  • Ошибка в .to_json() вызывая расширение однобайтовых ASCII-символов до четырехбайтовых Unicode (GH 15344)

  • Ошибка в .to_json() для движка C, где переполнение не обрабатывалось корректно для случая, когда frac нечетное и diff равно точно 0.5 (GH 15716, GH 15864)

  • Ошибка в pd.read_json() для Python 2, где lines=True и содержимое содержит не-ASCII символы Unicode (GH 15132)

  • Ошибка в pd.read_msgpack() в котором Series категориальные переменные обрабатывались некорректно (GH 14901)

  • Ошибка в pd.read_msgpack() который не позволял загрузить датафрейм с индексом типа CategoricalIndex (GH 15487)

  • Ошибка в pd.read_msgpack() при десериализации CategoricalIndex (GH 15487)

  • Ошибка в DataFrame.to_records() при преобразовании DatetimeIndex с часовым поясом (GH 13937)

  • Ошибка в DataFrame.to_records() который завершался сбоем при наличии символов Unicode в именах столбцов (GH 11879)

  • Ошибка в .to_sql() при записи DataFrame с числовыми именами индексов (GH 15404).

  • Ошибка в DataFrame.to_html() с index=False и max_rows вызов исключения в IndexError (GH 14998)

  • Ошибка в pd.read_hdf() передача Timestamp в where параметр с недатовым столбцом (GH 15492)

  • Ошибка в DataFrame.to_stata() и StataWriter что приводит к созданию некорректно отформатированных файлов для некоторых локалей (GH 13856)

  • Ошибка в StataReader и StataWriter который допускает недопустимые кодировки (GH 15723)

  • Ошибка в Series repr не показывает длину, когда вывод был усечен (GH 15962).

Построение графиков#

  • Ошибка в DataFrame.hist где plt.tight_layout вызвал AttributeError (используйте matplotlib >= 2.0.1) (GH 9351)

  • Ошибка в DataFrame.boxplot где fontsize операции между объектами несовместимых типов данных, результат будет базовымGH 15108)

  • Ошибка в конвертерах даты и времени, которые pandas регистрирует в matplotlib, не обрабатывающих многомерные данные (GH 16026)

  • Ошибка в pd.scatter_matrix() может принимать либо color или c, но не оба (GH 14855)

GroupBy/resample/rolling#

  • Ошибка в .groupby(..).resample() при передаче on= kwarg. (GH 15021)

  • Правильно установить __name__ и __qualname__ для Groupby.* функции (GH 14620)

  • Ошибка в GroupBy.get_group() неудача с категориальным группировщиком (GH 15155)

  • Ошибка в .groupby(...).rolling(...) когда on указан и используется DatetimeIndex (GH 15130, GH 13966)

  • Ошибка в операциях groupby с timedelta64 при передаче numeric_only=False (GH 5724)

  • Ошибка в groupby.apply() приведение object dtypes в числовые типы, когда не все значения были числовыми (GH 14423, GH 15421, и parse_dates включён для столбца, попытаться определить формат даты и времени для ускорения обработки.)

  • Ошибка в resample, где нестроковый loffset аргумент не применялся при ресемплинге временного ряда (GH 13218)

  • Ошибка в DataFrame.groupby().describe() при группировке по Index содержащий кортежи (GH 14848)

  • Ошибка в groupby().nunique() с группировщиком типа datetime, где подсчеты бинов были некорректны (GH 13453)

  • Ошибка в groupby.transform() который бы приводил результирующие типы данных обратно к исходным (GH 10972, GH 11444)

  • Ошибка в groupby.agg() неправильная локализация часового пояса на datetime (GH 15426, GH 10668, GH 13046)

  • Ошибка в .rolling/expanding() функции, где count() не подсчитывал np.Inf, ни обработка object типы данных (GH 12541)

  • Ошибка в .rolling() где pd.Timedelta или datetime.timedelta не принимался как window аргумент (GH 15440)

  • Ошибка в Rolling.quantile функция, вызывавшая ошибку сегментации при вызове с квантилем вне диапазона [0, 1] (GH 15463)

  • Ошибка в DataFrame.resample().median() если присутствуют повторяющиеся имена столбцов (GH 14233)

Разреженный#

  • Ошибка в SparseSeries.reindex на одном уровне со списком длины 1 (GH 15447)

  • Ошибка в форматировании repr для SparseDataFrame после установки значения на (копии) одного из его рядов (GH 15488)

  • Ошибка в SparseDataFrame конструкция со списками без приведения к dtype (GH 15682)

  • Ошибка в индексации разреженных массивов, при которой индексы не проверялись (GH 15863)

Изменение формы#

  • Ошибка в pd.merge_asof() где left_index или right_index вызывал сбой, когда несколько by был указан (GH 15676)

  • Ошибка в pd.merge_asof() где left_index/right_index вместе вызвали ошибку, когда tolerance был указан (GH 15135)

  • Ошибка в DataFrame.pivot_table() где dropna=True не удалял все-NaN столбцы, когда столбец был category тип данных (GH 15193)

  • Ошибка в pd.melt() где передача кортежа значения для value_vars вызвал TypeError (GH 15348)

  • Ошибка в pd.pivot_table() где ошибка не возникала, когда аргумент values не был в столбцах (GH 14938)

  • Ошибка в pd.concat() при конкатенации с пустым датафреймом с join='inner' неправильно обрабатывался (GH 15328)

  • Ошибка с sort=True в DataFrame.join и pd.merge при объединении по индексам (GH 15582)

  • Ошибка в DataFrame.nsmallest и DataFrame.nlargest где одинаковые значения приводили к дублированию строк (GH 15297)

  • Ошибка в pandas.pivot_table() некорректное возбуждение UnicodeError при передаче юникодного ввода для margins ключевое слово (GH 13292)

Числовой#

  • Ошибка в .rank() который некорректно ранжирует упорядоченные категории (GH 15420)

  • Ошибка в .corr() и .cov() где столбец и индекс были одним и тем же объектом (GH 14617)

  • Ошибка в .mode() где mode не возвращался, если было только одно значение (GH 15714)

  • Ошибка в pd.cut() с одним бином на массиве, состоящем только из нулей (GH 15428)

  • Ошибка в pd.qcut() с одним квантилем и массивом с идентичными значениями (GH 15431)

  • Ошибка в pandas.tools.utils.cartesian_product() при большом объеме входных данных может произойти переполнение в Windows (GH 15265)

  • Ошибка в .eval() что приводило к сбою многострочных вычислений, когда локальные переменные не находились на первой строке (GH 15342)

Другие#

  • Совместимость с SciPy 0.19.0 для тестирования на .interpolate() (GH 15662)

  • Совместимость для 32-битных платформ для .qcut/cut; интервалы теперь будут int64 тип данных (GH 14866)

  • Ошибка во взаимодействиях с Qt когда QtApplication уже существует (GH 14372)

  • Избегайте использования np.finfo() во время import pandas удалено для устранения взаимоблокировки из-за неправильного использования GIL Python (GH 14641)

Участники#

Всего 204 человека внесли патчи в этот релиз. Люди со знаком «+» рядом с именами внесли патч впервые.

  • Adam J. Stewart +

  • Adrian +

  • Ajay Saxena

  • Akash Tandon +

  • Albert Villanova del Moral +

  • Алексей Билоур +

  • Alexis Mignon +

  • Amol Kahat +

  • Андреас Винклер +

  • Andrew Kittredge +

  • Anthonios Partheniou

  • Arco Bast +

  • Ashish Singal +

  • Baurzhan Muftakhidinov +

  • Бен Кандел

  • Ben Thayer +

  • Ben Welsh +

  • Билл Чемберс +

  • Brandon M. Burroughs

  • Brian +

  • Brian McFee +

  • Carlos Souza +

  • Chris

  • Chris Ham

  • Chris Warth

  • Кристоф Голке

  • Christoph Paulik +

  • Christopher C. Aycock

  • Clemens Brunner +

  • Д.С. МакНил +

  • DaanVanHauwermeiren +

  • Daniel Himmelstein

  • Dave Willmer

  • David Cook +

  • David Gwynne +

  • David Hoffman +

  • David Krych

  • Diego Fernandez +

  • Dimitris Spathis +

  • Dmitry L +

  • Dody Suria Wijaya +

  • Dominik Stanczak +

  • Др-Ирв

  • Dr. Irv +

  • Эллиотт Сейлс де Андраде +

  • Эннемозер Кристоф +

  • Francesc Alted +

  • Fumito Hamamura +

  • Giacomo Ferroni

  • Graham R. Jeffries +

  • Greg Williams +

  • Guilherme Beltramini +

  • Гильерме Саморра +

  • Хао Ву +

  • Harshit Patni +

  • Ilya V. Schurov +

  • Иван Вальес Перес

  • Jackie Leng +

  • Jaehoon Hwang +

  • James Draper +

  • James Goppert +

  • James McBride +

  • Джеймс Сантуччи +

  • Ян Шульц

  • Jeff Carey

  • Jeff Reback

  • JennaVergeynst +

  • Джим +

  • Jim Crist

  • Joe Jevnik

  • Joel Nothman +

  • John +

  • Джон Такер +

  • John W. O’Brien

  • John Zwinck

  • Jon M. Mease

  • Jon Mease

  • Jonathan Whitmore +

  • Jonathan de Bruin +

  • Joost Kranendonk +

  • Joris Van den Bossche

  • Джошуа Брадт +

  • Julian Santander

  • Julien Marrec +

  • Jun Kim +

  • Justin Solinsky +

  • Kacawi +

  • Kamal Kamalaldin +

  • Керби Шедден

  • Kernc

  • Keshav Ramaswamy

  • Кевин Шеппард

  • Kyle Kelley

  • Ларри Рен

  • Leon Yin +

  • Line Pedersen +

  • Lorenzo Cestaro +

  • Luca Scarabello

  • Lukasz +

  • Mahmoud Lababidi

  • Mark Mandel +

  • Мэтт Рёшке

  • Мэтью Бретт

  • Matthew Roeschke +

  • Matti Picus

  • Maximilian Roos

  • Michael Charlton +

  • Michael Felt

  • Michael Lamparski +

  • Michiel Stock +

  • Mikolaj Chwalisz +

  • Min RK

  • Miroslav Šedivý +

  • Mykola Golubyev

  • Nate Yoder

  • Nathalie Rud +

  • Николас Вер Хейлен

  • Nick Chmura +

  • Nolan Nichols +

  • Pankaj Pandey +

  • Pawel Kordek

  • Pete Huang +

  • Питер +

  • Peter Csizsek +

  • Petio Petrov +

  • Phil Ruffwind +

  • Пьетро Баттистон

  • Piotr Chromiec

  • Prasanjit Prakash +

  • Rob Forgione +

  • Роберт Брэдшоу

  • Robin +

  • Родольфо Фернандес

  • Roger Thomas

  • Rouz Azari +

  • Сахил Дуа

  • Sam Foo +

  • Sami Salonen +

  • Sarah Bird +

  • Sarma Tangirala +

  • Скотт Сандерсон

  • Sebastian Bank

  • Sebastian Gsänger +

  • Шон Хайде

  • Shyam Saladi +

  • Sinhrks

  • Стивен Раух +

  • Sébastien de Menten +

  • Tara Adiseshan

  • Thiago Serafim

  • Thoralf Gutierrez +

  • Thrasibule +

  • Tobias Gustafsson +

  • Tom Augspurger

  • Tong SHEN +

  • Tong Shen +

  • TrigonaMinima +

  • Уве +

  • Wes Turner

  • Wiktor Tomczak +

  • WillAyd

  • Yaroslav Halchenko

  • Yimeng Zhang +

  • abaldenko +

  • adrian-stepien +

  • alexandercbooth +

  • atbd +

  • bastewart +

  • bmagnusson +

  • carlosdanielcsantos +

  • chaimdemulder +

  • chris-b1

  • dickreuter +

  • discort +

  • dr-leo +

  • dubourg

  • dwkenefick +

  • GH 16493

  • gfyoung

  • goldenbull +

  • hesham.shabana@hotmail.com

  • jojomdt +

  • linebp +

  • manu +

  • manuels +

  • mattip +

  • maxalbert +

  • mcocdawc +

  • nuffe +

  • paul-mannino

  • pbreach +

  • sakkemo +

  • scls19fr

  • sinhrks

  • stijnvanhoey +

  • the-nose-knows +

  • themrmax +

  • tomrod +

  • tzinckgraf

  • wandersoncferreira

  • watercrossing +

  • wcwagner

  • xgdgsc +

  • yui-knk