我有一个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
步骤2:对于每个转置的df列,通过移动给定列的1行来创建临时列
步骤3:给定这样的列,对这样的列和临时列进行groupby然后计数
Step4:所有计数的总和
我认为可能有某种方式比这更有效。我可以提出你的建议吗?谢谢。
如果你愿意的话,这是另一种解决方案:
tuple
应用于每对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
达蒙
M1:我在这里使用np.roll
,然后结合使用stack
和value_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]))
只是为了好玩,有一个巧妙的技巧:对(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