I have a dataset, df, where I would like to round any odd values to the next even values in columns in Python (except the number 1)
Data
site a b c
bali 5 3 1
mali 7 19 1
Desired
site a b c
bali 6 4 1
mali 8 20 1
Doing
setting this up, but I am stuck on how to point to the specific columns
if($num % 2 == 1)
Any suggestion is appreciated
CodePudding user response:
In your case do
df.update(df.select_dtypes(np.number).applymap(lambda x : 1 if x==1 else x//2*2))
a b c
0 4 2 1
1 6 18 1
CodePudding user response:
Set 'site' column as the index, using DataFrame.set_index
so that the DataFrame only contains numeric columns. This can be generalised if you contain more non-numeric columns besides 'site'. Then, mask the numbers (nums
) that are odd (nums % 2
) and different from 1 (nums != 1
), and add 1 to them, leaving the remaining unchanged. This can be done using DataFrame.mask
. Finally, reset the index of the DataFrames so that 'site' is a column again.
# get all the non-numeric columns, like 'site', in the case you have multiple ones
str_cols = df.select_dtypes(exclude='number').columns.tolist()
df = (
df.set_index(str_cols) # set the non-numeric column(s) as index
.mask(lambda nums: (nums % 2 == 1) & (nums != 1), # add 1 to every odd number !=1
lambda nums: nums 1) # and leave the remaining unchanched
.reset_index() # restore the non-numeric column(s)
)
>>> df
site a b c
0 bali 6 4 1
1 mali 8 20 1
Actually, setting and resetting the index can be avoided. Here is a simpler version of the above solution
# get all the numeric columns
num_cols = df.select_dtypes(include='number').columns.tolist()
# update only the numeric columns with the same logic
df[num_cols] = df[num_cols].mask(lambda nums: (nums % 2 == 1) & (nums != 1),
lambda nums: nums 1)
CodePudding user response:
use simple numpy to exclude 1
import numpy as np
data = np.array([
[5, 3, 1],
[7, 19,1]
])
data = data (data%2 * np.where(data==1, 0, 1))
print(data)
# array([[ 6, 4, 1],
# [ 8, 20, 1]])