数据帧值对角移位行

2024-06-30 16:44:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我希望对df中的每一行进行左移位,就像对角线移位一样。 我有这样的想法:

        a1 a2  a3  a4
row1    1   5   5   3
row2    0   4   1   4
row3    0   0   7   6
row4    0   0   0   2

并希望它像:

        a1 a2  a3  a4
row1    1   5   5   3
row2    4   1   4   0
row3    7   6   0   0
row4    2   0   0   0

我的想法是对每一行使用.shift()方法,具体取决于数字。但是有没有更好的方法来解决这个问题呢

我的解决办法是:

for i in range(0, len(df)):
   df.iloc[i] = df.iloc[i].shift(periods=-i,  fill_value = 0)

Tags: 方法a2dfshifta1数字a3a4
2条回答

使用^{}翻转零值位置的numpy方法:

import numpy as np
import pandas as pd

df = pd.DataFrame({
    'a1': {'row1': 1, 'row2': 0, 'row3': 0, 'row4': 0},
    'a2': {'row1': 5, 'row2': 4, 'row3': 0, 'row4': 0},
    'a3': {'row1': 5, 'row2': 1, 'row3': 7, 'row4': 0},
    'a4': {'row1': 3, 'row2': 4, 'row3': 6, 'row4': 2}
})

mask = df.ne(0)
flipped = np.fliplr(mask)
df.values[flipped] = df.values[mask]
df.values[~flipped] = 0

df

      a1  a2  a3  a4
row1   1   5   5   3
row2   4   1   4   0
row3   7   6   0   0
row4   2   0   0   0

类似的方法除了将所有0移动到末尾,而不仅仅是翻转:

mask = df.ne(0).values
sorted_mask = np.take_along_axis(mask, np.argsort(~mask), axis=1)
df.values[sorted_mask] = df.values[mask]
df.values[~sorted_mask] = 0

修改的df

      a1  a2  a3  a4
row1   1   0   5   3  # 0 added to a2
row2   0   4   1   4
row3   0   0   7   6
row4   0   0   0   2

翻转方法:

      a1  a2  a3  a4
row1   1   5   0   3  # 0 position has been flipped
row2   4   1   4   0
row3   7   6   0   0
row4   2   0   0   0

排序方法:

      a1  a2  a3  a4
row1   1   5   3   0  # 0 is at end
row2   4   1   4   0
row3   7   6   0   0
row4   2   0   0   0

翻转方法的细分:

mask = df.ne(0)

mask保存非零值的位置:

         a1     a2     a3    a4
row1   True   True   True  True
row2  False   True   True  True
row3  False  False   True  True
row4  False  False  False  True

flipped将0翻转到另一侧以保持掩码:

[[ True  True  True  True]
 [ True  True  True False]
 [ True  True False False]
 [ True False False False]]

来自df的非零值将根据翻转的:

df.values[flipped]  # [1 5 5 3 0 4 1 0 0 0]
df.values[mask]  # [1 5 5 3 4 1 4 7 6 2]
df.values[flipped] = df.values[mask]
      a1  a2  a3  a4
row1   1   5   5   3
row2   4   1   4   4
row3   7   6   7   6
row4   2   0   0   2

然后旧值需要用零覆盖:

df.values[~flipped] = 0
      a1  a2  a3  a4
row1   1   5   5   3
row2   4   1   4   0
row3   7   6   0   0
row4   2   0   0   0

排序方法类似,但不是翻转mask而是进行排序:

mask = df.ne(0).values
sorted_mask = np.take_along_axis(mask, np.argsort(~mask), axis=1)

df

      a1  a2  a3  a4
row1   1   0   5   3
row2   0   4   1   4
row3   0   0   7   6
row4   0   0   0   2

mask

[[ True False  True  True]
 [False  True  True  True]
 [False False  True  True]
 [False False False  True]]

sorted_mask

[[ True  True  True False]  # Falses are at end of the row always
 [ True  True  True False]
 [ True  True False False]
 [ True False False False]]

IIUC,这里有一个方法:

df1 = df.mask(df.eq(0)).apply(lambda x: pd.Series(sorted(x, key=pd.isnull)), axis = 1).fillna(0, downcast='infer')
df1.columns = df.columns

相关问题 更多 >