dtypes портят вещи при перемещении по первой оси (столбцы)

9

Рассмотрим кадр данных df

df = pd.DataFrame(dict(A=[1, 2], B=['X', 'Y']))

df

   A  B
0  1  X
1  2  Y

Если я смещусь axis=0(по умолчанию)

df.shift()

     A    B
0  NaN  NaN
1  1.0    X

Это толкает все ряды вниз на один ряд, как и ожидалось.

Но когда я сдвигаюсь axis=1

df.shift(axis=1)

    A    B
0 NaN  NaN
1 NaN  NaN

Все ноль, когда я ожидал

     A  B
0  NaN  1
1  NaN  2

Я понимаю, почему это произошло. Поскольку axis=0Pandas работает столбец за столбцом, где каждый столбец является единичным, dtypeа при сдвиге существует четкий протокол о том, как поступать с введенным NaNзначением в начале или в конце. Но при перемещении axis=1мы вводим потенциальную неоднозначность dtypeот одного столбца к другому. В этом случае я пытаюсь применить силу int64к objectстолбцу, и Панда решает просто обнулить значения.

Это становится более проблематичным, когда dtypesесть int64иfloat64

df = pd.DataFrame(dict(A=[1, 2], B=[1., 2.]))

df

   A    B
0  1  1.0
1  2  2.0

И происходит то же самое

df.shift(axis=1)

    A   B
0 NaN NaN
1 NaN NaN

Мой вопрос

Каковы хорошие варианты для создания кадра данных, смещенного вдоль, axis=1в котором результат имеет сдвинутые значения и dtypes?

Для случая int64/ float64будет выглядеть так:

df_shifted

     A  B
0  NaN  1
1  NaN  2

а также

df_shifted.dtypes

A    object
B     int64
dtype: object

Более полный пример

df = pd.DataFrame(dict(A=[1, 2], B=[1., 2.], C=['X', 'Y'], D=[4., 5.], E=[4, 5]))

df

   A    B  C    D  E
0  1  1.0  X  4.0  4
1  2  2.0  Y  5.0  5

Должно выглядеть так

df_shifted

     A  B    C  D    E
0  NaN  1  1.0  X  4.0
1  NaN  2  2.0  Y  5.0

df_shifted.dtypes

A     object
B      int64
C    float64
D     object
E    float64
dtype: object
piRSquared
источник
Похоже, ошибка для меня, что произойдет, если вы сделаете dtypes всех столбцов object?
EdChum
Оно работает. У меня уже есть пара работ. Я просто пытаюсь найти идеи для сообщества.
piRSquared
Я бы подал это как проблему, они должны по крайней мере предложить вариант продвижения dtype для смешанного dtype, такого какobject
EdChum
Я сделаю это сейчас.
piRSquared
1
@ EdChum-ReinstateMonica Подождите минуту! Сдвиг закончился blocks>. <Используйте это вместо этого и посмотритеdf = pd.DataFrame(dict(A=[1, 2], B=[3., 4.], C=['X', 'Y'], D=[5., 6.], E=[7, 8], F=['W', 'Z']))
piRSquared

Ответы:

7

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

Определить dfкак

df = pd.DataFrame(dict(
    A=[1, 2], B=[3., 4.], C=['X', 'Y'],
    D=[5., 6.], E=[7, 8], F=['W', 'Z']
))

df

#  i    f  o    f  i  o
#  n    l  b    l  n  b
#  t    t  j    t  t  j
#
   A    B  C    D  E  F
0  1  3.0  X  5.0  7  W
1  2  4.0  Y  6.0  8  Z

Он сместит целые числа к следующему столбцу целых чисел, с плавающей точкой к следующему столбцу с плавающей точкой и объектам к следующему столбцу объекта

df.shift(axis=1)

    A   B    C    D    E  F
0 NaN NaN  NaN  3.0  1.0  X
1 NaN NaN  NaN  4.0  2.0  Y

Я не знаю , если это хорошая идея, но это то , что происходит.


подходы

astype(object) первый

dtypes = df.dtypes.shift(fill_value=object)
df_shifted = df.astype(object).shift(1, axis=1).astype(dtypes)

df_shifted

     A  B    C  D    E  F
0  NaN  1  3.0  X  5.0  7
1  NaN  2  4.0  Y  6.0  8

transpose

Сделаю это object

dtypes = df.dtypes.shift(fill_value=object)
df_shifted = df.T.shift().T.astype(dtypes)

df_shifted

     A  B    C  D    E  F
0  NaN  1  3.0  X  5.0  7
1  NaN  2  4.0  Y  6.0  8

itertuples

pd.DataFrame([(np.nan, *t[1:-1]) for t in df.itertuples()], columns=[*df])

     A  B    C  D    E  F
0  NaN  1  3.0  X  5.0  7
1  NaN  2  4.0  Y  6.0  8

Хотя я бы, наверное, сделал это

pd.DataFrame([
    (np.nan, *t[:-1]) for t in
    df.itertuples(index=False, name=None)
], columns=[*df])
piRSquared
источник
4
Это определенно ошибка для меня, это сводит на нет весь смысл наличия колонок с
ключами
1
Я отправлю вопрос после моей встречи.
piRSquared
Если это все strdytpes, то он работает правильно, если вы делаете то же самое на этом df, df = pd.DataFrame(dict(C=['X', 'Y'], D=[5., 6.], E=[7, 8], F=['W', 'Z']))он смещает 'XY'столбец до 'F'столбца, это определенно неправильно для меня, моя версия для панд такова 0.24.2, что она должна dtypeпродвигаться, а не сдвигать столбцы в таких случаях. путь
EdChum
1

Я пытался использовать numpyметод. Метод работает до тех пор, пока вы храните свои данные в массиве:

def shift_df(data, n):
    shifted = np.roll(data, n)
    shifted[:, :n] = np.NaN

    return shifted

shifted(df, 1)

array([[nan, 1, 1.0, 'X', 4.0],
       [nan, 2, 2.0, 'Y', 5.0]], dtype=object)

Но когда вы вызываете DataFrameконструктор, все столбцы преобразуются в objectхотя значения в массиве float, int, object:

def shift_df(data, n):
    shifted = np.roll(data, n)
    shifted[:, :n] = np.NaN
    shifted = pd.DataFrame(shifted)

    return shifted

print(shift_df(df, 1),'\n')
print(shift_df(df, 1).dtypes)

     0  1  2  3  4
0  NaN  1  1  X  4
1  NaN  2  2  Y  5 

0    object
1    object
2    object
3    object
4    object
dtype: object
Erfan
источник