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
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 have a data-frame like this:
dtf:
id f1 f2 f3 f4 f5
t1 34 12 5 nan 6
t1 nan 4 2 9 7
t1 34 nan 5 nan 6
t2 nan nan nan nan nan
t2 nan nan nan nan nan
t2 nan nan nan nan nan
t3 23 7 8 1 32
t3 12 3 nan 45 56
t3 nan nan nan nan nan
I want to remove those rows (which have unique id) and all the features' values are 'nan' (like t2). Thus my desired data-frame should be like this:
dtf_new:
id f1 f2 f3 f4 f5
t1 34 12 5 nan 6
t1 nan 4 2 9 7
t1 34 nan 5 nan 6
t3 23 7 8 1 32
t3 12 3 nan 45 56
t3 nan nan nan nan nan
I have tried to convert it a dictionary using the below code, and then try to find nan values. But I still could not find the right solution.
dict=dict(enumerate(dtf.id.unique()))
You could do groupby and isna:
>>> dtf
id f1 f2 f3 f4 f5
0 t1 34.0 12.0 5.0 NaN 6.0
1 t1 NaN 4.0 2.0 9.0 7.0
2 t1 34.0 NaN 5.0 NaN 6.0
3 t2 NaN NaN NaN NaN NaN
4 t2 NaN NaN NaN NaN NaN
5 t2 NaN NaN NaN NaN NaN
6 t3 23.0 7.0 8.0 1.0 32.0
7 t3 12.0 3.0 NaN 45.0 56.0
8 t3 NaN NaN NaN NaN NaN
>>> dtf_new = dtf[~dtf['id'].map(dtf.groupby('id').apply(lambda x: x.drop(columns='id').isna().all(axis=None)))]
>>> dtf_new
id f1 f2 f3 f4 f5
0 t1 34.0 12.0 5.0 NaN 6.0
1 t1 NaN 4.0 2.0 9.0 7.0
2 t1 34.0 NaN 5.0 NaN 6.0
6 t3 23.0 7.0 8.0 1.0 32.0
7 t3 12.0 3.0 NaN 45.0 56.0
8 t3 NaN NaN NaN NaN NaN
#sacse is right, dropna does the job
https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html
Just change default "how" parameter...
These kinds of processing needs are basic, and common to most of pandas users... You can assume there is a feature for it, few mins on the documentation and you will find your answer, and other interesting features :)
Worth some time reading!
I want to turn my dataframe with non-distinct values underneath each column header into a dataframe with distinct values underneath each column header with next to it their occurrence in their particular column. An example:
My initial dataframe is visible underneath:
A B C D
0 CEN T2 56
2 DECEN T2 45
3 ONBEK T2 84
NaN CEN T1 59
3 NaN T1 87
NaN NaN T2 NaN
0 NaN NaN 98
NaN CEN NaN 23
NaN CEN T1 65
where A, B, C and D are the column headers with each 9 values underneath it (blanks included).
My preferred output dataframe should look like: (first a column of unique values for each column in the original dataframe and next to it their occurrence in that particular column)
A B C D A B C D
0 CEN T2 56 2 4 4 1
2 DECEN T1 45 1 1 3 1
3 ONBEK NaN 84 2 1 NaN 1
Nan NaN NaN 59 NaN NaN NaN 1
NaN NaN NaN 87 NaN NaN NaN 1
NaN NaN NaN 98 NaN NaN NaN 1
NaN NaN NaN 23 NaN NaN NaN 1
NaN NaN NaN 65 NaN NaN NaN 1
where A, B, C and D are the column headers with underneath them first the distinct values for each column from the original .csv-file and next to it the occurence of each element in their particular column.
Anybody ideas?
The code below is used to get the unique values out of each column into a new dataframe. I tried to do something with .value_counts to get the occurrence in each column but there I failed to get it into one dataframe again with the unique values..
df
new_df=pd.concat([pd.Series(df[i].unique()) for i in df.columns], axis=1)
new_df.columns=df.columns
new_df
The difficult part is keeping values of columns in each row aligned. To do this, you need to construct a new dataframe from unique, and pd.concat on with value_counts map to each column of this new dataframe.
new_df = (pd.DataFrame([df[c].unique() for c in df], index=df.columns).T
.dropna(how='all'))
df_final = pd.concat([new_df, *[new_df[c].map(df[c].value_counts()).rename(f'{c}_Count')
for c in df]], axis=1).reset_index(drop=True)
Out[1580]:
A B C D A_Count B_Count C_Count D_Count
0 0 CEN T2 56 2.0 4.0 4.0 1
1 2 DECEN T1 45 1.0 1.0 3.0 1
2 3 ONBEK NaN 84 2.0 1.0 NaN 1
3 NaN NaN NaN 59 NaN NaN NaN 1
4 NaN NaN NaN 87 NaN NaN NaN 1
5 NaN NaN NaN 98 NaN NaN NaN 1
6 NaN NaN NaN 23 NaN NaN NaN 1
7 NaN NaN NaN 65 NaN NaN NaN 1
If you only need to keep alignment between each pair of column and its count such as A - A_Count, B - B_Count..., it simply just use value_counts with reset_index some commands to change axis names
cols = df.columns.tolist() + (df.columns + '_Count').tolist()
new_df = pd.concat([df[col].value_counts(sort=False).rename_axis(col).reset_index(name=f'{col}_Count')
for col in df], axis=1).reindex(new_cols, axis=1)
Out[1501]:
A B C D A_Count B_Count C_Count D_Count
0 0.0 ONBEK T2 56.0 2.0 1.0 4.0 1
1 2.0 CEN T1 45.0 1.0 4.0 3.0 1
2 3.0 DECEN NaN 84.0 2.0 1.0 NaN 1
3 NaN NaN NaN 59.0 NaN NaN NaN 1
4 NaN NaN NaN 87.0 NaN NaN NaN 1
5 NaN NaN NaN 98.0 NaN NaN NaN 1
6 NaN NaN NaN 23.0 NaN NaN NaN 1
7 NaN NaN NaN 65.0 NaN NaN NaN 1
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