计算每个熊猫行中从一个值到另一个值的变化数量,并对所有计数求和

时间:2019-04-03 03:00:37

标签: python pandas

我的数据帧具有以下3种可能的值(1、2、3)

df = pd.DataFrame({"A": [1, 2], "B": [3, 3], "C": [2, 3], "D": [3, 2]})

使用此数据框

A   B   C   D
1   3   2   3
2   3   3   2

一个值到另一个值的计数是

行0

1 -> 1 = 0   2 -> 1 = 0   3 -> 1 = 0
1 -> 2 = 0   2 -> 2 = 0   3 -> 2 = 1
1 -> 3 = 1   2 -> 3 = 1   3 -> 3 = 0

第1行

1 -> 1 = 0   2 -> 1 = 0   3 -> 1 = 0
1 -> 2 = 0   2 -> 2 = 0   3 -> 2 = 1
1 -> 3 = 0   2 -> 3 = 1   3 -> 3 = 1

那么我的总和如下

总数

1 -> 1 = 0   2 -> 1 = 0   3 -> 1 = 0
1 -> 2 = 0   2 -> 2 = 0   3 -> 2 = 2
1 -> 3 = 1   2 -> 3 = 2   3 -> 3 = 1

我可以大致考虑以下步骤

第一步:转置df

Step2:对于转置df的每一列,通过移动给定列的1行来创建一个临时列

第3步:给定这样的列,对这样的列和临时列进行groupby然后计数count

Step4:所有​​计数之和

我认为可能有比这更有效的方法。请问您有什么建议吗?谢谢。

3 个答案:

答案 0 :(得分:3)

IIUC

M1:我在这里使用np.roll,然后结合使用stackvalue_counts

df=df.astype(str)
df1=df.copy()
df1[:]=np.roll(df1.values,axis=1,shift=-1)
df1.iloc[:,-1]=np.NaN
(df+'->'+df1).stack().value_counts()
3->2    2
2->3    2
3->3    1
1->3    1
dtype: int64

M2:如果roll很难工作,请尝试shfit

df = df.astype(str)
df1 = df.copy()
df1=df1.shift(-1,axis=1)
print((df + '->' + df1).stack().value_counts())
3->2    2
2->3    2
3->3    1
1->3    1
dtype: int64

M3:为速度numpy

df = pd.DataFrame({"A": [1, 2], "B": [3, 3], "C": [2, 3], "D": [3, 2]})

df1 = df.copy()
df1=df1.shift(-1,axis=1)

np.unique(np.rec.fromarrays((df.values[:,:-1],df1.values[:,:-1])),return_counts=True)
(rec.array([(1, 3.), (2, 3.), (3, 2.), (3, 3.)],
          dtype=[('f0', '<i8'), ('f1', '<f8')]), array([1, 2, 2, 1]))

答案 1 :(得分:2)

如果您愿意,这里是替代解决方案:

  1. 连接原始数据帧和移位的数据帧。
  2. 成对排列原始值和移位后的值
  3. tuple应用于每对
  4. 计算元组。

    pd.concat([df, df.shift(axis=1)], keys=[1,2])\
      .sort_index(level=1).dropna(axis=1).astype(int)\
      .unstack().T.apply(tuple, axis=1).value_counts()
    #(2, 3)    2
    #(3, 2)    2
    #(3, 3)    1
    #(3, 1)    1
    

答案 2 :(得分:2)

有趣的是,有一个巧妙的窍门:(x,y)x,y in (1,2,3)x*4 + y的对是唯一确定的。更具体地说

1,1 -> 5
1,2 -> 6
1,3 -> 7
2,1 -> 9
2,2 -> 10 
2,3 -> 11
3,1 -> 13
3,2 -> 14
3,3 -> 15

我们可以使用它并做

# compute values of these pairs across the dataset
new_df = (df[df.columns[:-1]].values * 4 + df[df.columns[1:]].values).flatten()

# count values
pd.Series(new_df).value_counts()

输出:

14    2
11    2
7     1
15    1
dtype: int64