Skip to content

Commit 7aec87d

Browse files
authored
add cols kwarg to rename/rename! (#3380)
1 parent 103fe0d commit 7aec87d

File tree

5 files changed

+52
-20
lines changed

5 files changed

+52
-20
lines changed

NEWS.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# DataFrames.jl v1.7.0 Release Notes
2+
3+
## New functionalities
4+
5+
* `rename` and `rename!` now allow to apply a function transforming
6+
column names only to a subset of the columns specified by the `cols`
7+
keyword argument
8+
([#3380](https://github.com/JuliaData/DataFrames.jl/pull/3380))
9+
110
# DataFrames.jl v1.6.1 Release Notes
211

312
## Bug fixes

src/abstractdataframe/abstractdataframe.jl

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Compat.hasproperty(df::AbstractDataFrame, s::AbstractString) = haskey(index(df),
123123
rename!(df::AbstractDataFrame, (from => to)::Pair...)
124124
rename!(df::AbstractDataFrame, d::AbstractDict)
125125
rename!(df::AbstractDataFrame, d::AbstractVector{<:Pair})
126-
rename!(f::Function, df::AbstractDataFrame)
126+
rename!(f::Function, df::AbstractDataFrame; cols=All())
127127
128128
Rename columns of `df` in-place.
129129
Each name is changed at most once. Permutation of names is allowed.
@@ -132,8 +132,10 @@ Each name is changed at most once. Permutation of names is allowed.
132132
- `df` : the `AbstractDataFrame`
133133
- `d` : an `AbstractDict` or an `AbstractVector` of `Pair`s that maps
134134
the original names or column numbers to new names
135-
- `f` : a function which for each column takes the old name as a `String`
136-
and returns the new name that gets converted to a `Symbol`
135+
- `f` : a function which for each column selected by the `cols` keyword argument
136+
takes the old name as a `String`
137+
and returns the new name that gets converted to a `Symbol`; the `cols`
138+
column selector can be any value accepted as column selector by the `names` function
137139
- `vals` : new column names as a vector of `Symbol`s or `AbstractString`s
138140
of the same length as the number of columns in `df`
139141
- `makeunique` : if `false` (the default), an error will be raised
@@ -194,6 +196,14 @@ julia> rename!(uppercase, df)
194196
│ Int64 Int64 Int64
195197
─────┼─────────────────────
196198
1 │ 1 2 3
199+
200+
julia> rename!(lowercase, df, cols=contains('A'))
201+
1×3 DataFrame
202+
Row │ a B a_1
203+
│ Int64 Int64 Int64
204+
─────┼─────────────────────
205+
1 │ 1 2 3
206+
197207
```
198208
"""
199209
function rename!(df::AbstractDataFrame, vals::AbstractVector{Symbol};
@@ -252,12 +262,8 @@ end
252262

253263
rename!(df::AbstractDataFrame, args::Pair...) = rename!(df, collect(args))
254264

255-
function rename!(f::Function, df::AbstractDataFrame)
256-
rename!(f, index(df))
257-
# renaming columns of SubDataFrame has to clean non-note metadata in its parent
258-
_drop_all_nonnote_metadata!(parent(df))
259-
return df
260-
end
265+
rename!(f::Function, df::AbstractDataFrame; cols=All()) =
266+
rename!(df, [n => Symbol(f(n)) for n in names(df, cols)])
261267

262268
"""
263269
rename(df::AbstractDataFrame, vals::AbstractVector{Symbol};
@@ -267,7 +273,7 @@ end
267273
rename(df::AbstractDataFrame, (from => to)::Pair...)
268274
rename(df::AbstractDataFrame, d::AbstractDict)
269275
rename(df::AbstractDataFrame, d::AbstractVector{<:Pair})
270-
rename(f::Function, df::AbstractDataFrame)
276+
rename(f::Function, df::AbstractDataFrame; cols=All())
271277
272278
Create a new data frame that is a copy of `df` with changed column names.
273279
Each name is changed at most once. Permutation of names is allowed.
@@ -277,8 +283,10 @@ Each name is changed at most once. Permutation of names is allowed.
277283
only allowed if it was created using `:` as a column selector.
278284
- `d` : an `AbstractDict` or an `AbstractVector` of `Pair`s that maps
279285
the original names or column numbers to new names
280-
- `f` : a function which for each column takes the old name as a `String`
281-
and returns the new name that gets converted to a `Symbol`
286+
- `f` : a function which for each column selected by the `cols` keyword argument
287+
takes the old name as a `String`
288+
and returns the new name that gets converted to a `Symbol`; the `cols`
289+
column selector can be any value accepted as column selector by the `names` function
282290
- `vals` : new column names as a vector of `Symbol`s or `AbstractString`s
283291
of the same length as the number of columns in `df`
284292
- `makeunique` : if `false` (the default), an error will be raised
@@ -350,14 +358,22 @@ julia> rename(uppercase, df)
350358
│ Int64 Int64 Int64
351359
─────┼─────────────────────
352360
1 │ 1 2 3
361+
362+
julia> rename(uppercase, df, cols=contains('x'))
363+
1×3 DataFrame
364+
Row │ i X y
365+
│ Int64 Int64 Int64
366+
─────┼─────────────────────
367+
1 │ 1 2 3
368+
353369
```
354370
"""
355371
rename(df::AbstractDataFrame, vals::AbstractVector{Symbol};
356372
makeunique::Bool=false) = rename!(copy(df), vals, makeunique=makeunique)
357373
rename(df::AbstractDataFrame, vals::AbstractVector{<:AbstractString};
358374
makeunique::Bool=false) = rename!(copy(df), vals, makeunique=makeunique)
359375
rename(df::AbstractDataFrame, args...) = rename!(copy(df), args...)
360-
rename(f::Function, df::AbstractDataFrame) = rename!(f, copy(df))
376+
rename(f::Function, df::AbstractDataFrame; cols=All()) = rename!(f, copy(df); cols=cols)
361377

362378
"""
363379
size(df::AbstractDataFrame[, dim])

src/other/index.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,6 @@ function rename!(x::Index, nms::AbstractVector{Pair{Symbol, Symbol}})
108108
return x
109109
end
110110

111-
rename!(f::Function, x::Index) = rename!(x, [(n=>Symbol(f(string(n)))) for n in x.names])
112-
113111
# we do not define keys on purpose;
114112
# use names to get keys as strings with copying
115113
# or _names to get keys as Symbols without copying

test/dataframe.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,19 @@ end
11121112
df = DataFrame(A=1)
11131113
asview && (df=view(df, :, :))
11141114
@test rename(x -> 1, df) == DataFrame(Symbol("1") => 1)
1115+
1116+
for cols in (:B, Not("A"), Cols(2), Char, contains('B'))
1117+
df = DataFrame(A=1:3, B='A':'C')
1118+
asview && (df = view(df, :, :))
1119+
@test names(rename(lowercase, df, cols=cols)) == ["A", "b"]
1120+
@test names(df) == ["A", "B"]
1121+
rename!(lowercase, df, cols=cols)
1122+
@test names(df) == ["A", "b"]
1123+
end
1124+
df = DataFrame(A=1:3, B='A':'C')
1125+
asview && (df = view(df, :, :))
1126+
@test names(rename(lowercase, df, cols=[:A, :B])) == ["a", "b"]
1127+
@test names(rename(lowercase, df, cols=Not(:))) == ["A", "B"]
11151128
end
11161129

11171130
sdf = view(DataFrame(ones(2, 3), :auto), 1:2, 1:3)

test/index.jl

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ using DataFrames: Index, SubIndex, fuzzymatch
5050
@test_throws ArgumentError i[Not(:x)]
5151
@test_throws ArgumentError i[Not("x")]
5252
@test_throws BoundsError i[Not(1:3)]
53-
53+
5454
@test i[Not([1, 1])] == [2]
5555
@test i[Not([:A, :A])] == [2]
5656
@test i[Not(["A", "A"])] == [2]
@@ -84,10 +84,6 @@ end
8484
@test rename!(copy(i), [:a => :A]) == Index([:A, :b])
8585
@test rename!(copy(i), [:a => :a]) == Index([:a, :b])
8686
@test rename!(copy(i), [:a => :b, :b => :a]) == Index([:b, :a])
87-
@test rename!(x -> Symbol(uppercase(string(x))), copy(i)) == Index([:A, :B])
88-
@test rename!(x -> Symbol(lowercase(string(x))), copy(i)) == Index([:a, :b])
89-
@test rename!(uppercase, copy(i)) == Index([:A, :B])
90-
@test rename!(lowercase, copy(i)) == Index([:a, :b])
9187

9288
@test delete!(i, :a) == Index([:b])
9389
push!(i, :C)

0 commit comments

Comments
 (0)