我有以下数据框:
a1 | a2 | a3 | a4 --------------------- Bob | Cat | Dov | Edd Cat | Dov | Bob | Edd Edd | Cat | Dov | Bob
我想把它转换成
Bob | Cat | Dov | Edd --------------------- a1 | a2 | a3 | a4 a3 | a1 | a2 | a4 a4 | a2 | a3 | a1
请注意,列数等于唯一值的数量,并保留行的数量和顺序
1)所需方法:
更快的实现方式是对数据帧的值进行排序,并根据之后获得的索引对齐列np.argsort
.
pd.DataFrame(df.columns[np.argsort(df.values)], df.index, np.unique(df.values))
应用程序np.argsort
为我们提供了我们正在寻找的数据:
df.columns[np.argsort(df.values)] Out[156]: Index([['a1', 'a2', 'a3', 'a4'], ['a3', 'a1', 'a2', 'a4'], ['a4', 'a2', 'a3', 'a1']], dtype='object')
2)缓慢的广义方法:
在以某种速度/效率为代价的更通用的方法是apply
在创建dict
数据帧中存在的字符串/值的映射及其对应的列名之后使用.
稍后在将获得的系列转换为其list
表示后使用数据框构造函数.
pd.DataFrame(df.apply(lambda s: dict(zip(pd.Series(s), pd.Series(s).index)), 1).tolist())
3)更快的通用方法:
在从df.to_dict
+ 获得字典列表之后orient='records'
,我们需要交换它们各自的键和值对,同时在循环中迭代它们.
pd.DataFrame([{val:key for key, val in d.items()} for d in df.to_dict('r')])
示例测试用例:
df = df.assign(a5=['Foo', 'Bar', 'Baz'])
这两种方法都产生:
@piRSquared编辑 1
广义解
def nic(df): v = df.values n, m = v.shape u, inv = np.unique(v, return_inverse=1) i = df.index.values c = df.columns.values r = np.empty((n, len(u)), dtype=c.dtype) r[i.repeat(m), inv] = np.tile(c, n) return pd.DataFrame(r, i, u)
1 我要感谢用户@ piRSquared提出了一个非常快速和通用的基于numpy的替代解决方案.
您可以使用堆栈重新整形并使用交换值和索引取消堆栈:
df_swap = (df.stack() # reshape the data frame to long format .reset_index(level = 1) # set the index(column headers) as a new column .set_index(0, append=True) # set the values as index .unstack(level=1)) # reshape the data frame to wide format df_swap.columns = df_swap.columns.get_level_values(1) # drop level 0 in the column index df_swap