I am trying to reshape a df so that the values become columns and the current columns' names become the values of the new df.
Here is an exemple.
df1=pd.DataFrame(data=[['v1','v2','v3'],['v4','v3','v1'],[np.nan,'v2','v1'],['v5','v3','v6'],], columns=['A','B','C'], index=['d1','d2','d3','d4'])
df1.index.names=['Day']
df1 # What I have
Out[1]:
A B C
Day
d1 v1 v2 v3
d2 v4 v3 v1
d3 NaN v2 v1
d4 v5 v3 v6
df2=pd.DataFrame(data=[['A','B','C',np.nan,np.nan,np.nan],['C',np.nan,'B','A',np.nan,np.nan],['C','B',np.nan,np.nan,np.nan,np.nan],[np.nan,np.nan,'B',np.nan,'A','C']], columns=['v1','v2','v3','v4','v5','v6'], index=['d1','d2','d3','d4'])
df2.index.names=['Day']
df2 # Desired output
Out[2]:
v1 v2 v3 v4 v5 v6
d1 A B C NaN NaN NaN
d2 C NaN B A NaN NaN
d3 C B NaN NaN NaN NaN
d4 NaN NaN B NaN A C
I guess something with stack(), unstack() or pivot()?
Try, stack then pivot:
df1a = df1.stack().reset_index()
df1a.pivot('Day', 0, 'level_1')
Output:
0 v1 v2 v3 v4 v5 v6
Day
d1 A B C NaN NaN NaN
d2 C NaN B A NaN NaN
d3 C B NaN NaN NaN NaN
d4 NaN NaN B NaN A C
and reset_index:
df1a.pivot('Day', 0, 'level_1').reset_index()
Output:
0 Day v1 v2 v3 v4 v5 v6
0 d1 A B C NaN NaN NaN
1 d2 C NaN B A NaN NaN
2 d3 C B NaN NaN NaN NaN
3 d4 NaN NaN B NaN A C
You could use a combination of melt and pivot :
(
df1.melt(ignore_index=False)
.dropna()
.pivot(columns="value", values="variable")
.rename_axis(columns=None)
)
v1 v2 v3 v4 v5 v6
Day
d1 A B C NaN NaN NaN
d2 C NaN B A NaN NaN
d3 C B NaN NaN NaN NaN
d4 NaN NaN B NaN A C
Related
I have this df
x y1 y2 y3 y4 d1 d2 d3 d4
0 -17.7 7 NaN NaN NaN 5 NaN 4 NaN
1 -15.0 NaN NaN NaN 3 4 NaN NaN 8
2 -12.5 NaN NaN 2 NaN NaN NaN 1 9
I want only 1 value per row between d1 to d4, based on what value is between y1 to y4.
Example: In the 1st row, value is on y1. So the value that stays is d1.
The output would be:
x y1 y2 y3 y4 d1 d2 d3 d4
0 -17.7 7 NaN NaN NaN 5 NaN NaN NaN
1 -15.0 NaN NaN NaN 3 NaN NaN NaN 8
2 -12.5 NaN NaN 2 NaN NaN NaN 1 NaN
You can use where with a boolean matrix:
df[['d1', 'd2', 'd3', 'd4']] = df.filter(like='d').where(df.filter(like='y').notna().to_numpy())
Output:
x y1 y2 y3 y4 d1 d2 d3 d4
0 -17.7 7.0 NaN NaN NaN 5.0 NaN NaN NaN
1 -15.0 NaN NaN NaN 3.0 NaN NaN NaN 8.0
2 -12.5 NaN NaN 2.0 NaN NaN NaN 1.0 NaN
I have a DF:
df = pd.DataFrame({"A":[0,1,3,5,6], "B":['B0','B1','B3','B5','B6'], "C":['C0','C1','C3','C5','C6']})
I’m trying to insert 10 empty rows at the position where the number is missed from the continuous sequence of column A. For the 10 rows, values of column A, B and C's are the missed number, Nan, and Nan, respectively. Like this:
A B C
0 B0 C0
1 B1 C1
2 NaN NaN
2 NaN NaN
2 NaN NaN
2 NaN NaN
2 NaN NaN
2 NaN NaN
2 NaN NaN
2 NaN NaN
2 NaN NaN
2 NaN NaN
3 B3 C3
4 NaN NaN
4 NaN NaN
4 NaN NaN
4 NaN NaN
4 NaN NaN
4 NaN NaN
4 NaN NaN
4 NaN NaN
4 NaN NaN
4 NaN NaN
5 B5 C5
6 B6 C6
I've played with index, but this adds only 1 row:
df1 = df.merge(how='right', on='A', right = pd.DataFrame({'A':np.arange(df.iloc[0]['A'],
df.iloc[-1]['A']+1)})).reset_index().drop(['index'], axis=1)
Thanks in advance!
Let's try to repeat the indices where the values diff is above 1 and concat:
N = 10
out = (pd.concat([df, df[['A']].loc[df.index.repeat(df['A'].diff(-1).lt(-1).mul(N-1))]])
.sort_index(kind='stable')
)
Output:
A B C
0 0 B0 C0
1 1 B1 C1
1 1 NaN NaN
1 1 NaN NaN
1 1 NaN NaN
1 1 NaN NaN
1 1 NaN NaN
1 1 NaN NaN
1 1 NaN NaN
1 1 NaN NaN
1 1 NaN NaN
2 3 B3 C3
2 3 NaN NaN
2 3 NaN NaN
2 3 NaN NaN
2 3 NaN NaN
2 3 NaN NaN
2 3 NaN NaN
2 3 NaN NaN
2 3 NaN NaN
2 3 NaN NaN
3 5 B5 C5
4 6 B6 C6
One approach could be as follows:
First, use df.set_index to make column A the index.
Next, use range for a range that runs from 0 through to the max of A (i.e. 6).
Now, apply df.reindex based on np.repeat. We use a loop to feed a 1 to the repeats parameter for all the values that exist in A, for all the ones that are missing, we use 10.
Finally, chain df.reset_index.
df.set_index('A', inplace=True)
rng = range(df.index.max()+1)
df = df.reindex(np.repeat(rng,[1 if i in df.index else 10 for i in rng]))\
.reset_index(drop=False)
print(df)
A B C
0 0 B0 C0
1 1 B1 C1
2 2 NaN NaN
3 2 NaN NaN
4 2 NaN NaN
5 2 NaN NaN
6 2 NaN NaN
7 2 NaN NaN
8 2 NaN NaN
9 2 NaN NaN
10 2 NaN NaN
11 2 NaN NaN
12 3 B3 C3
13 4 NaN NaN
14 4 NaN NaN
15 4 NaN NaN
16 4 NaN NaN
17 4 NaN NaN
18 4 NaN NaN
19 4 NaN NaN
20 4 NaN NaN
21 4 NaN NaN
22 4 NaN NaN
23 5 B5 C5
24 6 B6 C6
I'm trying to replace null values in dataframe d using dataframe f.
d and f are linked by EGI. In d, EGI is a column and is not unique. In f, EGI is unique and is this dataframe's index.
For each row in d, I need the values in that row to be 'masked' by the row in f with corresponding EGI.
Sample data:
d = pd.DataFrame({'EGI':['a1','b2','a1','d4'],'A': ['x', np.nan, 'z', 'e'], 'B': [pd.NaT, 6, 7, 9], 'C': [2, 1, None, 9], 'D': [2, None, np.nan, None]})
EGI A B C D
0 a1 x NaT 2.0 2.0
1 b2 NaN 6 1.0 NaN
2 a1 z 7 NaN NaN
3 d4 e 9 9.0 NaN
f = pd.DataFrame({'B': [5, 8, 9], 'A': ['w', 'y', np.nan], 'D': [None, np.nan, 8], 'test': [5, 8, 9]}, index=['b2', 'a1', 'c3'])
B A D test
b2 5 w NaN 5
a1 8 y NaN 8
c3 9 NaN 8.0 9
Expected output:
EGI A B C D
0 a1 x 8 2.0 2.0
1 b2 w 6 1.0 NaN
2 a1 z 7 NaN NaN
3 d4 e 9 9.0 NaN
What I tried:
m = d.isnull()
m.index = d['EGI'].tolist()
m = m.drop(['EGI'], axis = 1)
d.mask(m, f)
EGI A B C D
0 NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN
If dataframes d and f have matching row indexes, we can just fillna:
d.fillna(f)
But in OP's example, the indexes do not match up, so we just need to align them first.
One-liner
Use set_index and reindex to align the indexes to EGI and then fillna:
d.set_index('EGI').fillna(f.reindex(d.EGI))
# EGI A B C D
# 0 a1 x 8.0 2.0 2.0
# 1 b2 w 6 1.0 NaN
# 2 a1 z 7 NaN NaN
# 3 d4 e 9 9.0 NaN
Step-by-step
Use set_index to set d's index to EGI:
d = d.set_index('EGI')
# A B C D
# EGI
# a1 x NaT 2.0 2.0
# b2 NaN 6 1.0 NaN
# a1 z 7 NaN NaN
# d4 e 9 9.0 NaN
Use reindex to align f's index to d's index:
f = f.reindex(d.index)
# B A D test
# EGI
# a1 8.0 y NaN 8.0
# b2 5.0 w NaN 5.0
# a1 8.0 y NaN 8.0
# d4 NaN NaN NaN NaN
Use fillna to fill d's NaNs with f:
d.fillna(f)
# EGI A B C D
# 0 a1 x 8.0 2.0 2.0
# 1 b2 w 6 1.0 NaN
# 2 a1 z 7 NaN NaN
# 3 d4 e 9 9.0 NaN
Note that the column indexes of d and f are not aligned and do not need to be. We only need to align the row indexes, and fillna will handle the rest.
Original dataframe:
a1 a2 a3 a4 a5 a6
b1 b2 b3 b4 b5 b6
New dataframe:
a1 a2 a3 a4 a5 a6
(1st empty row)
(2nd empty row)
...
(24th empty row)
b1 b2 b3 b4 b5 b6
(1st empty row)
(2nd empty row)
...
(24th empty row)
The question is: How to perform the transformation above? Thanks a lot.
Use:
print (df)
0 1 2 3 4 5
0 a1 a2 a3 a4 a5 a6
1 b1 b2 b3 b4 b5 b6
First multiple index values by number of repeated values and then use DataFrame.reindex with np.arange:
N = 5
df.index = df.index * (N + 1)
df = df.reindex(np.arange(df.index.max() + N + 1))
print (df)
0 1 2 3 4 5
0 a1 a2 a3 a4 a5 a6
1 NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN
6 b1 b2 b3 b4 b5 b6
7 NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN
10 NaN NaN NaN NaN NaN NaN
11 NaN NaN NaN NaN NaN NaN
EDIT:
print (df)
0 1 2 3 4 5
0 a1 2 a3 a4 a5 6
1 b1 2 b3 b4 b5 6
N = 5
df.index = df.index * (N + 1)
df = df.reindex(np.arange(df.index.max() + N + 1))
print (df)
0 1 2 3 4 5
0 a1 2.0 a3 a4 a5 6.0
1 NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN
6 b1 2.0 b3 b4 b5 6.0
7 NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN
10 NaN NaN NaN NaN NaN NaN
11 NaN NaN NaN NaN NaN NaN
def convert_int_with_NaNs(x):
try:
return x.astype('Int64')
except Exception:
return x
df = df.apply(convert_int_with_NaNs)
print (df)
0 1 2 3 4 5
0 a1 2 a3 a4 a5 6
1 NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN
6 b1 2 b3 b4 b5 6
7 NaN NaN NaN NaN NaN NaN
8 NaN NaN NaN NaN NaN NaN
9 NaN NaN NaN NaN NaN NaN
10 NaN NaN NaN NaN NaN NaN
11 NaN NaN NaN NaN NaN NaN
In order to add an empty row you can use the following insctruction :
your_dataframe = your_dataframe.append({} , ignore_index=True)
To perform the requested transformation, as i don't know how your data is shaped, nor how it is indexed, i suggest you create a new empty dataframe.
For each of your initial dataframe entries, you should insert it to your new one, and append 24 time an empty row as i described.
Here is an example on how to perform it :
## Use your own data instead
data = [['a1', 'a2', 'a3', 'a4', 'a5', 'a6'],['b1', 'b2', 'b3', 'b4', 'b5', 'b6']]
### Load the data in the dataframe
df = pd.DataFrame(data)
## Create the empty dataframe
df2 = pd.DataFrame()
## Use the initial dataframe length to perform the row iteration
length = len(df.index)
## For each rows of the initial dataframe
for i in range(0, length):
## Append the current row to the new dataframe
df2 = df2.append(df[i:i+1],ignore_index=True)
## Adding 24 empty rows
for j in range(0,25):
df2 = df2.append({},ignore_index=True)
So if your initial dataframe is something like :
0 1 2 3 4 5
0 a1 a2 a3 a4 a5 a6
1 b1 b2 b3 b4 b5 b6
Once you have executed the script it outputs :
0 1 2 3 4 5
0 a1 a2 a3 a4 a5 a6
1 NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN
...
25 NaN NaN NaN NaN NaN NaN
26 b1 b2 b3 b4 b5 b6
27 NaN NaN NaN NaN NaN NaN
...
49 NaN NaN NaN NaN NaN NaN
50 NaN NaN NaN NaN NaN NaN
51 NaN NaN NaN NaN NaN NaN
I have the following problem:
I have got a dataframe that could be up to around 6 million rows. On of the columns in this data frame contains certain IDs.
ID
NaN
NaN
D1
D1
D1
NaN
D1
D1
NaN
NaN
NaN
NaN
D2
NaN
D2
NaN
NaN
NaN
NaN
D3
NaN
D3
NaN
D3
NaN
NaN
I want to make the NaNs that is included between the IDs the same as the IDs. Thus above df should become:
ID
NaN
NaN
D1
D1
D1
D1
D1
D1
NaN
NaN
NaN
NaN
D2
D2
D2
NaN
NaN
NaN
NaN
D3
D3
D3
D3
D3
NaN
NaN
Does anybody know how to do this in a fast, memory economical way?
Thanks in advance.
Using shift and loc. Compare previous and next values using shift(1) and shift(-1)
In [219]: df.loc[df.ID.shift(-1) == df.ID.shift(1), 'ID'] = df.ID.shift(1)
In [220]: df
Out[220]:
ID
0 NaN
1 NaN
2 D1
3 D1
4 D1
5 D1
6 D1
7 D1
8 NaN
9 NaN
10 NaN
11 NaN
12 D2
13 D2
14 D2
15 NaN
16 NaN
17 NaN
18 NaN
19 D3
20 D3
21 D3
22 D3
23 D3
24 NaN
25 NaN
You can use ffill and bfill - it works also if gap is higher as 1:
f = df['ID'].ffill()
df['a'] = df['ID'].mask(f.eq(df['ID'].bfill()), f)
print (df)
ID a
0 NaN NaN
1 NaN NaN
2 D1 D1
3 D1 D1
4 D1 D1
5 NaN D1
6 D1 D1
7 D1 D1
8 NaN NaN
9 NaN NaN
10 NaN NaN
11 NaN NaN
12 D2 D2
13 NaN D2
14 D2 D2
15 NaN NaN
16 NaN NaN
17 NaN NaN
18 NaN NaN
19 D3 D3
20 NaN D3
21 D3 D3
22 NaN D3
23 D3 D3
24 NaN NaN
25 NaN NaN