How to replace number with text for each row in dataframe? - r

I have a data frame like this:
id status
241 1
451 3
748 3
469 2
102 3
100 1
203 2
Now what I want to do is this:
1 corresponds to 'good' , 2 corresponds to 'moderate', 3 corresponds to 'bad'.
So my output should be like this:
id status
241 good
451 bad
748 bad
469 moderate
102 bad
100 good
203 moderate
How to do this ? I tried to do this using if else but it is getting complicated.

It sounds like you want a labelled factor. You can try:
df$status <- factor(df$status, labels=c('Good','Moderate','Bad'))
> df
id status
1 241 Good
2 451 Bad
3 748 Bad
4 469 Moderate
5 102 Bad
6 100 Good
7 203 Moderate

It depends on what is the type of status column. If they are not factors, you can do(as pointed out by Pascal)
level<-c("Good","Moderate","Bad")
df$status<-level[df$status]
data
df<-data.frame(item=c("apple","banana","orange","papaya","mango"),grade=c(1,3,2,1,3),stringsAsFactors=FALSE)
And if it is set as factors, you may(as pointed out by Jay)
df$status<-factor(df$status, labels=c('Good','Moderate','Bad'))
data
df<-data.frame(item=c("apple","banana","orange","papaya","mango"),grade=c(1,3,2,1,3),stringsAsFactors=TRUE)

Related

R: loop or filter over the dataframe and stop when specific condition is met

UPDATE:
I have a dataframe df, which looks like this and it is chronological ordered by years.
id
status
601
4
601
4
601
2
601
2
601
2
601
4
601
4
601
2
601
2
601
4
601
2
990
4
990
2
990
4
First Output I want to have is:
Per id the status should alsways start with 2, so if it starts with 4 it should be delted from the df
I want to use a loop to filter over the id and that it stops, when per the number 4 occurs the first time per id:
so I want that it looks like this at the end:
id
status
601
2
601
2
601
2
601
4
601
4
990
2
990
4
and the second output I want to have:
It should stop with 4, no matter how often it occurs in the original dataset. After 4 nothing else should come.
id
status
601
2
601
2
601
2
601
4
601
4
601
2
601
2
601
4
990
2
990
4
I do not know how to do it? Maybe there is also a way with filtering?
I would really apreciate your help
If I understand you question correctly, you can use {dplyr} to get the first 4 rows of each id:
df %>% dplyr::group_by(id) %>% slice_head(n = 4)
How are your two questions different? Try adding some data that we can run and illustrate if the above is insufficient.

Calculate mean by decile in Svydesign object

So, I´m working with ENIGH - Database, which stands for ¨National Survey of Household Income and Expenses¨ in Spanish, this is an exercise conducted by the Mexican government and like most surveys of its kind, it works with Weights.
What I´m trying to do is to calculate the mean, maximum and minimum household income by Decile. In other words What´s the income of each 10%, grouping household base on their income.
To be honest, I haven’t gone that far but this is what I got until now:
I need my svydesign object
Convert that into a table using svytable
Arrange using desc() on my income variable
ENIGH_design <-svydesign(id=~upm, strata=~est_dis, weights=~factor_hog, data = ENIGH)
ENIGH_table <- svytable(ing_cor, ENIGH_design)
Here is where it gets tricky, supposing I have 100 rows, I can’t take the first 10 of them because in reality, when taking weights in mind, the might be 9% or 20% (I´m just throwing numbers) of the actual population.
I could use cut() on my income variable but I would be forgetting about weights and results will only be representative of the sample, not total population.
I think that the best approach would be to use a combination of:
mutate() to create a new variable base
if() in conjugation with mutate to define on which decile each row falls to
group_by() and mean() to calculate what I´m aiming for
This way I will have an extra variable which I could use to calculate whatever I want with whatever other variable I wish to. But again, I haven´t define my groups so it´s pretty much useless.
Thank you for reading. Thank you for your help.
Database available: https://www.inegi.org.mx/programas/enigh/nc/2016/default.html#Datos_abiertos
Here is a glimpse of how my DB looks:
folioviv foliohog ubica_geo est_dis upm factor ing_cor
100587003 1 10010000 2 610 180 22,723
100587004 1 10010000 2 610 180 17,920
100587005 1 10010000 2 610 180 27,506
100587006 1 10010000 2 610 180 56,236
100605201 1 10010000 2 620 178 41,587
100605202 1 10010000 2 620 178 135,437
100605203 1 10010000 2 620 178 62,386
100605205 1 10010000 2 620 178 103,502
100605206 1 10010000 2 620 178 27,323
100606301 1 10010000 3 630 223 68,042
100606302 1 10010000 3 630 223 98,537
100606305 1 10010000 3 630 223 53,237
100606306 1 10010000 3 630 223 132,861
100609801 1 10010000 3 640 232 190,033
100609802 1 10010000 3 640 232 28,654
100609805 1 10010000 3 640 232 74,408
100631401 1 10010000 1 650 171 80,761
100711503 1 10010000 1 770 184 38,640
100711504 1 10010000 1 770 184 81,672
There are many more columns but they aren´t necessary for this exercise.
Make a table (dataframe or data.table or tibble) that looks like this:
> dt
folioviv factor ing_tri
1 247 30000
2 200 15000
3 150 50000
incomes <- rep(dt$ing_tri, times = dt$factor)
deciles <- quantile(incomes, probs = seq(0.1, 1, by = 0.1), names = TRUE)
If I were you, I would try with names = FALSE to make it manipulable. Otherwise, it will be a named list and that's a bit annoying.
Oh, and in case you want to compute the mean, just do mean(incomes).
PS: The column folioviv is not actually necessary, but you may want to put it there just in case.

Rotate Row Cell Values to a Single Column in R

I can't seem to find anything relevant to my specific problem, so I am asking here.
I have my original dataframe here:
Sample#, Fert_A_Mean, Fert_B_Mean, Fert_C_Mean, Fert_D_Mean
1 987, 384, 672, 364
2 567, 845, 398, 243
And I'd like to be able to restructure it like this:
Sample#, Fert_Mean
1 987
1 384
1 672
1 364
2 567
2 845
2 398
2 243
I've found some similar topics on stack-exchange, such as here
but using 't()' in this case doesn't seem to work... or I am doing something wrong. Hopefully one of you folks can help me out. Thanks so much. Using R 3.4.1 through R-studio. Any packages you recommend for your methods are fine.
You could use something like gather from the tidyr package:
library(tidyr)
df2 <- gather(df, key=Fert_Mean, value=value, -Sample)
df2
Sample Fert_Mean value
1 1 Fert_A_Mean 987
2 2 Fert_A_Mean 567
3 1 Fert_B_Mean 384
4 2 Fert_B_Mean 845
5 1 Fert_C_Mean 672
6 2 Fert_C_Mean 398
7 1 Fert_D_Mean 364
8 2 Fert_D_Mean 243
You can remove the Fert_Mean column if you don't want it, and sort by Sample to get the ordering in your example.

adding and subtracting values in multiple data frames of different lengths - flow analysis

Thank you jakub and Hack-R!
Yes, these are my actual data. The data I am starting from are the following:
[A] #first, longer dataset
CODE_t2 VALUE_t2
111 3641
112 1691
121 1271
122 185
123 522
124 0
131 0
132 0
133 0
141 626
142 170
211 0
212 0
213 0
221 0
222 0
223 0
231 95
241 0
242 0
243 0
244 0
311 129
312 1214
313 0
321 0
322 0
323 565
324 0
331 0
332 0
333 0
334 0
335 0
411 0
412 0
421 0
422 0
423 0
511 6
512 0
521 0
522 0
523 87
In the above table, we can see the 44 land use CODES (which I inappropriately named "class" in my first entry) for a certain city. Some values are just 0, meaning that there are no land uses of that type in that city.
Starting from this table, which displays all the land use types for t2 and their corresponding values ("VALUE_t2") I have to reconstruct the previous amount of land uses ("VALUE_t1") per each type.
To do so, I have to add and subtract the value per each land use (if not 0) by using the "change land use table" from t2 to t1, which is the following:
[B] #second, shorter dataset
CODE_t2 CODE_t1 VALUE_CHANGE1
121 112 2
121 133 12
121 323 0
121 511 3
121 523 2
123 523 4
133 123 3
133 523 4
141 231 12
141 511 37
So, in order to get VALUE_t1 from VALUE_t2, I have, for instance, to subtract 2 + 12 + 0 + 3 + 2 hectares (first 5 values of the second, shorter table) from the value of land use type/code 121 of the first, longer table (1271 ha), and add 2 hectares to land type 112, 12 hectares to land type 133, 3 hectares to land type 511 and 2 hectares to land type 523. And I have to do that for all the land use types different than 0, and later also from t1 to t0.
What I have to do is a sort of loop that would both add and subtract, per each land use type/code, the values from VALUE_t2 to VALUE_t1, and from VALUE_t1 to VALUE_t0.
Once I estimated VALUE_t1 and VALUE_t0, I will put the values in a simple table showing the relative variation (here the values are not real):
CODE VALUE_t0 VALUE_t2 % VAR t2-t0
code1 50 100 ((100-50)/50)*100
code2 70 80 ((80-70)/70)*100
code3 45 34 ((34-45)/45)*100
What I could do so far is:
land_code <- names(A)[-1]
land_code
A$VALUE_t1 <- for(code in land_code{
cbind(A[1], A[land_code] - B[match(A$CODE_t2, B$CODE_t2), land_code])
}
If I use the loop I get an error, while if I take it away:
A$VALUE_t1 <- cbind(A[1], A[land_code] - B[match(A$CODE_t2, B$CODE_t2), land_code])
it works but I don't really get what I want to get... so far I was working on how to get a new column which would contain the new "add & subtract" values, but haven't succeeded yet. So I worked on how to get a new column which would at least match the land use types first, to then include the "add and subtract" formula.
Another problem is that, by using "match", I get a shorter A$VALUE_t1 table (13 rows instead of 44), while I would like to keep all the land use types in dataset A, because I will have then to match it with the table including VALUES_t0 (which I haven't shown here).
Sorry that I cannot do better than this at the moment... and I hope to have explained better what I have to do. I am extremely grateful for any help you can provide to me.
thanks a lot

creating vector from 'if' function using apply in R

I'm tyring to create new vector in R using an 'if' function to pull out only certain values for the new array. Basically, I want to segregate data by day of week for each of several cities. How do I use the apply function to get only, say, Tuesdays in a new array for each city? Thanks
It sounds as though you don't want if or apply at all. The solution is simpler:
Suppose that your data frame is data. Then subset(data, Weekday == 3) should work.
You don't want to use the R if. Instead use the subsetting function [
dat <- read.table(text=" Date Weekday Holiday Atlanta Chicago Houston Tulsa
1 1/1/2008 3 1 313 313 361 123
2 1/2/2008 4 0 735 979 986 310
3 1/3/2008 5 0 690 904 950 286
4 1/4/2008 6 0 610 734 822 281
5 1/5/2008 7 0 482 633 622 211
6 1/6/2008 1 0 349 421 402 109", header=TRUE)
dat[ dat$Weekday==3, ]

Resources