我有一个包含 3 列和以下值的数据框
df = pd.DataFrame(columns=['a', 'b', 'c'])
df.loc[0] = [4, 6, 8]
df.loc[1] = [5, 9, 7]
df.loc[2] = [8, 2, 1]
生成的数据框将如下所示:
a b c
0 4 6 8
1 5 9 7
2 8 2 1
我想将每行中的前两个数字(或列)转换为它们相应的 8 位二进制值,并在 df 中替换它们。但保留最后一列 df['c'] 原样。
例如df.loc[0]应该转换为
df.loc[0] = [0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,8]
这里,在 df.loc[0] 中,前八个 0 和 1 等价于 4,接下来的八个等价于 6。但最后一个数字保留在 int 中。
这是我正在做的:
# save df.iloc[0, 'c'] in a different dataframe
df_1.iloc[0, 'c'] = df.iloc[0, 'c']
df.drop(columns='c', inplace=True)
each_row = np.array(df.iloc[0, 'a']) # read each row
each_row = np.array(each_row, dtype=np.uint8) #convert them to uint8 type
each_row = np.unpackbits(each_row)
each_row = pd.Series(each_row.astype(int)) #convert uint8 back to a series to concatenate to a dataframe
现在我想插入列 a、b,然后复制回 c。
如何用变量 each_row 中的值替换 df.loc[0] 中的 4 和 6?有没有一种有效的方法可以对数据帧的所有行执行此操作,而无需在 for 循环中运行它们?
答案 0 :(得分:1)
您可以尝试一些看起来令人困惑的字典理解。
d = {col: np.append(np.concatenate(df.loc[:1, col].apply(lambda x: list(f'{x:08b}'))), df.loc[2, col]) for col in df.columns}
new_df = pd.DataFrame(d)
a b c
0 0 0 0
1 0 0 0
2 0 0 0
3 0 0 0
4 0 0 1
5 1 1 0
6 0 0 0
7 0 1 0
8 0 0 0
9 0 0 0
10 0 0 0
11 0 0 0
12 0 1 0
13 1 0 0
14 1 0 1
15 0 1 0
16 8 7 1
答案 1 :(得分:1)
虽然您的问题有点令人困惑,但从您提供的值来看,我想您确实想将 [4, 6, 8] 映射到 [0,0,0,0,0,1,0,0, 0,0,0,0,0,1,1,0,8]。 您应该编辑您的问题以获得更详细的答案。
以下是为实现这一目标而逐步构建的不同功能。
def my_format(s):
return format(s['a'], '08b')+format(s['b'], '08b')+str(s['c'])
df.apply(my_format, axis=1)
输出:
0 00000100000001018
1 00000110000010012
2 00001000000001111
def my_format2(s):
return list(map(int, ''.join(map('{:08b}'.format, s[:2]))))+[s[2]]
df.apply(my_format2, axis=1)
输出:
0 [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, ...
1 [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, ...
2 [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, ...
def my_format3(s):
return pd.Series(list(map(int, ''.join(map('{:08b}'.format, s[:2]))))+[s[2]])
df.apply(my_format3, axis=1)
输出:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 8
1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 8
2 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 8
df = pd.DataFrame([[4,6,8],[4,9,7],[8,2,1]], columns=['a', 'b', 'c'])
df[['a', 'b']] = df[['a', 'b']].applymap('{:08b}'.format)
df
输出:(注意,如果你想保留前导零,a和b是字符串)
a b c
0 00000100 00000110 8
1 00000100 00001001 7
2 00001000 00000010 1
答案 2 :(得分:0)
你可以试试:
首先创建一个掩码:
mask=df.index%3>=2
那么:
out=df[~mask].applymap(lambda x:format(x, "08b")).append(df[mask]).sort_index()
out=out.T.astype(str).agg(lambda x:list(''.join(x)),1)
现在,如果您打印 out
,您将获得预期的输出
另外:
列表中的值是字符串类型如果你想要 int 那么:
out=out.map(lambda x:[int(y) for y in x])